Provide Properties with a description

useful für gui+auto generated docu

Change-Id: I0a2f7dc4b3c745145dd4b03956d15d33731cf980
Reviewed-on: https://forge.frm2.tum.de/review/20949
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 2019-07-24 10:57:18 +02:00
parent 7c620901c9
commit 95d50fb51e
8 changed files with 72 additions and 45 deletions

View File

@ -68,13 +68,17 @@ class Module(HasProperties):
# note: the names map to a [datatype, value] list, value comes from the cfg file,
# datatype is fixed!
properties = {
'export': Property(BoolType(), default=True, export=False),
'group': Property(StringType(), default='', extname='group'),
'description': Property(StringType(), extname='description', mandatory=True),
'meaning': Property(TupleOf(StringType(),IntRange(0,50)), default=('',0), extname='meaning'),
'visibility': Property(EnumType('visibility', user=1, advanced=2, expert=3), default=1, extname='visibility'),
'implementation': Property(StringType(), extname='implementation'),
'interface_class': Property(ArrayOf(StringType()), extname='interface_class'),
'export': Property('Flag if this Module is to be exported', BoolType(), default=True, export=False),
'group': Property('Optional group the Module belongs to', StringType(), default='', extname='group'),
'description': Property('Description of the module', StringType(), extname='description', mandatory=True),
'meaning': Property('Optional Meaning indicator', TupleOf(StringType(),IntRange(0,50)),
default=('',0), extname='meaning'),
'visibility': Property('Optional visibility hint', EnumType('visibility', user=1, advanced=2, expert=3),
default='user', extname='visibility'),
'implementation': Property('Internal name of the implementation class of the module', StringType(),
extname='implementation'),
'interface_class': Property('Offical highest Interface-class of the module', ArrayOf(StringType()),
extname='interface_class'),
# what else?
}

View File

@ -25,7 +25,8 @@ from __future__ import division, print_function
from collections import OrderedDict
from secop.datatypes import CommandType, DataType, StringType, BoolType, EnumType, DataTypeType, ValueType, OrType
from secop.datatypes import CommandType, DataType, StringType, BoolType, EnumType, DataTypeType, ValueType, OrType, \
NoneOr
from secop.errors import ProgrammingError
from secop.properties import HasProperties, Property
@ -91,18 +92,26 @@ class Parameter(Accessible):
"""
properties = {
u'description': Property(StringType(), extname=u'description', mandatory=True),
u'datatype': Property(DataTypeType(), extname=u'datatype', mandatory=True),
u'unit': Property(StringType(), extname=u'unit', default=''), # goodie, should be on the datatype!
u'readonly': Property(BoolType(), extname=u'readonly', default=True),
u'group': Property(StringType(), extname=u'group', default=''),
u'visibility': Property(EnumType(u'visibility', user=1, advanced=2, expert=3),
u'description': Property('Description of the Parameter', StringType(),
extname=u'description', mandatory=True),
u'datatype': Property('Datatype of the Parameter', DataTypeType(),
extname=u'datatype', mandatory=True),
u'unit': Property('[legacy] unit of the parameter. This should now be on the datatype!', StringType(),
extname=u'unit', default=''), # goodie, should be on the datatype!
u'readonly': Property('Is the Parameter readonly? (vs. changeable via SECoP)', BoolType(),
extname=u'readonly', default=True),
u'group': Property('Optional parameter group this parameter belongs to', StringType(),
extname=u'group', default=''),
u'visibility': Property('Optional visibility hint', EnumType(u'visibility', user=1, advanced=2, expert=3),
extname=u'visibility', default=1),
u'constant': Property(ValueType(), extname=u'constant', default=None),
u'default': Property(ValueType(), export=False, default=None, mandatory=False),
u'export': Property(OrType(BoolType(), StringType()), export=False, default=True),
u'poll': Property(ValueType(), export=False, default=True), # check default value!
u'optional': Property(BoolType(), export=False, default=False),
u'constant': Property('Optional constant value for constant parameters', ValueType(),
extname=u'constant', default=None),
u'default': Property('Default (startup) value of this parameter if it can not be read from the hardware.',
ValueType(), export=False, default=None, mandatory=False),
u'export': Property('Is this parameter accessible via SECoP? (vs. internal parameter)',
OrType(BoolType(), StringType()), export=False, default=True),
u'poll': Property('Polling indicator', ValueType(), export=False, default=True), # check default value!
u'optional': Property('[Internal] is this parameter optional?', BoolType(), export=False, default=False),
}
value = None
@ -242,18 +251,27 @@ class Command(Accessible):
"""
# datatype is not listed (handled separately)
properties = {
u'description': Property(StringType(), extname=u'description', export=True, mandatory=True),
u'group': Property(StringType(), extname=u'group', export=True, default=''),
u'visibility': Property(EnumType(u'visibility', user=1, advanced=2, expert=3),
u'description': Property('Description of the Command', StringType(),
extname=u'description', export=True, mandatory=True),
u'group': Property('Optional command group of the command.', StringType(),
extname=u'group', export=True, default=''),
u'visibility': Property('Optional visibility hint', EnumType(u'visibility', user=1, advanced=2, expert=3),
extname=u'visibility', export=True, default=1),
u'export': Property(OrType(BoolType(), StringType()), export=False, default=True),
u'optional': Property(BoolType(), export=False, default=False, settable=False),
u'datatype': Property(DataTypeType(), extname=u'datatype', mandatory=True),
u'export': Property('[internal] Flag: is the command accessible via SECoP? (vs. pure internal use)',
OrType(BoolType(), StringType()), export=False, default=True),
u'optional': Property('[internal] is The comamnd optional to implement? (vs. mandatory',
BoolType(), export=False, default=False, settable=False),
u'datatype': Property('[internal] datatype of the command, auto generated from \'argument\' and \'result\'',
DataTypeType(), extname=u'datatype', mandatory=True),
u'argument': Property('Datatype of the argument to the command, or None.',
NoneOr(DataTypeType()), export=False, mandatory=True),
u'result': Property('Datatype of the result from the command, or None.',
NoneOr(DataTypeType()), export=False, mandatory=True),
}
def __init__(self, description, argument=None, result=None, ctr=None, **kwds):
def __init__(self, description, ctr=None, **kwds):
kwds[u'description'] = description
kwds[u'datatype'] = CommandType(argument, result)
kwds[u'datatype'] = CommandType(kwds.get('argument', None), kwds.get('result', None))
super(Command, self).__init__(**kwds)
if ctr is not None:
self.ctr = ctr

View File

@ -36,15 +36,16 @@ class Property(object):
'''base class holding info about a property
properties are only sent to the ECS if export is True, or an extname is set
if mandatory is True, they MUST have avalue in the cfg file assigned to them.
if mandatory is True, they MUST have a value in the cfg file assigned to them.
otherwise, this is optional in which case the default value is applied.
All values MUST pass the datatype.
'''
# note: this is inteded to be used on base classes.
# the VALUES of the properties are on the instances!
def __init__(self, datatype, default=None, extname='', export=False, mandatory=False, settable=True):
def __init__(self, description, datatype, default=None, extname='', export=False, mandatory=False, settable=True):
if not callable(datatype):
raise ValueError(u'datatype MUST be a valid DataType or a basic_validator')
self.description = description
self.default = datatype.default if default is None else datatype(default)
self.datatype = datatype
self.extname = unicode(extname)
@ -53,8 +54,8 @@ class Property(object):
self.settable = settable or mandatory # settable means settable from the cfg file
def __repr__(self):
return u'Property(%s, default=%r, extname=%r, export=%r, mandatory=%r)' % (
self.datatype, self.default, self.extname, self.export, self.mandatory)
return u'Property(%s, %s, default=%r, extname=%r, export=%r, mandatory=%r)' % (
self.description, self.datatype, self.default, self.extname, self.export, self.mandatory)
class Properties(OrderedDict):

View File

@ -33,12 +33,12 @@ from secop.modules import Drivable, Override, Parameter
# test custom property (value.test can be changed in config file)
from secop.properties import Property
Parameter.properties['test'] = Property(StringType(), default='', export=True)
Parameter.properties['test'] = Property('A Property for testing purposes', StringType(), default='', export=True)
class CryoBase(Drivable):
properties = {
'is_cryo': Property(BoolType(), default=True, export=True),
'is_cryo': Property('private Flag if this is a cryostat', BoolType(), default=True, export=True),
}

View File

@ -35,7 +35,7 @@ from secop.properties import Property
class Parameter(SECoP_Parameter):
properties = {
'test' : Property(StringType(), default='', mandatory=False, extname='test'),
'test' : Property('A property for testing purposes', StringType(), default='', mandatory=False, extname='test'),
}
PERSIST = 101
@ -62,7 +62,8 @@ class Switch(Drivable):
}
properties = {
'description' : Property(StringType(), default='no description', mandatory=False, extname='description'),
'description' : Property('The description of the Module', StringType(),
default='no description', mandatory=False, extname='description'),
}
def read_value(self):

View File

@ -101,7 +101,7 @@ class Temp(Drivable):
class Lower(Communicator):
"""Communicator returning a lowercase version of the request"""
command = {
'communicate': Command('lowercase a string', StringType(), StringType(), export='communicate'),
'communicate': Command('lowercase a string', argument=StringType(), result=StringType(), export='communicate'),
}
def do_communicate(self, request):
return unicode(request).lower()

View File

@ -39,7 +39,7 @@ def test_Command():
assert cmd.for_export() == {u'datatype': [u'command', {u'argument': None, u'result': None}],
u'description': u'do_something'}
cmd = Command(u'do_something', IntRange(-9,9), IntRange(-1,1))
cmd = Command(u'do_something', argument=IntRange(-9,9), result=IntRange(-1,1))
assert cmd.description
assert isinstance(cmd.argument, IntRange)
assert isinstance(cmd.result, IntRange)

View File

@ -54,7 +54,7 @@ V_test_Property = [
def test_Property():
for entry in V_test_Property:
args, check = entry
p = Property(*args)
p = Property('', *args)
for k,v in check.items():
assert getattr(p, k) == v
@ -62,15 +62,18 @@ def test_Property_basic():
with pytest.raises(TypeError):
# pylint: disable=no-value-for-parameter
Property()
with pytest.raises(TypeError):
# pylint: disable=no-value-for-parameter
Property('')
with pytest.raises(ValueError):
Property(1)
Property(IntRange(), '42', 'extname', False, False)
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)
p['a'] = Property('', IntRange(), '42', export=True)
assert p['a'].default == 42
assert p['a'].export is True
assert p['a'].extname == u'_a'
@ -80,7 +83,7 @@ def test_Properties():
del p[1]
with pytest.raises(ProgrammingError):
del p['a']
p['a'] = Property(IntRange(), 0, export=False)
p['a'] = Property('', IntRange(), 0, export=False)
assert p['a'].default == 0
assert p['a'].export is False
assert p['a'].extname == ''
@ -88,13 +91,13 @@ def test_Properties():
class c(HasProperties):
properties = {
'a' : Property(IntRange(), 1),
'a' : Property('', IntRange(), 1),
}
class cl(c):
properties = {
'a' : Property(IntRange(), 3),
'b' : Property(FloatRange(), 3.14),
'a' : Property('', IntRange(), 3),
'b' : Property('', FloatRange(), 3.14),
}
def test_HasProperties():