migrated secop_psi drivers to new syntax

- includes all changes up to 'fix inheritance order' from git_mlz
  6a32ecf342

Change-Id: Ie3ceee3dbd0a9284b47b1d5b5dbe262eebe8f283
This commit is contained in:
2021-02-24 16:15:23 +01:00
parent bc5edec06f
commit 41baf5805f
79 changed files with 2610 additions and 3952 deletions

View File

@@ -24,10 +24,11 @@
# no fixtures needed
import pytest
from secop.basic_validators import FloatProperty, PositiveFloatProperty, \
NonNegativeFloatProperty, IntProperty, PositiveIntProperty, \
NonNegativeIntProperty, BoolProperty, StringProperty, UnitProperty, \
FmtStrProperty, OneOfProperty, NoneOr, EnumProperty, TupleProperty
from secop.basic_validators import BoolProperty, EnumProperty, FloatProperty, \
FmtStrProperty, IntProperty, NoneOr, NonNegativeFloatProperty, \
NonNegativeIntProperty, OneOfProperty, PositiveFloatProperty, \
PositiveIntProperty, StringProperty, TupleProperty, UnitProperty
class unprintable:
def __str__(self):

View File

@@ -26,8 +26,9 @@
import pytest
from secop.datatypes import ArrayOf, BLOBType, BoolType, \
DataType, EnumType, FloatRange, IntRange, ProgrammingError, ConfigError, \
ScaledInteger, StringType, TextType, StructOf, TupleOf, get_datatype, CommandType
CommandType, ConfigError, DataType, Enum, EnumType, FloatRange, \
IntRange, ProgrammingError, ScaledInteger, StatusType, \
StringType, StructOf, TextType, TupleOf, get_datatype
def copytest(dt):
@@ -359,6 +360,7 @@ def test_BoolType():
# pylint: disable=unexpected-keyword-arg
BoolType(unit='K')
def test_ArrayOf():
# test constructor catching illegal arguments
with pytest.raises(ValueError):
@@ -478,6 +480,14 @@ def test_Command():
'result':{'type': 'int', 'min':-3, 'max':3}}
def test_StatusType():
status_codes = Enum('Status', IDLE=100, WARN=200, BUSY=300, ERROR=400)
dt = StatusType(status_codes)
assert dt.IDLE == status_codes.IDLE
assert dt.ERROR == status_codes.ERROR
assert dt._enum == status_codes
def test_get_datatype():
with pytest.raises(ValueError):
get_datatype(1)

View File

@@ -23,10 +23,11 @@
import pytest
from secop.datatypes import FloatRange, IntRange, Property, StringType
from secop.errors import ProgrammingError
from secop.iohandler import CmdParser, IOHandler
from secop.modules import Module, Parameter
from secop.datatypes import FloatRange, StringType, IntRange, Property
from secop.errors import ProgrammingError
@pytest.mark.parametrize('fmt, text, values, text2', [
('%d,%d', '2,3', [2,3], None),
@@ -107,15 +108,11 @@ def test_IOHandler():
class Module1(Module):
properties = {
'channel': Property('the channel', IntRange(), default=3),
'loop': Property('the loop', IntRange(), default=2),
}
parameters = {
'simple': Parameter('a readonly', FloatRange(), default=0.77, handler=group1),
'real': Parameter('a float value', FloatRange(), default=12.3, handler=group2, readonly=False),
'text': Parameter('a string value', StringType(), default='x', handler=group2, readonly=False),
}
channel = Property('the channel', IntRange(), default=3)
loop = Property('the loop', IntRange(), default=2)
simple = Parameter('a readonly', FloatRange(), default=0.77, handler=group1)
real = Parameter('a float value', FloatRange(), default=12.3, handler=group2, readonly=False)
text = Parameter('a string value', StringType(), default='x', handler=group2, readonly=False)
def sendRecv(self, command):
assert data.pop('command') == command
@@ -196,6 +193,4 @@ def test_IOHandler():
with pytest.raises(ProgrammingError): # can not use a handler for different modules
# pylint: disable=unused-variable
class Module2(Module):
parameters = {
'simple': Parameter('a readonly', FloatRange(), default=0.77, handler=group1),
}
simple = Parameter('a readonly', FloatRange(), default=0.77, handler=group1)

View File

@@ -22,13 +22,14 @@
# *****************************************************************************
"""test data types."""
# no fixtures needed
#import pytest
import threading
import pytest
from secop.datatypes import BoolType, FloatRange, StringType
from secop.errors import ProgrammingError
from secop.modules import Communicator, Drivable, Module
from secop.params import Command, Override, Parameter
from secop.params import Command, Parameter
from secop.poller import BasicPoller
@@ -64,30 +65,27 @@ def test_Communicator():
assert event.is_set() # event should be set immediately
def test_ModuleMeta():
def test_ModuleMagic():
class Newclass1(Drivable):
parameters = {
'pollinterval': Override(reorder=True),
'param1' : Parameter('param1', datatype=BoolType(), default=False),
'param2': Parameter('param2', datatype=FloatRange(unit='Ohm'), default=True),
"cmd": Command('stuff', argument=BoolType(), result=BoolType())
}
commands = {
# intermixing parameters with commands is not recommended,
# but acceptable for influencing the order
'a1': Parameter('a1', datatype=BoolType(), default=False),
'a2': Parameter('a2', datatype=BoolType(), default=True),
'value': Override(datatype=StringType(), default='first'),
'cmd2': Command('another stuff', argument=BoolType(), result=BoolType()),
}
param1 = Parameter('param1', datatype=BoolType(), default=False)
param2 = Parameter('param2', datatype=FloatRange(unit='Ohm'), default=True)
@Command(argument=BoolType(), result=BoolType())
def cmd(self, arg):
"""stuff"""
return not arg
a1 = Parameter('a1', datatype=BoolType(), default=False)
a2 = Parameter('a2', datatype=BoolType(), default=True)
value = Parameter(datatype=StringType(), default='first')
@Command(argument=BoolType(), result=BoolType())
def cmd2(self, arg):
"""another stuff"""
return not arg
pollerClass = BasicPoller
def do_cmd(self, arg):
return not arg
def do_cmd2(self, arg):
return not arg
def read_param1(self):
return True
@@ -103,19 +101,31 @@ def test_ModuleMeta():
def read_value(self):
return 'second'
with pytest.raises(ProgrammingError):
class Mod1(Module): # pylint: disable=unused-variable
def do_this(self): # old style command
pass
# first inherited accessibles, then Overrides with reorder=True and new accessibles
sortcheck1 = ['value', 'status', 'target', 'pollinterval',
with pytest.raises(ProgrammingError):
class Mod2(Module): # pylint: disable=unused-variable
param = Parameter(), # pylint: disable=trailing-comma-tuple
# first inherited accessibles
sortcheck1 = ['value', 'status', 'pollinterval', 'target', 'stop',
'param1', 'param2', 'cmd', 'a1', 'a2', 'cmd2']
class Newclass2(Newclass1):
parameters = {
'cmd2': Override('another stuff'),
'value': Override(datatype=FloatRange(unit='deg'), reorder=True),
'a1': Override(datatype=FloatRange(unit='$/s'), reorder=True, readonly=False),
'b2': Parameter('<b2>', datatype=BoolType(), default=True,
poll=True, readonly=False, initwrite=True),
}
paramOrder = 'param1', 'param2', 'cmd', 'value'
@Command(description='another stuff')
def cmd2(self, arg):
return arg
value = Parameter(datatype=FloatRange(unit='deg'))
a1 = Parameter(datatype=FloatRange(unit='$/s'), readonly=False)
b2 = Parameter('<b2>', datatype=BoolType(), default=True,
poll=True, readonly=False, initwrite=True)
def write_a1(self, value):
self._a1_written = value
@@ -128,14 +138,15 @@ def test_ModuleMeta():
def read_value(self):
return 0
sortcheck2 = ['value', 'status', 'target', 'pollinterval',
'param1', 'param2', 'cmd', 'a2', 'cmd2', 'a1', 'b2']
# first inherited items not mentioned, then the ones mentioned in paramOrder, then the other new ones
sortcheck2 = ['status', 'pollinterval', 'target', 'stop',
'a1', 'a2', 'cmd2', 'param1', 'param2', 'cmd', 'value', 'b2']
logger = LoggerStub()
updates = {}
srv = ServerStub(updates)
params_found = set() # set of instance accessibles
params_found = set() # set of instance accessibles
objects = []
for newclass, sortcheck in [(Newclass1, sortcheck1), (Newclass2, sortcheck2)]:
@@ -143,16 +154,11 @@ def test_ModuleMeta():
o2 = newclass('o2', logger, {'.description':''}, srv)
for obj in [o1, o2]:
objects.append(obj)
ctr_found = set()
for n, o in obj.accessibles.items():
for o in obj.accessibles.values():
# check that instance accessibles are unique objects
assert o not in params_found
params_found.add(o)
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 list(obj.accessibles) == sortcheck
# check for inital updates working properly
o1 = Newclass1('o1', logger, {'.description':''}, srv)
@@ -214,7 +220,7 @@ def test_ModuleMeta():
assert acs is not None
else: # do not check object or mixin
acs = {}
for n, o in acs.items():
for o in acs.values():
# check that class accessibles are not reused as instance accessibles
assert o not in params_found

View File

@@ -23,8 +23,8 @@
import pytest
from secop.protocol.interface import encode_msg_frame, decode_msg
import secop.protocol.messages as m
from secop.protocol.interface import decode_msg, encode_msg_frame
# args are: msg tuple, msg bytes
MSG = [

View File

@@ -25,66 +25,78 @@
# no fixtures needed
import pytest
from secop.datatypes import BoolType, IntRange
from secop.params import Command, Override, Parameter, Parameters
from secop.datatypes import BoolType, FloatRange, IntRange
from secop.errors import ProgrammingError
from secop.modules import HasAccessibles
from secop.params import Command, Parameter
def test_Command():
cmd = Command('do_something')
assert cmd.description == 'do_something'
assert cmd.ctr
assert cmd.argument is None
assert cmd.result is None
assert cmd.for_export() == {'datainfo': {'type': 'command'},
'description': 'do_something'}
class Mod(HasAccessibles):
@Command()
def cmd(self):
"""do something"""
@Command(IntRange(-9,9), result=IntRange(-1,1), description='do some other thing')
def cmd2(self):
pass
cmd = Command('do_something', argument=IntRange(-9,9), result=IntRange(-1,1))
assert cmd.description
assert isinstance(cmd.argument, IntRange)
assert isinstance(cmd.result, IntRange)
assert cmd.for_export() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'min':-9, 'max':9},
'result': {'type': 'int', 'min':-1, 'max':1}},
'description': 'do_something'}
assert cmd.exportProperties() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'max': 9, 'min': -9},
'result': {'type': 'int', 'max': 1, 'min': -1}},
'description': 'do_something'}
assert Mod.cmd.description == 'do something'
assert Mod.cmd.argument is None
assert Mod.cmd.result is None
assert Mod.cmd.for_export() == {'datainfo': {'type': 'command'},
'description': 'do something'}
assert Mod.cmd2.description == 'do some other thing'
assert isinstance(Mod.cmd2.argument, IntRange)
assert isinstance(Mod.cmd2.result, IntRange)
assert Mod.cmd2.for_export() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'min': -9, 'max': 9},
'result': {'type': 'int', 'min': -1, 'max': 1}},
'description': 'do some other thing'}
assert Mod.cmd2.exportProperties() == {'datainfo': {'type': 'command', 'argument': {'type': 'int', 'max': 9, 'min': -9},
'result': {'type': 'int', 'max': 1, 'min': -1}},
'description': 'do some other thing'}
def test_Parameter():
p1 = Parameter('description1', datatype=IntRange(), default=0)
p2 = Parameter('description2', datatype=IntRange(), constant=1)
assert p1 != p2
assert p1.ctr != p2.ctr
class Mod(HasAccessibles):
p1 = Parameter('desc1', datatype=FloatRange(), default=0)
p2 = Parameter('desc2', datatype=FloatRange(), default=0, readonly=True)
p3 = Parameter('desc3', datatype=FloatRange(), default=0, readonly=False)
p4 = Parameter('desc4', datatype=FloatRange(), constant=1)
assert repr(Mod.p1) != repr(Mod.p3)
assert id(Mod.p1.datatype) != id(Mod.p2.datatype)
assert Mod.p1.exportProperties() == {'datainfo': {'type': 'double'}, 'description': 'desc1', 'readonly': True}
assert Mod.p2.exportProperties() == {'datainfo': {'type': 'double'}, 'description': 'desc2', 'readonly': True}
assert Mod.p3.exportProperties() == {'datainfo': {'type': 'double'}, 'description': 'desc3', 'readonly': False}
assert Mod.p4.exportProperties() == {'datainfo': {'type': 'double'}, 'description': 'desc4', 'readonly': True,
'constant': 1.0}
p3 = Mod.p1.copy()
assert id(p3) != id(Mod.p1)
assert repr(Mod.p1) == repr(p3)
with pytest.raises(ProgrammingError):
Parameter(None, datatype=float)
p3 = p1.copy()
assert p1.ctr != p3.ctr
p3.ctr = p1.ctr # manipulate ctr for next line
assert repr(p1) == repr(p3)
assert p1.datatype != p2.datatype
Parameter(None, datatype=float, inherit=False)
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
class Base(HasAccessibles):
p1 = Parameter('description1', datatype=BoolType, default=False)
p2 = Parameter('description1', datatype=BoolType, default=False)
p3 = Parameter('description1', datatype=BoolType, default=False)
p2 = Parameter('description2', datatype=BoolType, default=False)
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
class Mod(Base):
p1 = Parameter(default=True)
p2 = Parameter() # override without change
def test_Parameters():
ps = Parameters(dict(p1=Parameter('p1', datatype=BoolType, default=True)))
ps['p2'] = Parameter('p2', datatype=BoolType, default=True, export=True)
assert ps['_p2'].export == '_p2'
assert Mod.p1 != Base.p1
assert Mod.p2 != Base.p2
assert Mod.p3 == Base.p3
assert id(Mod.p2) != id(Base.p2) # must be a new object
assert repr(Mod.p2) == repr(Base.p2) # but must be a clone
def test_Export():
class Mod:
param = Parameter('description1', datatype=BoolType, default=False)
assert Mod.param.export == '_param'

View File

@@ -22,8 +22,8 @@
"""test data types."""
from collections import OrderedDict
from ast import literal_eval
from collections import OrderedDict
import pytest

View File

@@ -23,9 +23,12 @@
import time
from collections import OrderedDict
import pytest
from secop.modules import Drivable
from secop.poller import Poller, REGULAR, DYNAMIC, SLOW
from secop.poller import DYNAMIC, REGULAR, SLOW, Poller
Status = Drivable.Status
class Time:

View File

@@ -23,39 +23,59 @@
import pytest
from secop.datatypes import IntRange, StringType, FloatRange, ValueType
from secop.errors import ProgrammingError, ConfigError
from secop.properties import Property, Properties, HasProperties
from secop.datatypes import FloatRange, IntRange, StringType, ValueType
from secop.errors import BadValueError, ConfigError, ProgrammingError
from secop.properties import HasProperties, Property
# args are: datatype, default, extname, export, mandatory, settable
def Prop(*args, name=None, **kwds):
# collect the args for Property
return name, args, kwds
# Property(description, datatype, default, ...)
V_test_Property = [
[(StringType(), 'default', 'extname', False, False),
dict(default='default', extname='extname', export=True, mandatory=False)],
[(IntRange(), '42', '_extname', False, True),
dict(default=42, extname='_extname', export=True, mandatory=True)],
[(IntRange(), '42', '_extname', True, False),
dict(default=42, extname='_extname', export=True, mandatory=False)],
[(IntRange(), 42, '_extname', True, True),
dict(default=42, extname='_extname', export=True, mandatory=True)],
[(IntRange(), 0, '', True, True),
dict(default=0, extname='', export=True, mandatory=True)],
[(IntRange(), 0, '', True, False),
dict(default=0, extname='', export=True, mandatory=False)],
[(IntRange(), 0, '', False, True),
dict(default=0, extname='', export=False, mandatory=True)],
[(IntRange(), 0, '', False, False),
dict(default=0, extname='', export=False, mandatory=False)],
[(IntRange(), None, '', None),
dict(default=0, extname='', export=False, mandatory=True)], # mandatory not given, no default -> mandatory
[(ValueType(), 1, '', False),
dict(default=1, extname='', export=False, mandatory=False)], # mandatory not given, default given -> NOT mandatory
[Prop(StringType(), 'default', extname='extname', mandatory=False),
dict(default='default', extname='extname', export=True, mandatory=False)
],
[Prop(IntRange(), '42', export=True, name='custom', mandatory=True),
dict(default=42, extname='_custom', export=True, mandatory=True),
],
[Prop(IntRange(), '42', export=True, name='name'),
dict(default=42, extname='_name', export=True, mandatory=False)
],
[Prop(IntRange(), 42, '_extname', mandatory=True),
dict(default=42, extname='_extname', export=True, mandatory=True)
],
[Prop(IntRange(), 0, export=True, mandatory=True),
dict(default=0, extname='', export=True, mandatory=True)
],
[Prop(IntRange(), 0, export=True, mandatory=False),
dict(default=0, extname='', export=True, mandatory=False)
],
[Prop(IntRange(), 0, export=False, mandatory=True),
dict(default=0, extname='', export=False, mandatory=True)
],
[Prop(IntRange(), 0, export=False, mandatory=False),
dict(default=0, extname='', export=False, mandatory=False)
],
[Prop(IntRange()),
dict(default=0, extname='', export=False, mandatory=True) # mandatory not given, no default -> mandatory
],
[Prop(ValueType(), 1),
dict(default=1, extname='', export=False, mandatory=False) # mandatory not given, default given -> NOT mandatory
],
]
@pytest.mark.parametrize('args, check', V_test_Property)
def test_Property(args, check):
p = Property('', *args)
@pytest.mark.parametrize('propargs, check', V_test_Property)
def test_Property(propargs, check):
name, args, kwds = propargs
p = Property('', *args, **kwds)
if name:
p.__set_name__(None, name)
result = {k: getattr(p, k) for k in check}
assert result == check
def test_Property_basic():
with pytest.raises(TypeError):
# pylint: disable=no-value-for-parameter
@@ -67,47 +87,47 @@ def test_Property_basic():
Property('', 1)
Property('', IntRange(), '42', 'extname', False, False)
def test_Properties():
p = Properties()
with pytest.raises(ProgrammingError):
p[1] = 2
p['a'] = Property('', IntRange(), '42', export=True)
assert p['a'].default == 42
assert p['a'].export is True
assert p['a'].extname == '_a'
with pytest.raises(ProgrammingError):
p['a'] = 137
with pytest.raises(ProgrammingError):
del p[1]
with pytest.raises(ProgrammingError):
del p['a']
p['a'] = Property('', IntRange(), 0, export=False)
assert p['a'].default == 0
assert p['a'].export is False
assert p['a'].extname == ''
class Cls(HasProperties):
aa = Property('', IntRange(0, 99), '42', export=True)
bb = Property('', IntRange(), 0, export=False)
assert Cls.aa.default == 42
assert Cls.aa.export is True
assert Cls.aa.extname == '_aa'
cc = Cls()
with pytest.raises(BadValueError):
cc.aa = 137
assert Cls.bb.default == 0
assert Cls.bb.export is False
assert Cls.bb.extname == ''
class c(HasProperties):
properties = {
'a' : Property('', IntRange(), 1),
}
# properties
a = Property('', IntRange(), 1)
class cl(c):
properties = {
'a' : Property('', IntRange(), 3),
'b' : Property('', FloatRange(), 3.14),
'minabc': Property('', IntRange(), 8),
'maxabc': Property('', IntRange(), 9),
'minx': Property('', IntRange(), 2),
'maxy': Property('', IntRange(), 1),
}
# properties
a = Property('', IntRange(), 3)
b = Property('', FloatRange(), 3.14)
minabc = Property('', IntRange(), 8)
maxabc = Property('', IntRange(), 9)
minx = Property('', IntRange(), 2)
maxy = Property('', IntRange(), 1)
def test_HasProperties():
o = c()
assert o.properties['a'] == 1
assert o.a == 1
o = cl()
assert o.properties['a'] == 3
assert o.properties['b'] == 3.14
assert o.a == 3
assert o.b == 3.14
def test_Property_checks():
o = c()
@@ -119,6 +139,7 @@ def test_Property_checks():
with pytest.raises(ConfigError):
o.checkProperties()
def test_Property_override():
o1 = c()
class co(c):
@@ -131,10 +152,10 @@ def test_Property_override():
class cx(c): # pylint: disable=unused-variable
def a(self):
pass
assert 'collides with method' in str(e.value)
assert 'collides with' in str(e.value)
with pytest.raises(ProgrammingError) as e:
class cz(c): # pylint: disable=unused-variable
a = 's'
assert 'can not be set to' in str(e.value)
assert 'can not set' in str(e.value)