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
|
return r
|
||||||
|
|
||||||
|
|
||||||
# base class for all DataTypes
|
class SimpleDataType(HasProperties):
|
||||||
class DataType(HasProperties):
|
"""base class for simple datatypes, used in properties only"""
|
||||||
"""base class for all data types"""
|
|
||||||
IS_COMMAND = False
|
|
||||||
unit = ''
|
|
||||||
default = None
|
default = None
|
||||||
client = False # used on the client side
|
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""convert given value to our datatype and validate
|
"""convert given value to our datatype and validate
|
||||||
@@ -105,38 +101,10 @@ class DataType(HasProperties):
|
|||||||
"""
|
"""
|
||||||
return self.format_value(value, False)
|
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):
|
def export_value(self, value):
|
||||||
"""if needed, reformat value for transport"""
|
"""if needed, reformat value for transport"""
|
||||||
return value
|
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):
|
def set_properties(self, **kwds):
|
||||||
"""init datatype properties"""
|
"""init datatype properties"""
|
||||||
try:
|
try:
|
||||||
@@ -161,6 +129,34 @@ class DataType(HasProperties):
|
|||||||
# looks like the simplest way to make a deep copy
|
# looks like the simplest way to make a deep copy
|
||||||
return get_datatype(self.export_datatype())
|
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):
|
def compatible(self, other):
|
||||||
"""check other for compatibility
|
"""check other for compatibility
|
||||||
|
|
||||||
@@ -169,6 +165,10 @@ class DataType(HasProperties):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def export_datatype(self):
|
||||||
|
"""return a python object which after jsonifying identifies this datatype"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def set_main_unit(self, unit):
|
def set_main_unit(self, unit):
|
||||||
"""replace $ in unit by argument"""
|
"""replace $ in unit by argument"""
|
||||||
|
|
||||||
@@ -1131,10 +1131,23 @@ class CommandType(DataType):
|
|||||||
|
|
||||||
# internally used datatypes (i.e. only for programming the SEC-node)
|
# 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):
|
def __call__(self, value):
|
||||||
"""accepts a datatype"""
|
"""accepts a datatype"""
|
||||||
if isinstance(value, DataType):
|
if isinstance(value, SimpleDataType):
|
||||||
return value
|
return value
|
||||||
#TODO: not needed anymore?
|
#TODO: not needed anymore?
|
||||||
try:
|
try:
|
||||||
@@ -1155,7 +1168,7 @@ class DataTypeType(DataType):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ValueType(DataType):
|
class ValueType(SimpleDataType):
|
||||||
"""Can take any python value.
|
"""Can take any python value.
|
||||||
|
|
||||||
The optional (callable) validator can be used to restrict values to a
|
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"""
|
"""if needed, reformat value for transport"""
|
||||||
return value
|
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`
|
class NoneOr(SimpleDataType):
|
||||||
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):
|
|
||||||
"""validates a None or smth. else"""
|
"""validates a None or smth. else"""
|
||||||
default = None
|
default = None
|
||||||
|
|
||||||
@@ -1222,7 +1220,7 @@ class NoneOr(DataType):
|
|||||||
return self.other.export_value(value)
|
return self.other.export_value(value)
|
||||||
|
|
||||||
|
|
||||||
class OrType(DataType):
|
class OrType(SimpleDataType):
|
||||||
def __init__(self, *types):
|
def __init__(self, *types):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.types = types
|
self.types = types
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from frappy.datatypes import ArrayOf, BoolType, CommandType, DataType, \
|
from frappy.datatypes import ArrayOf, BoolType, CommandType, DataType, \
|
||||||
DataTypeType, EnumType, FloatRange, NoneOr, OrType, StringType, StructOf, \
|
DataTypeType, DefaultType, EnumType, FloatRange, NoneOr, OrType, StringType, \
|
||||||
TextType, TupleOf, ValueType
|
StructOf, TextType, TupleOf, ValueType
|
||||||
from frappy.errors import BadValueError, ProgrammingError, WrongTypeError
|
from frappy.errors import BadValueError, ProgrammingError, WrongTypeError
|
||||||
from frappy.lib import generalConfig
|
from frappy.lib import generalConfig
|
||||||
from frappy.properties import HasProperties, Property
|
from frappy.properties import HasProperties, Property
|
||||||
@@ -144,7 +144,7 @@ class Parameter(Accessible):
|
|||||||
extname='description', mandatory=True, export='always')
|
extname='description', mandatory=True, export='always')
|
||||||
datatype = Property(
|
datatype = Property(
|
||||||
'datatype of the Parameter (SECoP datainfo)', DataTypeType(),
|
'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(
|
readonly = Property(
|
||||||
'not changeable via SECoP (default True)', BoolType(),
|
'not changeable via SECoP (default True)', BoolType(),
|
||||||
extname='readonly', default=True, export='always')
|
extname='readonly', default=True, export='always')
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ def out_of_range(dt, *args):
|
|||||||
|
|
||||||
def test_DataType():
|
def test_DataType():
|
||||||
dt = DataType()
|
dt = DataType()
|
||||||
with pytest.raises(ProgrammingError):
|
with pytest.raises(NotImplementedError):
|
||||||
dt.export_datatype()
|
dt.export_datatype()
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
dt('')
|
dt('')
|
||||||
|
|||||||
Reference in New Issue
Block a user