datatypes: split base classes for internal and SECoP datatypes
Simple datatypes used only in properties like ValueType of NoneOr do not need a couple of methods. Splitting the base class avoids warnings about unimlemented abstract methods. Change-Id: Ie7d5754c44a5fb5c3ed8569df544495450347082
This commit is contained in:
@@ -53,13 +53,9 @@ def shortrepr(value):
|
||||
return r
|
||||
|
||||
|
||||
# base class for all DataTypes
|
||||
class DataType(HasProperties):
|
||||
"""base class for all data types"""
|
||||
IS_COMMAND = False
|
||||
unit = ''
|
||||
class SimpleDataType(HasProperties):
|
||||
"""base class for simple datatypes, used in properties only"""
|
||||
default = None
|
||||
client = False # used on the client side
|
||||
|
||||
def __call__(self, value):
|
||||
"""convert given value to our datatype and validate
|
||||
@@ -105,38 +101,10 @@ class DataType(HasProperties):
|
||||
"""
|
||||
return self.format_value(value, False)
|
||||
|
||||
def export_datatype(self):
|
||||
"""return a python object which after jsonifying identifies this datatype"""
|
||||
raise ProgrammingError(
|
||||
f"{type(self).__name__} is not able to be exported to SECoP. "
|
||||
f"It is intended for internal use only."
|
||||
)
|
||||
|
||||
def export_value(self, value):
|
||||
"""if needed, reformat value for transport"""
|
||||
return value
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
return self(value)
|
||||
|
||||
def format_value(self, value, unit=True):
|
||||
"""format a value of this type into a string
|
||||
|
||||
This is intended for 'nice' formatting for humans and is NOT
|
||||
the opposite of :meth:`from_string`
|
||||
|
||||
possible values of unit:
|
||||
- True: use the string of the datatype
|
||||
- False: return a value interpretable by ast.literal_eval (internal use only)
|
||||
- any other string: use as unit (internal use only)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_properties(self, **kwds):
|
||||
"""init datatype properties"""
|
||||
try:
|
||||
@@ -161,6 +129,34 @@ class DataType(HasProperties):
|
||||
# looks like the simplest way to make a deep copy
|
||||
return get_datatype(self.export_datatype())
|
||||
|
||||
|
||||
class DataType(SimpleDataType):
|
||||
"""base class for data types used in parameters and commands"""
|
||||
IS_COMMAND = False
|
||||
unit = ''
|
||||
client = False # used on the client side
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
return self(value)
|
||||
|
||||
def format_value(self, value, unit=True):
|
||||
"""format a value of this type into a string
|
||||
|
||||
This is intended for 'nice' formatting for humans and is NOT
|
||||
the opposite of :meth:`from_string`
|
||||
|
||||
possible values of unit:
|
||||
- True: use the string of the datatype
|
||||
- False: return a value interpretable by ast.literal_eval (internal use only)
|
||||
- any other string: use as unit (internal use only)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def compatible(self, other):
|
||||
"""check other for compatibility
|
||||
|
||||
@@ -169,6 +165,10 @@ class DataType(HasProperties):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def export_datatype(self):
|
||||
"""return a python object which after jsonifying identifies this datatype"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_main_unit(self, unit):
|
||||
"""replace $ in unit by argument"""
|
||||
|
||||
@@ -1131,10 +1131,23 @@ class CommandType(DataType):
|
||||
|
||||
# internally used datatypes (i.e. only for programming the SEC-node)
|
||||
|
||||
class DataTypeType(DataType):
|
||||
class DefaultType(DataType):
|
||||
"""datatype used as default for parameters
|
||||
|
||||
needs some minimal interface to avoid errors when
|
||||
the datatype of a parameter is not yet defined
|
||||
"""
|
||||
def __call__(self, value):
|
||||
return value
|
||||
|
||||
def setProperty(self, key, value):
|
||||
"""silently ignored"""
|
||||
|
||||
|
||||
class DataTypeType(SimpleDataType):
|
||||
def __call__(self, value):
|
||||
"""accepts a datatype"""
|
||||
if isinstance(value, DataType):
|
||||
if isinstance(value, SimpleDataType):
|
||||
return value
|
||||
#TODO: not needed anymore?
|
||||
try:
|
||||
@@ -1155,7 +1168,7 @@ class DataTypeType(DataType):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ValueType(DataType):
|
||||
class ValueType(SimpleDataType):
|
||||
"""Can take any python value.
|
||||
|
||||
The optional (callable) validator can be used to restrict values to a
|
||||
@@ -1188,23 +1201,8 @@ class ValueType(DataType):
|
||||
"""if needed, reformat value for transport"""
|
||||
return value
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def setProperty(self, key, value):
|
||||
"""silently ignored
|
||||
|
||||
as ValueType is used for the datatype default, this makes code
|
||||
shorter for cases, where the datatype may not yet be defined
|
||||
"""
|
||||
|
||||
|
||||
class NoneOr(DataType):
|
||||
class NoneOr(SimpleDataType):
|
||||
"""validates a None or smth. else"""
|
||||
default = None
|
||||
|
||||
@@ -1222,7 +1220,7 @@ class NoneOr(DataType):
|
||||
return self.other.export_value(value)
|
||||
|
||||
|
||||
class OrType(DataType):
|
||||
class OrType(SimpleDataType):
|
||||
def __init__(self, *types):
|
||||
super().__init__()
|
||||
self.types = types
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
import inspect
|
||||
|
||||
from frappy.datatypes import ArrayOf, BoolType, CommandType, DataType, \
|
||||
DataTypeType, EnumType, FloatRange, NoneOr, OrType, StringType, StructOf, \
|
||||
TextType, TupleOf, ValueType
|
||||
DataTypeType, DefaultType, EnumType, FloatRange, NoneOr, OrType, StringType, \
|
||||
StructOf, TextType, TupleOf, ValueType
|
||||
from frappy.errors import BadValueError, ProgrammingError, WrongTypeError
|
||||
from frappy.lib import generalConfig
|
||||
from frappy.properties import HasProperties, Property
|
||||
@@ -144,7 +144,7 @@ class Parameter(Accessible):
|
||||
extname='description', mandatory=True, export='always')
|
||||
datatype = Property(
|
||||
'datatype of the Parameter (SECoP datainfo)', DataTypeType(),
|
||||
extname='datainfo', mandatory=True, export='always', default=ValueType())
|
||||
extname='datainfo', mandatory=True, export='always', default=DefaultType())
|
||||
readonly = Property(
|
||||
'not changeable via SECoP (default True)', BoolType(),
|
||||
extname='readonly', default=True, export='always')
|
||||
|
||||
@@ -75,7 +75,7 @@ def out_of_range(dt, *args):
|
||||
|
||||
def test_DataType():
|
||||
dt = DataType()
|
||||
with pytest.raises(ProgrammingError):
|
||||
with pytest.raises(NotImplementedError):
|
||||
dt.export_datatype()
|
||||
with pytest.raises(NotImplementedError):
|
||||
dt('')
|
||||
|
||||
Reference in New Issue
Block a user