diff --git a/secop/datatypes.py b/secop/datatypes.py index 65c62fa..48fb97c 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -57,7 +57,6 @@ DEFAULT_MAX_INT = 16777216 class DataType(object): - as_json = [u'undefined'] IS_COMMAND = False unit = u'' fmtstr = u'%r' @@ -75,7 +74,7 @@ class DataType(object): def export_datatype(self): """return a python object which after jsonifying identifies this datatype""" - return self.as_json + raise NotImplementedError def export_value(self, value): """if needed, reformat value for transport""" @@ -134,8 +133,7 @@ class FloatRange(DataType): if self.relative_resolution < 0: raise ValueError(u'relative_resolution MUST be >=0') - @property - def as_json(self): + def export_datatype(self): return [u'double', {k: getattr(self, k) for k, v in self._defaults.items() if v != getattr(self, k)}] @@ -151,7 +149,7 @@ class FloatRange(DataType): (value, self.min, self.max)) def __repr__(self): - items = [u'%s=%r' % (k,v) for k,v in self.as_json[1].items()] + items = [u'%s=%r' % (k,v) for k,v in self.export_datatype()[1].items()] return u'FloatRange(%s)' % (', '.join(items)) def export_value(self, value): @@ -185,8 +183,7 @@ class IntRange(DataType): if self.min > self.max: raise ValueError(u'Max must be larger then min!') - @property - def as_json(self): + def export_datatype(self): return [u'int', {"min": self.min, "max": self.max}] def validate(self, value): @@ -253,8 +250,7 @@ class ScaledInteger(DataType): # Remark: Datatype.copy() will round min, max to a multiple of self.scale # this should be o.k. - @property - def as_json(self): + def export_datatype(self): info = {k: getattr(self, k) for k, v in self._defaults.items() if v != getattr(self, k)} info['scale'] = self.scale @@ -279,7 +275,7 @@ class ScaledInteger(DataType): return value # return 'actual' value (which is more discrete than a float) def __repr__(self): - hints = self.as_json[1] + hints = self.export_datatype()[1] hints.pop('scale') items = ['%g' % self.scale] for k,v in hints.items(): @@ -320,8 +316,7 @@ class EnumType(DataType): # as the name is not exported, we have to implement copy ourselfs return EnumType(self._enum) - @property - def as_json(self): + def export_datatype(self): return [u'enum'] + [{u"members":dict((m.name, m.value) for m in self._enum.members)}] def __repr__(self): @@ -364,7 +359,9 @@ class BLOBType(DataType): raise ValueError(u'sizes must be bigger than or equal to 0!') elif self.minsize > self.maxsize: raise ValueError(u'maxsize must be bigger than or equal to minsize!') - self.as_json = [u'blob', dict(min=minsize, max=maxsize)] + + def export_datatype(self): + return [u'blob', dict(min=self.minsize, max=self.maxsize)] def __repr__(self): return u'BLOB(%d, %d)' % (self.minsize, self.maxsize) @@ -400,7 +397,6 @@ class BLOBType(DataType): class StringType(DataType): - as_json = [u'string'] minsize = None maxsize = None @@ -413,7 +409,9 @@ class StringType(DataType): raise ValueError(u'sizes must be bigger than or equal to 0!') elif self.minsize > self.maxsize: raise ValueError(u'maxsize must be bigger than or equal to minsize!') - self.as_json = [u'string', dict(min=minsize, max=maxsize)] + + def export_datatype(self): + return [u'string', dict(min=self.minsize, max=self.maxsize)] def __repr__(self): return u'StringType(%d, %d)' % (self.minsize, self.maxsize) @@ -454,8 +452,8 @@ class StringType(DataType): # Bool is a special enum class BoolType(DataType): - def __init__(self): - self.as_json = [u'bool', {}] + def export_datatype(self): + return [u'bool', {}] def __repr__(self): return u'BoolType()' @@ -513,13 +511,10 @@ class ArrayOf(DataType): raise ValueError(u'Maximum size must be >= 1!') elif self.minsize > self.maxsize: raise ValueError(u'maxsize must be bigger than or equal to minsize!') - # if only one arg is given, it is maxsize! - if self.unit: - self.as_json = [u'array', dict(min=minsize, max=maxsize, - members=members.as_json, unit=self.unit)] - else: - self.as_json = [u'array', dict(min=minsize, max=maxsize, - members=members.as_json)] + + def export_datatype(self): + return [u'array', dict(min=self.minsize, max=self.maxsize, + members=self.members.export_datatype())] def __repr__(self): return u'ArrayOf(%s, %s, %s)' % ( @@ -574,7 +569,9 @@ class TupleOf(DataType): raise ValueError( u'TupleOf only works with DataType objs as arguments!') self.members = members - self.as_json = [u'tuple', dict(members=[subtype.as_json for subtype in members])] + + def export_datatype(self): + return [u'tuple', dict(members=[subtype.export_datatype() for subtype in self.members])] def __repr__(self): return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.members]) @@ -630,16 +627,17 @@ class StructOf(DataType): if name not in members: raise ProgrammingError( u'Only members of StructOf may be declared as optional!') - self.as_json = [u'struct', dict(members=dict((n, s.as_json) - for n, s in list(members.items())))] - if optional: - self.as_json[1]['optional'] = self.optional def __repr__(self): return u'StructOf(%s)' % u', '.join( [u'%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]) + def export_datatype(self): + return [u'struct', dict(members=dict((n, s.export_datatype()) + for n, s in list(self.members.items())), + optional=self.optional)] + def validate(self, value): """return the validated value or raise""" try: @@ -697,11 +695,13 @@ class CommandType(DataType): self.argtype = argument self.resulttype = result - if argument: - argument = argument.as_json - if result: - result = result.as_json - self.as_json = [u'command', dict(argument=argument, result=result)] + def export_datatype(self): + info = {} + if self.argtype: + info['argument'] = self.argtype.export_datatype() + if self.resulttype: + info['result'] = self.argtype.export_datatype() + return [u'command', info] def __repr__(self): argstr = repr(self.argtype) if self.argtype else '' diff --git a/test/test_datatypes.py b/test/test_datatypes.py index 56b6b92..e7e9f14 100644 --- a/test/test_datatypes.py +++ b/test/test_datatypes.py @@ -38,19 +38,18 @@ def copytest(dt): def test_DataType(): dt = DataType() - assert dt.as_json == [u'undefined'] - with pytest.raises(NotImplementedError): - dt = DataType() + dt.export_datatype() + with pytest.raises(NotImplementedError): dt.validate('') - dt.export_value('') - dt.import_value('') + dt.export_value('') + dt.import_value('') def test_FloatRange(): dt = FloatRange(-3.14, 3.14) copytest(dt) - assert dt.as_json == [u'double', {u'min':-3.14, u'max':3.14}] + assert dt.export_datatype() == [u'double', {u'min':-3.14, u'max':3.14}] with pytest.raises(ValueError): dt.validate(9) @@ -69,16 +68,16 @@ def test_FloatRange(): FloatRange(u'x', u'Y') # check that unit can be changed dt.unit = u'K' - assert dt.as_json == [u'double', {u'min':-3.14, u'max':3.14, u'unit': u'K'}] + assert dt.export_datatype() == [u'double', {u'min':-3.14, u'max':3.14, u'unit': u'K'}] dt = FloatRange() copytest(dt) - assert dt.as_json == [u'double', {}] + assert dt.export_datatype() == [u'double', {}] dt = FloatRange(unit=u'X', fmtstr=u'%r', absolute_resolution=1, relative_resolution=0.1) copytest(dt) - assert dt.as_json == [u'double', {u'unit':u'X', u'fmtstr':u'%r', + assert dt.export_datatype() == [u'double', {u'unit':u'X', u'fmtstr':u'%r', u'absolute_resolution':1, u'relative_resolution':0.1}] assert dt.validate(4) == 4 @@ -90,7 +89,7 @@ def test_FloatRange(): def test_IntRange(): dt = IntRange(-3, 3) copytest(dt) - assert dt.as_json == [u'int', {u'min':-3, u'max':3}] + assert dt.export_datatype() == [u'int', {u'min':-3, u'max':3}] with pytest.raises(ValueError): dt.validate(9) @@ -107,16 +106,16 @@ def test_IntRange(): dt = IntRange() copytest(dt) - assert dt.as_json[0] == u'int' - assert dt.as_json[1][u'min'] < 0 < dt.as_json[1][u'max'] - assert dt.as_json == [u'int', {u'max': 16777216, u'min': -16777216}] + assert dt.export_datatype()[0] == u'int' + assert dt.export_datatype()[1][u'min'] < 0 < dt.export_datatype()[1][u'max'] + assert dt.export_datatype() == [u'int', {u'max': 16777216, u'min': -16777216}] assert dt.format_value(42) == u'42' def test_ScaledInteger(): dt = ScaledInteger(0.01, -3, 3) copytest(dt) # serialisation of datatype contains limits on the 'integer' value - assert dt.as_json == [u'scaled', {u'scale':0.01, u'min':-300, u'max':300}] + assert dt.export_datatype() == [u'scaled', {u'scale':0.01, u'min':-300, u'max':300}] with pytest.raises(ValueError): dt.validate(9) @@ -136,7 +135,7 @@ def test_ScaledInteger(): ScaledInteger(scale=-10, minval=1, maxval=2) # check that unit can be changed dt.unit = u'A' - assert dt.as_json == [u'scaled', {u'scale':0.01, u'min':-300, u'max':300, u'unit': u'A'}] + assert dt.export_datatype() == [u'scaled', {u'scale':0.01, u'min':-300, u'max':300, u'unit': u'A'}] assert dt.export_value(0.0001) == int(0) assert dt.export_value(2.71819) == int(272) @@ -145,7 +144,7 @@ def test_ScaledInteger(): dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%r', absolute_resolution=0.001, relative_resolution=1e-5) copytest(dt) - assert dt.as_json == [u'scaled', {u'scale':0.003,u'min':0,u'max':333, + assert dt.export_datatype() == [u'scaled', {u'scale':0.003,u'min':0,u'max':333, u'unit':u'X', u'fmtstr':u'%r', u'absolute_resolution':0.001, u'relative_resolution':1e-5}] @@ -167,7 +166,7 @@ def test_EnumType(): dt = EnumType(u'dt', a=3, c=7, stuff=1) copytest(dt) - assert dt.as_json == [u'enum', dict(members=dict(a=3, c=7, stuff=1))] + assert dt.export_datatype() == [u'enum', dict(members=dict(a=3, c=7, stuff=1))] with pytest.raises(ValueError): dt.validate(9) @@ -202,14 +201,14 @@ def test_BLOBType(): # test constructor catching illegal arguments dt = BLOBType() copytest(dt) - assert dt.as_json == [u'blob', {u'min':0, u'max':255}] + assert dt.export_datatype() == [u'blob', {u'min':0, u'max':255}] dt = BLOBType(10) copytest(dt) - assert dt.as_json == [u'blob', {u'min':10, u'max':10}] + assert dt.export_datatype() == [u'blob', {u'min':10, u'max':10}] dt = BLOBType(3, 10) copytest(dt) - assert dt.as_json == [u'blob', {u'min':3, u'max':10}] + assert dt.export_datatype() == [u'blob', {u'min':3, u'max':10}] with pytest.raises(ValueError): dt.validate(9) @@ -236,11 +235,11 @@ def test_StringType(): copytest(dt) dt = StringType(12) copytest(dt) - assert dt.as_json == [u'string', {u'min':12, u'max':12}] + assert dt.export_datatype() == [u'string', {u'min':12, u'max':12}] dt = StringType(4, 11) copytest(dt) - assert dt.as_json == [u'string', {u'min':4, u'max':11}] + assert dt.export_datatype() == [u'string', {u'min':4, u'max':11}] with pytest.raises(ValueError): dt.validate(9) @@ -266,7 +265,7 @@ def test_BoolType(): # test constructor catching illegal arguments dt = BoolType() copytest(dt) - assert dt.as_json == [u'bool', {}] + assert dt.export_datatype() == [u'bool', {}] with pytest.raises(ValueError): dt.validate(9) @@ -298,13 +297,13 @@ def test_ArrayOf(): ArrayOf(-3, IntRange(-10,10)) dt = ArrayOf(IntRange(-10, 10), 5) copytest(dt) - assert dt.as_json == [u'array', {u'min':5, u'max':5, + assert dt.export_datatype() == [u'array', {u'min':5, u'max':5, u'members':[u'int', {u'min':-10, u'max':10}]}] dt = ArrayOf(FloatRange(-10, 10, unit=u'Z'), 1, 3) copytest(dt) - assert dt.as_json == [u'array', {u'min':1, u'max':3, + assert dt.export_datatype() == [u'array', {u'min':1, u'max':3, u'members':[u'double', {u'min':-10, u'max':10, u'unit':u'Z'}]}] @@ -330,7 +329,7 @@ def test_TupleOf(): dt = TupleOf(IntRange(-10, 10), BoolType()) copytest(dt) - assert dt.as_json == [u'tuple', {u'members':[[u'int', {u'min':-10, + assert dt.export_datatype() == [u'tuple', {u'members':[[u'int', {u'min':-10, u'max':10}], [u'bool', {}]]}] @@ -357,7 +356,7 @@ def test_StructOf(): dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999), optional=[u'an_int']) copytest(dt) - assert dt.as_json == [u'struct', {u'members':{u'a_string': + assert dt.export_datatype() == [u'struct', {u'members':{u'a_string': [u'string', {u'min':0, u'max':55}], u'an_int': [u'int', {u'min':0, u'max':999}],}, @@ -434,8 +433,8 @@ def test_get_datatype(): u'max':111}]), ScaledInteger) dt = ScaledInteger(scale=0.03, minval=0, maxval=9.9) - assert dt.as_json == [u'scaled', {u'max':330, u'min':0, u'scale':0.03}] - assert get_datatype(dt.as_json).as_json == dt.as_json + assert dt.export_datatype() == [u'scaled', {u'max':330, u'min':0, u'scale':0.03}] + assert get_datatype(dt.export_datatype()).export_datatype() == dt.export_datatype() with pytest.raises(ValueError): get_datatype([u'scaled']) # dict missing