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

@ -42,9 +42,10 @@ class Property(object):
'''
# 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():