Factory creation in ADD is now working
1 parent 82cb89e commit ed00a800dbd12b84213a7f0334f349c7fcf93bd6
@David Whale David Whale authored on 27 May 2016
Showing 2 changed files
View
31
src/energenie/KVS.py
def __init__(self, filename=None):
self.filename = filename
self.store = {}
 
def load(self, filename=None, create_cb=None):
def load(self, filename=None, factory_cb=None):
"""Load the whole file into an in-memory cache"""
 
# use new filename if provided, else use existing filename
if filename == None:
##print("parsing %s" % line)
k,v = line.split("=", 1)
obj[k] = v
else: # is blank
self.process(command, key, obj)
self.process(command, key, obj, factory_cb)
command = None
is_cmd = True
 
self.filename = filename # remember filename if it was provided
 
def process(self, command, key, obj):
def process(self, command, key, obj, factory_cb):
"""Process the temporary object"""
m = getattr(self, command)
#If command is not found? get AttributeError - that's fine
m(key, obj)
m(key, obj, factory_cb)
 
def ADD(self, key, obj):
def ADD(self, key, obj, factory=None):
"""Add a new item to the kvs"""
# The ADD command process the next type= parameter as the class name in context
# The ADD command processes the next type= parameter as the class name in context
# all other parameters are read as strings and passed to class constructor as kwargs
 
if factory != None:
print("*** calling factory to turn into a class instance")
type = obj["type"]
del obj["type"] # don't pass to constructor
obj = factory.get(type, **obj)
# If this fails, then this is an error, so just let it bubble out
else:
print("*** no factory configured, just storing kvp")
 
print("*** object: %s" % obj)
# store kvp or class instance appropriately
self.store[key] = obj
self.append(key, obj)
 
@unimplemented
def IGN(self, key, obj=None):
def IGN(self, key, obj=None, factory=None):
"""Ignore the whole record"""
# The IGN command is the same length as ADD, allowing a seek/write to change any
# command into IGN without changing the file size, effectively patching the file
# so that the record is deleted.
pass # There is nothing to do with this command
 
@unimplemented
def DEL(self, key, obj=None):
def DEL(self, key, obj=None, factory=None):
"""Delete the key from the store"""
# The DEL command deletes the rec from the store.
# This is useful to build temporary objects and delete them later.
# There is no need to write this to the file copy, we're processing the file
if key in self.store:
self.remove(key) # patches it to an IGN record
 
self.store[key] = value
#TODO: If this fails, just add the kv pair map as the object
obj = value.get_config() # will fail with AttributeError if this method does not exist
self.append(key, obj)
 
def __delitem__(self, key):
v = values[k]
f.write("%s=%s\n" % (k, v))
f.write("\n")
 
@untested
def remove(self, key):
"""Remove reference to this key in the file"""
if self.filename == None:
return # No file, nothing to do
View
96
src/energenie/KVS_test.py
# A dummy test class
 
class TV():
def __init__(self, id):
print("Creating TV %s" % id)
self.id = id
 
def __repr__(self):
return "TV(%s)" % self.id
show_file(self.KVS_FILENAME)
 
#---- HERE ----
 
@unimplemented
@test_0
def test_ADD_nofactory(self):
#NOTE: This is an under the bonnet test of parsing an ADD record from the file
 
# No factory callback provided, use ADD parse action
obj = {
"type": "MIHO005",
"id": 1234
}
kvs = KVS(self.KVS_FILENAME)
kvs.ADD("tv1", obj)
 
# expected result: object described as a kvp becomes a kvp in the store if no factory callback
print(kvs.store)
 
@test_1
def test_ADD(self):
pass #TODO: do ADD records get added when parsing the file?
 
@unimplemented
def test_ADD_factory(self):
#NOTE: This is an under the bonnet test of parsing an ADD record from the file
obj = {
"type": "TV",
"id": 1234
}
kvs = KVS(self.KVS_FILENAME)
 
class FACTORY():
@staticmethod
def get(name, **kwargs):
if name == "TV": return TV(**kwargs)
else:
raise ValueError("Unknown device name %s" % name)
 
kvs.ADD("tv1", obj, FACTORY)
 
#TODO all non type args need to be passed as the kwargs to the factory.get
 
# expected result: object described as a kvp becomes a configured object instance in store
print(kvs.store)
 
 
@test_0
def test_IGN(self):
#NOTE: This is an under the bonnet test of parsing an IGN record from the file
pass #TODO: do IGN records get ignored when parsing the file?
 
@unimplemented
# expected result: no change to the in memory data structures
 
@test_0
def test_DEL(self):
#NOTE: This is an under the bonnet test of parsing a DEL record from the file
pass #TODO: do DEL records get processed when parsing the file?
 
@unimplemented
# expected result: record is deleted from in memory store
# expected result: error if it was not in the store in the first place
 
@test_0
def test_load_process(self):
"""Load and process a file with lots of records in it"""
#including ADD, IGN, DEL
#as the callback will create the object that is stored in the cache
pass #TODO
 
 
#TODO: Other tests - for integrating with the registry later
#pass in an object creator callback, should turn kvp into object instance
#when persisting, try to call get_config(), if it works, persist the kvp,
#if there is no get_config(), decide what to persist, if anything,
#or throw a NotPersistable error perhaps?
#Look to see if there is a pythonic way to do this, perhaps with one of
#the meta methods?
 
if __name__ == "__main__":
unittest.main()