From 18586a3f090263d3e8b320a3008b209ef56f2ab1 Mon Sep 17 00:00:00 2001 From: Enrico Faulhaber Date: Wed, 27 Mar 2019 14:32:40 +0100 Subject: [PATCH] params: move unit into datatypes, support for constant property Change-Id: Ida7c8b5fd7d508d41d3b44ea98600f27f7f57dbd Reviewed-on: https://forge.frm2.tum.de/review/20243 Tested-by: JenkinsCodeReview Reviewed-by: Enrico Faulhaber --- secop/modules.py | 2 +- secop/params.py | 33 +++++++++++++++++++++++++++++---- secop/protocol/dispatcher.py | 4 ++++ test/test_params.py | 2 +- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/secop/modules.py b/secop/modules.py index 85b388f..1ab5b71 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -204,7 +204,7 @@ class Module(object): setattr(self, k, v) cfgdict.pop(k) - # Adopt units AFTER applying the cfgdict + # Modify units AFTER applying the cfgdict for k, v in self.accessibles.items(): if not isinstance(v, Parameter): continue diff --git a/secop/params.py b/secop/params.py index bc5e0a6..e3e8ddd 100644 --- a/secop/params.py +++ b/secop/params.py @@ -94,17 +94,18 @@ class Parameter(Accessible): # unit and datatype are not listed (handled separately) valid_properties = dict() - for prop in ('description', 'readonly', 'group', 'visibility', 'fmtstr', 'precision'): + for prop in ('description', 'readonly', 'group', 'visibility', 'constant'): valid_properties[prop] = prop def __init__(self, description, datatype=None, default=unset_value, - unit='', readonly=True, export=True, poll=False, + unit=u'', + constant=None, value=None, # swallow timestamp=None, # swallow optional=False, @@ -121,10 +122,10 @@ class Parameter(Accessible): self.description = description self.datatype = datatype self.default = default - self.unit = unit - self.readonly = readonly + self.readonly = readonly if constant is None else True self.export = export self.optional = optional + self.constant = constant # note: auto-converts True/False to 1/0 which yield the expected # behaviour... @@ -132,6 +133,14 @@ class Parameter(Accessible): for key in kwds: if key not in self.valid_properties: raise ProgrammingError('%s is not a valid parameter property' % key) + if constant is not None: + # The value of the `constant` property should be the + # serialised version of the constant, or unset + constant = self.datatype.validate(constant) + self.constant = self.datatype.export_value(constant) + # helper. unit should be set on the datatype, not on the parameter! + if unit: + self.datatype.unit = unit self.__dict__.update(kwds) # internal caching: value and timestamp of last change... self.value = default @@ -149,6 +158,16 @@ class Parameter(Accessible): def export_value(self): return self.datatype.export_value(self.value) + def _get_unit_(self): + return self.datatype.unit + + def _set_unit_(self, unit): + self.datatype.unit = unit + + unit = property(_get_unit_, _set_unit_) + del _get_unit_ + del _set_unit_ + class Override(CountedObj): """Stores the overrides to be applied to a Parameter @@ -177,7 +196,13 @@ class Override(CountedObj): if key not in props and key not in type(obj).valid_properties: raise ProgrammingError( "%s is not a valid %s property" % (key, type(obj).__name__)) + if isinstance(obj, Parameter): + if u'constant' in self.kwds: + constant = obj.datatype.validate(self.kwds.pop(u'constant')) + self.kwds[u'constant'] = obj.datatype.export_value(constant) + self.kwds[u'readonly'] = True props.update(self.kwds) + if self.reorder: props['ctr'] = self.ctr return type(obj)(**props) diff --git a/secop/protocol/dispatcher.py b/secop/protocol/dispatcher.py index e9cdd83..964133e 100644 --- a/secop/protocol/dispatcher.py +++ b/secop/protocol/dispatcher.py @@ -222,6 +222,8 @@ class Dispatcher(object): pobj = moduleobj.accessibles.get(pname, None) if pobj is None or not isinstance(pobj, Parameter): raise NoSuchParameterError('Module has no such parameter on this SEC-Node!') + if pobj.constant is not None: + raise ReadOnlyError('This parameter is constant and can not be accessed remotely.') if pobj.readonly: raise ReadOnlyError('This parameter can not be changed remotely.') @@ -244,6 +246,8 @@ class Dispatcher(object): pobj = moduleobj.accessibles.get(pname, None) if pobj is None or not isinstance(pobj, Parameter): raise NoSuchParameterError('Module has no such parameter on this SEC-Node!') + if pobj.constant is not None: + raise ReadOnlyError('This parameter is constant and can not be accessed remotely.') readfunc = getattr(moduleobj, u'read_%s' % pname, None) if readfunc: diff --git a/test/test_params.py b/test/test_params.py index aa17499..3501582 100644 --- a/test/test_params.py +++ b/test/test_params.py @@ -41,7 +41,7 @@ def test_Command(): def test_Parameter(): p1 = Parameter('description1', datatype=BoolType, default=False) - p2 = Parameter('description2', datatype=BoolType, default=True) + p2 = Parameter('description2', datatype=BoolType, constant=True) assert p1 != p2 assert p1.ctr != p2.ctr with pytest.raises(ValueError):