fix several regressions from switching to accessibles

also include some basic tests now

Change-Id: Ia07892c03f4d72f5da307a79a9827f926940881d
Reviewed-on: https://forge.frm2.tum.de/review/18539
Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
Enrico Faulhaber
2018-07-26 17:53:00 +02:00
parent 5b273e36a7
commit b1f1653ebd
10 changed files with 283 additions and 80 deletions

View File

@ -65,6 +65,10 @@ class ModuleMeta(type):
(so the dispatcher will get notfied of changed values)
"""
def __new__(mcs, name, bases, attrs):
commands = attrs.pop('commands', {})
parameters = attrs.pop('parameters', {})
overrides = attrs.pop('overrides', {})
newtype = type.__new__(mcs, name, bases, attrs)
if '__constructed__' in attrs:
return newtype
@ -82,17 +86,15 @@ class ModuleMeta(type):
for base in reversed(bases):
if hasattr(base, "accessibles"):
accessibles_list.append(base.accessibles)
for entry in ['accessibles', 'parameters', 'commands', 'overrides']:
accessibles_list.append(attrs.get(entry, {}))
accessibles = {} # unordered dict of accessibles
newtype.parameters = {}
for accessibles in [attrs.get('accessibles', {}), parameters, commands, overrides]:
accessibles_list.append(accessibles)
accessibles = {} # unordered dict of accessibles, will be sorted later
for accessibles_dict in accessibles_list:
for key, obj in accessibles_dict.items():
if isinstance(obj, Override):
try:
obj = obj.apply(accessibles[key])
accessibles[key] = obj
newtype.parameters[key] = obj
except KeyError:
raise ProgrammingError("module %s: %s does not exist"
% (name, key))
@ -104,16 +106,16 @@ class ModuleMeta(type):
# raise ProgrammingError("module %s: %s must not be redefined"
# % (name, key))
if isinstance(obj, Parameter):
newtype.parameters[key] = obj
accessibles[key] = obj
elif isinstance(obj, Command):
# XXX: convert to param with datatype=CommandType???
accessibles[key] = obj
else:
raise ProgrammingError('%r: accessibles entry %r should be a '
'Parameter or Command object!' % (name, key))
# Correct naming of EnumTypes
for k, v in newtype.parameters.items():
for k, v in accessibles.items():
if isinstance(v.datatype, EnumType) and not v.datatype._enum.name:
v.datatype._enum.name = k
@ -123,10 +125,13 @@ class ModuleMeta(type):
newtype.accessibles = OrderedDict(sorted(accessibles.items(), key=lambda item: item[1].ctr))
# check validity of Parameter entries
for pname, pobj in newtype.parameters.items():
for pname, pobj in newtype.accessibles.items():
# XXX: create getters for the units of params ??
# wrap of reading/writing funcs
if isinstance(pobj, Command):
# skip commands for now
continue
rfunc = attrs.get('read_' + pname, None)
for base in bases:
if rfunc is not None:
@ -140,7 +145,7 @@ class ModuleMeta(type):
else:
# return cached value
self.log.debug("rfunc(%s): return cached value" % pname)
value = self.parameters[pname].value
value = self.accessibles[pname].value
setattr(self, pname, value) # important! trigger the setter
return value
@ -159,13 +164,13 @@ class ModuleMeta(type):
def wrapped_wfunc(self, value, pname=pname, wfunc=wfunc):
self.log.debug("wfunc(%s): set %r" % (pname, value))
pobj = self.parameters[pname]
pobj = self.accessibles[pname]
value = pobj.datatype.validate(value)
if wfunc:
self.log.debug('calling %r(%r)' % (wfunc, value))
value = wfunc(self, value) or value
# XXX: use setattr or direct manipulation
# of self.parameters[pname]?
# of self.accessibles[pname]?
setattr(self, pname, value)
return value
@ -176,16 +181,16 @@ class ModuleMeta(type):
wrapped_wfunc.__wrapped__ = True
def getter(self, pname=pname):
return self.parameters[pname].value
return self.accessibles[pname].value
def setter(self, value, pname=pname):
pobj = self.parameters[pname]
pobj = self.accessibles[pname]
value = pobj.datatype.validate(value)
pobj.timestamp = time.time()
if (not EVENT_ONLY_ON_CHANGED_VALUES) or (value != pobj.value):
pobj.value = value
# also send notification
if self.parameters[pname].export:
if self.accessibles[pname].export:
self.log.debug('%s is now %r' % (pname, value))
self.DISPATCHER.announce_update(self, pname, pobj)
@ -194,7 +199,7 @@ class ModuleMeta(type):
# check information about Command's
for attrname in attrs:
if attrname.startswith('do_'):
if attrname[3:] not in newtype.commands:
if attrname[3:] not in newtype.accessibles:
raise ProgrammingError('%r: command %r has to be specified '
'explicitly!' % (name, attrname[3:]))
attrs['__constructed__'] = True