make order of accessibles work again

- when applying overrides with reorder=True, take ctr from Override,
  else copy from the cloned Accesible. This did not work properly
- reworked:
  - replaced CountedObj class by object_counter
  - accessibles created by a copy or by applying Overrides
    do not need fresh counted values
- adjusted tests

Change-Id: Id2fcf1ab1295aa1ea80ea81ae8cd02d36f86e969
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24926
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
zolliker 2021-01-25 18:26:13 +01:00
parent 25a887dcab
commit 9df43bb940
3 changed files with 36 additions and 47 deletions

View File

@ -24,6 +24,7 @@
from collections import OrderedDict
import itertools
from secop.datatypes import CommandType, DataType, StringType, BoolType, EnumType, DataTypeType, ValueType, OrType, \
NoneOr, TextType, IntRange
@ -31,20 +32,16 @@ from secop.errors import ProgrammingError, BadValueError
from secop.properties import HasProperties, Property
class CountedObj:
ctr = [0]
def __init__(self):
cl = self.__class__.ctr
cl[0] += 1
self.ctr = cl[0]
object_counter = itertools.count(1)
class Accessible(HasProperties, CountedObj):
class Accessible(HasProperties):
'''base class for Parameter and Command'''
properties = {}
def __init__(self, **kwds):
def __init__(self, ctr, **kwds):
self.ctr = ctr or next(object_counter)
super(Accessible, self).__init__()
# do not use self.properties.update here, as no invalid values should be
# assigned to properties, even not before checkProperties
@ -52,8 +49,9 @@ class Accessible(HasProperties, CountedObj):
self.setProperty(k, v)
def __repr__(self):
return '%s_%d(%s)' % (self.__class__.__name__, self.ctr, ',\n\t'.join(
['%s=%r' % (k, self.properties.get(k, v.default)) for k, v in sorted(self.__class__.properties.items())]))
return '%s(%s, ctr=%d)' % (self.__class__.__name__, ',\n\t'.join(
['%s=%r' % (k, self.properties.get(k, v.default)) for k, v in sorted(self.__class__.properties.items())]),
self.ctr)
def copy(self):
# return a copy of ourselfs
@ -122,9 +120,6 @@ class Parameter(Accessible):
def __init__(self, description, datatype, ctr=None, unit=None, **kwds):
if ctr is not None:
self.ctr = ctr
if not isinstance(datatype, DataType):
if issubclass(datatype, DataType):
# goodie: make an instance from a class (forgotten ()???)
@ -138,8 +133,7 @@ class Parameter(Accessible):
kwds['readonly'] = kwds.get('readonly', True) # for frappy optional, for SECoP mandatory
if unit is not None: # for legacy code only
datatype.setProperty('unit', unit)
super(Parameter, self).__init__(**kwds)
super(Parameter, self).__init__(ctr, **kwds)
if self.initwrite and self.readonly:
raise ProgrammingError('can not have both readonly and initwrite!')
@ -221,24 +215,22 @@ class Commands(Parameters):
"""class storage for Commands"""
class Override(CountedObj):
class Override:
"""Stores the overrides to be applied to a Parameter
note: overrides are applied by the metaclass during class creating
reorder= True: use position of Override instead of inherited for the order
"""
def __init__(self, description="", reorder=False, **kwds):
super(Override, self).__init__()
self.kwds = kwds
self.reorder = reorder
# allow to override description without keyword
if description:
self.kwds['description'] = description
# for now, do not use the Override ctr
# self.kwds['ctr'] = self.ctr
if reorder: # result from apply must use new ctr from Override
self.kwds['ctr'] = next(object_counter)
def __repr__(self):
return '%s_%d(%s)' % (self.__class__.__name__, self.ctr, ', '.join(
return '%s(%s)' % (self.__class__.__name__, ', '.join(
['%s=%r' % (k, v) for k, v in sorted(self.kwds.items())]))
def apply(self, obj):
@ -256,12 +248,10 @@ class Override(CountedObj):
except BadValueError:
# clear default, if it does not match datatype
props['default'] = None
props['ctr'] = obj.ctr # take ctr from inherited param except when overridden by self.kwds
props.update(self.kwds)
if self.reorder:
#props['ctr'] = self.ctr
return type(obj)(ctr=self.ctr, **props)
return type(obj)(**props)
raise ProgrammingError(
"Overrides can only be applied to Accessibles, %r is none!" %
obj)
@ -292,9 +282,7 @@ class Command(Accessible):
def __init__(self, description, ctr=None, **kwds):
kwds['description'] = description
kwds['datatype'] = CommandType(kwds.get('argument', None), kwds.get('result', None))
super(Command, self).__init__(**kwds)
if ctr is not None:
self.ctr = ctr
super(Command, self).__init__(ctr, **kwds)
@property
def argument(self):

View File

@ -128,8 +128,8 @@ def test_ModuleMeta():
def read_value(self):
return 0
sortcheck2 = ['value', 'status', 'target', 'pollinterval',
'param1', 'param2', 'cmd', 'a2', 'cmd2', 'a1', 'b2']
sortcheck2 = ['status', 'target', 'pollinterval',
'param1', 'param2', 'cmd', 'a2', 'cmd2', 'value', 'a1', 'b2']
logger = LoggerStub()
updates = {}
@ -151,8 +151,7 @@ def test_ModuleMeta():
assert o.ctr not in ctr_found
ctr_found.add(o.ctr)
check_order = [(obj.accessibles[n].ctr, n) for n in sortcheck]
# HACK: atm. disabled to fix all other problems first.
assert check_order + sorted(check_order)
assert check_order == sorted(check_order)
# check for inital updates working properly
o1 = Newclass1('o1', logger, {'.description':''}, srv)

View File

@ -59,7 +59,7 @@ def test_Parameter():
with pytest.raises(ProgrammingError):
Parameter(None, datatype=float)
p3 = p1.copy()
assert p1.ctr != p3.ctr
assert p1.ctr == p3.ctr
p3.ctr = p1.ctr # manipulate ctr for next line
assert repr(p1) == repr(p3)
assert p1.datatype != p2.datatype
@ -67,22 +67,24 @@ def test_Parameter():
def test_Override():
p = Parameter('description1', datatype=BoolType, default=False)
o = Override(default=True, reorder=True)
assert o.ctr != p.ctr
q = o.apply(p)
assert q.ctr != o.ctr # override shall be useable to influence the order, hence copy the ctr value
assert q.ctr != p.ctr
assert o.ctr != p.ctr
assert q != p
p2 = Parameter('description2', datatype=BoolType, default=False)
o = Override(default=True, reorder=True)
q = o.apply(p)
qctr = q.ctr
assert q.ctr > p.ctr # reorder=True: take ctr from override object
assert q != p
assert qctr == o.apply(p).ctr # do not create a new ctr when applied again
o2 = Override(default=True)
assert o2.ctr != p2.ctr
q2 = o2.apply(p2)
assert q2.ctr != o2.ctr
assert q2.ctr != p2.ctr # EVERY override makes a new parameter object -> ctr++
assert o2.ctr != p2.ctr
assert q2 != p2
q2 = o2.apply(p)
assert q2.ctr == p.ctr # reorder=False: take ctr from inherited param
assert q2 != p
assert repr(q2) != repr(p)
q3 = Override().apply(p) # Override without change
assert id(q2) != id(p) # must be a new object
assert repr(q3) == repr(p) # but must be a clone
def test_Parameters():
ps = Parameters(dict(p1=Parameter('p1', datatype=BoolType, default=True)))