diff --git a/secop/datatypes.py b/secop/datatypes.py index c22f2ed..be75563 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -59,6 +59,8 @@ DEFAULT_MAX_INT = 16777216 class DataType(object): as_json = [u'undefined'] IS_COMMAND = False + unit = u'' + fmtstr = u'%r' def validate(self, value): """check if given value (a python obj) is valid for this datatype @@ -87,12 +89,18 @@ class DataType(object): """ return value + def format_value(self, value, unit=None): + """format a value of this type into a unicode string + + This is intended for 'nice' formatting for humans and is NOT + the opposite of :meth:`from_string` + if unit is given, use it, else use the unit of the datatype (if any)""" + raise NotImplementedError + class FloatRange(DataType): """Restricted float type""" - unit = u'' - fmtstr = u'%f' def __init__(self, minval=None, maxval=None, unit=u'', fmtstr=u'', absolute_precision=None, relative_precision=None,): # store hints @@ -170,13 +178,17 @@ class FloatRange(DataType): value = float(text) return self.validate(value) + def format_value(self, value, unit=None): + if unit is None: + unit = self.unit + if unit: + return u' '.join([self.fmtstr % value, unit]) + return self.fmtstr % value class IntRange(DataType): """Restricted int type""" - unit = u'' - fmtstr = u'%f' def __init__(self, minval=None, maxval=None, fmtstr=u'%d', unit=u''): self.hints = {} self.fmtstr = unicode(fmtstr) @@ -232,6 +244,13 @@ class IntRange(DataType): value = int(text) return self.validate(value) + def format_value(self, value, unit=None): + if unit is None: + unit = self.unit + if unit: + return u' '.join([self.fmtstr % value, unit]) + return self.fmtstr % value + class ScaledInteger(DataType): """Scaled integer int type @@ -239,8 +258,6 @@ class ScaledInteger(DataType): note: limits are for the scaled value (i.e. the internal value) the scale is only used for calculating to/from transport serialisation""" - unit = u'' - fmtstr = u'%f' def __init__(self, scale, minval=None, maxval=None, unit=u'', fmtstr=u'', absolute_precision=None, relative_precision=None,): self.scale = float(scale) @@ -314,9 +331,16 @@ class ScaledInteger(DataType): return self.scale * int(value) def from_string(self, text): - value = int(text) + value = float(text) return self.validate(value) + def format_value(self, value, unit=None): + if unit is None: + unit = self.unit + if unit: + return u' '.join([self.fmtstr % value, unit]) + return self.fmtstr % value + class EnumType(DataType): @@ -352,6 +376,9 @@ class EnumType(DataType): def from_string(self, text): return self.validate(text) + def format_value(self, value, unit=None): + return u'%s<%s>' % (self._enum[value].name, self._enum[value].value) + class BLOBType(DataType): minsize = None @@ -399,6 +426,9 @@ class BLOBType(DataType): # XXX: return self.validate(value) + def format_value(self, value, unit=None): + return repr(value) + class StringType(DataType): as_json = [u'string'] @@ -448,6 +478,9 @@ class StringType(DataType): value = unicode(text) return self.validate(value) + def format_value(self, value, unit=None): + return repr(value) + # Bool is a special enum class BoolType(DataType): @@ -478,6 +511,10 @@ class BoolType(DataType): value = text return self.validate(value) + + def format_value(self, value, unit=None): + return repr(bool(value)) + # # nested types # @@ -486,9 +523,9 @@ class BoolType(DataType): class ArrayOf(DataType): minsize = None maxsize = None - subtype = None + members = None - def __init__(self, members, minsize=0, maxsize=None): + def __init__(self, members, minsize=0, maxsize=None, unit=u''): if not isinstance(members, DataType): raise ValueError( u'ArrayOf only works with a DataType as first argument!') @@ -496,7 +533,8 @@ class ArrayOf(DataType): # argument default to 10 if maxsize is None: maxsize = minsize or 10 - self.subtype = members + self.members = members + self.unit = unit self.minsize = int(minsize) self.maxsize = int(maxsize) @@ -507,11 +545,16 @@ class ArrayOf(DataType): 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! - self.as_json = [u'array', dict(min=minsize, max=maxsize, members=members.as_json)] + 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 __repr__(self): return u'ArrayOf(%s, %s, %s)' % ( - repr(self.subtype), self.minsize or u'unspecified', self.maxsize or u'unspecified') + repr(self.members), self.minsize, self.maxsize) def validate(self, value): """validate a external representation to an internal one""" @@ -525,17 +568,17 @@ class ArrayOf(DataType): raise ValueError( u'Array too big, holds at most %d elements!' % self.minsize) # apply subtype valiation to all elements and return as list - return [self.subtype.validate(elem) for elem in value] + return [self.members.validate(elem) for elem in value] raise ValueError( u'Can not convert %s to ArrayOf DataType!' % repr(value)) def export_value(self, value): """returns a python object fit for serialisation""" - return [self.subtype.export_value(elem) for elem in value] + return [self.members.export_value(elem) for elem in value] def import_value(self, value): """returns a python object from serialisation""" - return [self.subtype.import_value(elem) for elem in value] + return [self.members.import_value(elem) for elem in value] def from_string(self, text): value, rem = Parser.parse(text) @@ -543,43 +586,51 @@ class ArrayOf(DataType): raise ProtocolError(u'trailing garbage: %r' % rem) return self.validate(value) + def format_value(self, value, unit=None): + if unit is None: + unit = self.unit or self.members.unit + res = u'[%s]' % (', '.join([self.members.format_value(elem, u'') for elem in value])) + if unit: + return ' '.join([res, unit]) + return res + class TupleOf(DataType): - def __init__(self, *subtypes): - if not subtypes: + def __init__(self, *members): + if not members: raise ValueError(u'Empty tuples are not allowed!') - for subtype in subtypes: + for subtype in members: if not isinstance(subtype, DataType): raise ValueError( u'TupleOf only works with DataType objs as arguments!') - self.subtypes = subtypes - self.as_json = [u'tuple', dict(members=[subtype.as_json for subtype in subtypes])] + self.members = members + self.as_json = [u'tuple', dict(members=[subtype.as_json for subtype in members])] def __repr__(self): - return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.subtypes]) + return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.members]) def validate(self, value): """return the validated value or raise""" # keep the ordering! try: - if len(value) != len(self.subtypes): + if len(value) != len(self.members): raise ValueError( u'Illegal number of Arguments! Need %d arguments.' % - (len(self.subtypes))) + (len(self.members))) # validate elements and return as list return [sub.validate(elem) - for sub, elem in zip(self.subtypes, value)] + for sub, elem in zip(self.members, value)] except Exception as exc: raise ValueError(u'Can not validate:', unicode(exc)) def export_value(self, value): """returns a python object fit for serialisation""" - return [sub.export_value(elem) for sub, elem in zip(self.subtypes, value)] + return [sub.export_value(elem) for sub, elem in zip(self.members, value)] def import_value(self, value): """returns a python object from serialisation""" - return [sub.import_value(elem) for sub, elem in zip(self.subtypes, value)] + return [sub.import_value(elem) for sub, elem in zip(self.members, value)] def from_string(self, text): value, rem = Parser.parse(text) @@ -587,11 +638,15 @@ class TupleOf(DataType): raise ProtocolError(u'trailing garbage: %r' % rem) return self.validate(value) + def format_value(self, value, unit=None): + return u'(%s)' % (', '.join([sub.format_value(elem) + for sub, elem in zip(self.members, value)])) + class StructOf(DataType): def __init__(self, optional=None, **members): - self.named_subtypes = members + self.members = members if not members: raise ValueError(u'Empty structs are not allowed!') self.optional = list(optional or []) @@ -614,37 +669,38 @@ class StructOf(DataType): def __repr__(self): return u'StructOf(%s)' % u', '.join( - [u'%s=%s' % (n, repr(st)) for n, st in list(self.named_subtypes.items())]) + [u'%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]) def validate(self, value): """return the validated value or raise""" try: - if len(list(value.keys())) != len(list(self.named_subtypes.keys())): + # XXX: handle optional elements !!! + if len(list(value.keys())) != len(list(self.members.keys())): raise ValueError( u'Illegal number of Arguments! Need %d arguments.' % - len(list(self.named_subtypes.keys()))) + len(list(self.members.keys()))) # validate elements and return as dict - return dict((unicode(k), self.named_subtypes[k].validate(v)) + return dict((unicode(k), self.members[k].validate(v)) for k, v in list(value.items())) except Exception as exc: raise ValueError(u'Can not validate %s: %s' % (repr(value), unicode(exc))) def export_value(self, value): """returns a python object fit for serialisation""" - if len(list(value.keys())) != len(list(self.named_subtypes.keys())): + if len(list(value.keys())) != len(list(self.members.keys())): raise ValueError( u'Illegal number of Arguments! Need %d arguments.' % len( - list(self.namd_subtypes.keys()))) - return dict((unicode(k), self.named_subtypes[k].export_value(v)) + list(self.members.keys()))) + return dict((unicode(k), self.members[k].export_value(v)) for k, v in list(value.items())) def import_value(self, value): """returns a python object from serialisation""" - if len(list(value.keys())) != len(list(self.named_subtypes.keys())): + if len(list(value.keys())) != len(list(self.members.keys())): raise ValueError( u'Illegal number of Arguments! Need %d arguments.' % len( - list(self.namd_subtypes.keys()))) - return dict((unicode(k), self.named_subtypes[k].import_value(v)) + list(self.members.keys()))) + return dict((unicode(k), self.members[k].import_value(v)) for k, v in list(value.items())) def from_string(self, text): @@ -653,6 +709,9 @@ class StructOf(DataType): raise ProtocolError(u'trailing garbage: %r' % rem) return self.validate(dict(value)) + def format_value(self, value, unit=None): + return u'{%s}' % (', '.join(['%s=%s' % (k, self.members[k].format_value(v)) for k, v in sorted(value.items())])) + class CommandType(DataType): IS_COMMAND = True @@ -697,6 +756,10 @@ class CommandType(DataType): raise ProtocolError(u'trailing garbage: %r' % rem) return self.validate(value) + def format_value(self, value, unit=None): + # actually I have no idea what to do here! + raise NotImplementedError + # Goodie: Convenience Datatypes for Programming class LimitsType(StructOf): diff --git a/test/test_datatypes.py b/test/test_datatypes.py index 97a79bb..ac9aacf 100644 --- a/test/test_datatypes.py +++ b/test/test_datatypes.py @@ -33,7 +33,7 @@ from secop.datatypes import ArrayOf, BLOBType, BoolType, \ def test_DataType(): dt = DataType() - assert dt.as_json == ['undefined'] + assert dt.as_json == [u'undefined'] with pytest.raises(NotImplementedError): dt = DataType() @@ -44,77 +44,83 @@ def test_DataType(): def test_FloatRange(): dt = FloatRange(-3.14, 3.14) - assert dt.as_json == ['double', {'min':-3.14, 'max':3.14}] + assert dt.as_json == [u'double', {u'min':-3.14, u'max':3.14}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): dt.validate(-9) with pytest.raises(ValueError): - dt.validate('XX') + dt.validate(u'XX') with pytest.raises(ValueError): - dt.validate([19, 'X']) + dt.validate([19, u'X']) dt.validate(1) dt.validate(0) assert dt.export_value(-2.718) == -2.718 assert dt.import_value(-2.718) == -2.718 with pytest.raises(ValueError): - FloatRange('x', 'Y') + FloatRange(u'x', u'Y') dt = FloatRange() - assert dt.as_json == ['double', {}] + assert dt.as_json == [u'double', {}] - dt = FloatRange(unit='X', fmtstr='%r', absolute_precision=1, + dt = FloatRange(unit=u'X', fmtstr=u'%r', absolute_precision=1, relative_precision=0.1) - assert dt.as_json == ['double', {'unit':'X', 'fmtstr':'%r', - 'absolute_precision':1, - 'relative_precision':0.1}] + assert dt.as_json == [u'double', {u'unit':u'X', u'fmtstr':u'%r', + u'absolute_precision':1, + u'relative_precision':0.1}] assert dt.validate(4) == 4 + assert dt.format_value(3.14) == u'3.14 X' + assert dt.format_value(3.14, u'') == u'3.14' + assert dt.format_value(3.14, u'#') == u'3.14 #' def test_IntRange(): dt = IntRange(-3, 3) - assert dt.as_json == ['int', {'min':-3, 'max':3}] + assert dt.as_json == [u'int', {u'min':-3, u'max':3}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): dt.validate(-9) with pytest.raises(ValueError): - dt.validate('XX') + dt.validate(u'XX') with pytest.raises(ValueError): - dt.validate([19, 'X']) + dt.validate([19, u'X']) dt.validate(1) dt.validate(0) with pytest.raises(ValueError): - IntRange('xc', 'Yx') + IntRange(u'xc', u'Yx') dt = IntRange() - assert dt.as_json[0] == 'int' - assert dt.as_json[1]['min'] < 0 < dt.as_json[1]['max'] + assert dt.as_json[0] == u'int' + assert dt.as_json[1][u'min'] < 0 < dt.as_json[1][u'max'] - dt = IntRange(unit='X', fmtstr='%r') - assert dt.as_json == ['int', {'fmtstr': '%r', 'max': 16777216, - 'min': -16777216, 'unit': 'X'}] + dt = IntRange(unit=u'X', fmtstr=u'%r') + assert dt.as_json == [u'int', {u'fmtstr': u'%r', u'max': 16777216, + u'min': -16777216, u'unit': u'X'}] + assert dt.format_value(42) == u'42 X' + assert dt.format_value(42, u'') == u'42' + assert dt.format_value(42, u'Z') == u'42 Z' def test_ScaledInteger(): dt = ScaledInteger(0.01, -3, 3) # serialisation of datatype contains limits on the 'integer' value - assert dt.as_json == ['scaled', {'scale':0.01, 'min':-300, 'max':300}] + assert dt.as_json == [u'scaled', {u'scale':0.01, u'min':-300, u'max':300}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): dt.validate(-9) with pytest.raises(ValueError): - dt.validate('XX') + dt.validate(u'XX') with pytest.raises(ValueError): - dt.validate([19, 'X']) + dt.validate([19, u'X']) dt.validate(1) dt.validate(0) with pytest.raises(ValueError): - ScaledInteger('xc', 'Yx') + ScaledInteger(u'xc', u'Yx') with pytest.raises(ValueError): ScaledInteger(scale=0, minval=1, maxval=2) with pytest.raises(ValueError): @@ -124,13 +130,16 @@ def test_ScaledInteger(): assert dt.export_value(2.71819) == int(272) assert dt.import_value(272) == 2.72 - dt = ScaledInteger(0.003, 0, 1, unit='X', fmtstr='%r', + dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%r', absolute_precision=1, relative_precision=0.1) - assert dt.as_json == ['scaled', {'scale':0.003,'min':0,'max':333, - 'unit':'X', 'fmtstr':'%r', - 'absolute_precision':1, - 'relative_precision':0.1}] + assert dt.as_json == [u'scaled', {u'scale':0.003,u'min':0,u'max':333, + u'unit':u'X', u'fmtstr':u'%r', + u'absolute_precision':1, + u'relative_precision':0.1}] assert dt.validate(0.4) == 0.399 + assert dt.format_value(0.4) == u'0.4 X' + assert dt.format_value(0.4, u'') == u'0.4' + assert dt.format_value(0.4, u'Z') == u'0.4 Z' def test_EnumType(): @@ -138,79 +147,84 @@ def test_EnumType(): with pytest.raises(TypeError): EnumType(1) with pytest.raises(TypeError): - EnumType(['b', 0]) + EnumType([u'b', 0]) - dt = EnumType('dt', a=3, c=7, stuff=1) - assert dt.as_json == ['enum', dict(members=dict(a=3, c=7, stuff=1))] + dt = EnumType(u'dt', a=3, c=7, stuff=1) + assert dt.as_json == [u'enum', dict(members=dict(a=3, c=7, stuff=1))] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): dt.validate(-9) with pytest.raises(ValueError): - dt.validate('XX') + dt.validate(u'XX') with pytest.raises(TypeError): - dt.validate([19, 'X']) + dt.validate([19, u'X']) - assert dt.validate('a') == 3 - assert dt.validate('stuff') == 1 + assert dt.validate(u'a') == 3 + assert dt.validate(u'stuff') == 1 assert dt.validate(1) == 1 with pytest.raises(ValueError): dt.validate(2) - assert dt.export_value('c') == 7 - assert dt.export_value('stuff') == 1 + assert dt.export_value(u'c') == 7 + assert dt.export_value(u'stuff') == 1 assert dt.export_value(1) == 1 - assert dt.import_value('c') == 7 - assert dt.import_value('a') == 3 - assert dt.import_value('stuff') == 1 + assert dt.import_value(u'c') == 7 + assert dt.import_value(u'a') == 3 + assert dt.import_value(u'stuff') == 1 with pytest.raises(ValueError): dt.export_value(2) with pytest.raises(ValueError): - dt.import_value('A') + dt.import_value(u'A') + + assert dt.format_value(3) == u'a<3>' def test_BLOBType(): # test constructor catching illegal arguments dt = BLOBType() - assert dt.as_json == ['blob', {'min':0, 'max':255}] + assert dt.as_json == [u'blob', {u'min':0, u'max':255}] dt = BLOBType(10) - assert dt.as_json == ['blob', {'min':10, 'max':10}] + assert dt.as_json == [u'blob', {u'min':10, u'max':10}] dt = BLOBType(3, 10) - assert dt.as_json == ['blob', {'min':3, 'max':10}] + assert dt.as_json == [u'blob', {u'min':3, u'max':10}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): - dt.validate('av') + dt.validate(u'av') with pytest.raises(ValueError): - dt.validate('abcdefghijklmno') + dt.validate(u'abcdefghijklmno') assert dt.validate('abcd') == b'abcd' assert dt.validate(b'abcd') == b'abcd' assert dt.validate(u'abcd') == b'abcd' - assert dt.export_value('abcd') == 'YWJjZA==' - assert dt.export_value(b'abcd') == 'YWJjZA==' - assert dt.export_value(u'abcd') == 'YWJjZA==' - assert dt.import_value('YWJjZA==') == 'abcd' + assert dt.export_value('abcd') == u'YWJjZA==' + assert dt.export_value(b'abcd') == u'YWJjZA==' + assert dt.export_value(u'abcd') == u'YWJjZA==' + assert dt.import_value(u'YWJjZA==') == b'abcd' + + # XXX: right? or different format? + assert dt.format_value(b'ab\0cd') == '\'ab\\x00cd\'' def test_StringType(): # test constructor catching illegal arguments dt = StringType() dt = StringType(12) - assert dt.as_json == ['string', {'min':12, 'max':12}] + assert dt.as_json == [u'string', {u'min':12, u'max':12}] dt = StringType(4, 11) - assert dt.as_json == ['string', {'min':4, 'max':11}] + assert dt.as_json == [u'string', {u'min':4, u'max':11}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): - dt.validate('av') + dt.validate(u'av') with pytest.raises(ValueError): - dt.validate('abcdefghijklmno') + dt.validate(u'abcdefghijklmno') with pytest.raises(ValueError): dt.validate('abcdefg\0') assert dt.validate('abcd') == b'abcd' @@ -220,31 +234,36 @@ def test_StringType(): assert dt.export_value('abcd') == b'abcd' assert dt.export_value(b'abcd') == b'abcd' assert dt.export_value(u'abcd') == b'abcd' - assert dt.import_value(u'abcd') == 'abcd' + assert dt.import_value(u'abcd') == u'abcd' + + assert dt.format_value(u'abcd') == u"u'abcd'" def test_BoolType(): # test constructor catching illegal arguments dt = BoolType() - assert dt.as_json == ['bool', {}] + assert dt.as_json == [u'bool', {}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): - dt.validate('av') + dt.validate(u'av') - assert dt.validate('true') is True - assert dt.validate('off') is False + assert dt.validate(u'true') is True + assert dt.validate(u'off') is False assert dt.validate(1) is True - assert dt.export_value('false') is False + assert dt.export_value(u'false') is False assert dt.export_value(0) is False - assert dt.export_value('on') is True + assert dt.export_value(u'on') is True assert dt.import_value(False) is False assert dt.import_value(True) is True with pytest.raises(ValueError): - dt.import_value('av') + dt.import_value(u'av') + + assert dt.format_value(0) == u"False" + assert dt.format_value(True) == u"True" def test_ArrayOf(): @@ -254,31 +273,40 @@ def test_ArrayOf(): with pytest.raises(ValueError): ArrayOf(-3, IntRange(-10,10)) dt = ArrayOf(IntRange(-10, 10), 5) - assert dt.as_json == ['array', {'min':5, 'max':5, - 'members':['int', {'min':-10, 'max':10}]}] + assert dt.as_json == [u'array', {u'min':5, u'max':5, + u'members':[u'int', {u'min':-10, + u'max':10}]}] - dt = ArrayOf(IntRange(-10, 10), 1, 3) - assert dt.as_json == ['array', {'min':1, 'max':3, - 'members':['int', {'min':-10, 'max':10}]}] + dt = ArrayOf(IntRange(-10, 10, unit=u'Z'), 1, 3) + assert dt.as_json == [u'array', {u'min':1, u'max':3, + u'members':[u'int', {u'min':-10, + u'max':10, + u'unit':u'Z'}]}] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): - dt.validate('av') + dt.validate(u'av') assert dt.validate([1, 2, 3]) == [1, 2, 3] assert dt.export_value([1, 2, 3]) == [1, 2, 3] assert dt.import_value([1, 2, 3]) == [1, 2, 3] + assert dt.format_value([1,2,3]) == u'[1, 2, 3] Z' + assert dt.format_value([1,2,3], u'') == u'[1, 2, 3]' + assert dt.format_value([1,2,3], u'Q') == u'[1, 2, 3] Q' + def test_TupleOf(): # test constructor catching illegal arguments with pytest.raises(ValueError): TupleOf(2) - dt = TupleOf(IntRange(-10, 10), BoolType()) - assert dt.as_json == ['tuple', {'members':[['int', {'min':-10, 'max':10}], - ['bool', {}]]}] + dt = TupleOf(IntRange(-10, 10, unit=u'X'), BoolType()) + assert dt.as_json == [u'tuple', {u'members':[[u'int', {u'min':-10, + u'max':10, + u'unit':u'X'}], + [u'bool', {}]]}] with pytest.raises(ValueError): dt.validate(9) @@ -290,6 +318,8 @@ def test_TupleOf(): assert dt.export_value([1, True]) == [1, True] assert dt.import_value([1, True]) == [1, True] + assert dt.format_value([3,0]) == u"(3 X, False)" + def test_StructOf(): # test constructor catching illegal arguments @@ -298,28 +328,31 @@ def test_StructOf(): with pytest.raises(ProgrammingError): StructOf(IntRange=1) - dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999), - optional=['an_int']) - assert dt.as_json == [u'struct', {'members':{u'a_string': - [u'string', {'min':0, 'max':55}], - u'an_int': - [u'int', {'min':0, 'max':999}],}, - 'optional':['an_int'], + dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999, unit=u'Y'), + optional=[u'an_int']) + assert dt.as_json == [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, + u'unit':u'Y'}],}, + u'optional':[u'an_int'], }] with pytest.raises(ValueError): dt.validate(9) with pytest.raises(ValueError): - dt.validate([99, 'X']) + dt.validate([99, u'X']) with pytest.raises(ValueError): - dt.validate(dict(a_string='XXX', an_int=1811)) + dt.validate(dict(a_string=u'XXX', an_int=1811)) - assert dt.validate(dict(a_string='XXX', an_int=8)) == {'a_string': 'XXX', - 'an_int': 8} - assert dt.export_value({'an_int': 13, 'a_string': 'WFEC'}) == { - 'a_string': 'WFEC', 'an_int': 13} - assert dt.import_value({'an_int': 13, 'a_string': 'WFEC'}) == { - 'a_string': 'WFEC', 'an_int': 13} + assert dt.validate(dict(a_string=u'XXX', an_int=8)) == {u'a_string': u'XXX', + u'an_int': 8} + assert dt.export_value({u'an_int': 13, u'a_string': u'WFEC'}) == { + u'a_string': u'WFEC', u'an_int': 13} + assert dt.import_value({u'an_int': 13, u'a_string': u'WFEC'}) == { + u'a_string': u'WFEC', u'an_int': 13} + + assert dt.format_value({u'an_int':2, u'a_string':u'Z'}) == u"{a_string=u'Z', an_int=2 Y}" def test_get_datatype(): @@ -330,148 +363,148 @@ def test_get_datatype(): with pytest.raises(ValueError): get_datatype(str) with pytest.raises(ValueError): - get_datatype(['undefined']) + get_datatype([u'undefined']) - assert isinstance(get_datatype(['bool', {}]), BoolType) + assert isinstance(get_datatype([u'bool', {}]), BoolType) with pytest.raises(ValueError): - get_datatype(['bool']) + get_datatype([u'bool']) with pytest.raises(ValueError): - get_datatype(['bool', 3]) + get_datatype([u'bool', 3]) with pytest.raises(ValueError): - get_datatype(['int', {'min':-10}]) + get_datatype([u'int', {u'min':-10}]) with pytest.raises(ValueError): - get_datatype(['int', {'max':10}]) - assert isinstance(get_datatype(['int', {'min':-10, 'max':10}]), IntRange) + get_datatype([u'int', {u'max':10}]) + assert isinstance(get_datatype([u'int', {u'min':-10, u'max':10}]), IntRange) with pytest.raises(ValueError): - get_datatype(['int', {'min':10, 'max':-10}]) + get_datatype([u'int', {u'min':10, u'max':-10}]) with pytest.raises(ValueError): - get_datatype(['int']) + get_datatype([u'int']) with pytest.raises(ValueError): - get_datatype(['int', {}]) + get_datatype([u'int', {}]) with pytest.raises(ValueError): - get_datatype(['int', 1, 2]) + get_datatype([u'int', 1, 2]) - assert isinstance(get_datatype(['double', {}]), FloatRange) - assert isinstance(get_datatype(['double', {'min':-2.718}]), FloatRange) - assert isinstance(get_datatype(['double', {'max':3.14}]), FloatRange) - assert isinstance(get_datatype(['double', {'min':-9.9, 'max':11.1}]), + assert isinstance(get_datatype([u'double', {}]), FloatRange) + assert isinstance(get_datatype([u'double', {u'min':-2.718}]), FloatRange) + assert isinstance(get_datatype([u'double', {u'max':3.14}]), FloatRange) + assert isinstance(get_datatype([u'double', {u'min':-9.9, u'max':11.1}]), FloatRange) with pytest.raises(ValueError): - get_datatype(['double']) + get_datatype([u'double']) with pytest.raises(ValueError): - get_datatype(['double', {'min':10, 'max':-10}]) + get_datatype([u'double', {u'min':10, u'max':-10}]) with pytest.raises(ValueError): - get_datatype(['double', 1, 2]) + get_datatype([u'double', 1, 2]) with pytest.raises(ValueError): - get_datatype(['scaled', {'scale':0.01,'min':-2.718}]) + get_datatype([u'scaled', {u'scale':0.01,u'min':-2.718}]) with pytest.raises(ValueError): - get_datatype(['scaled', {'scale':0.02,'max':3.14}]) - assert isinstance(get_datatype(['scaled', {'scale':0.03, - 'min':-99, - 'max':111}]), ScaledInteger) + get_datatype([u'scaled', {u'scale':0.02,u'max':3.14}]) + assert isinstance(get_datatype([u'scaled', {u'scale':0.03, + u'min':-99, + u'max':111}]), ScaledInteger) dt = ScaledInteger(scale=0.03, minval=0, maxval=9.9) - assert dt.as_json == ['scaled', {'max':330, 'min':0, 'scale':0.03}] + 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 with pytest.raises(ValueError): - get_datatype(['scaled']) # dict missing + get_datatype([u'scaled']) # dict missing with pytest.raises(ValueError): - get_datatype(['scaled', {'min':-10, 'max':10}]) # no scale + get_datatype([u'scaled', {u'min':-10, u'max':10}]) # no scale with pytest.raises(ValueError): - get_datatype(['scaled', {'min':10, 'max':-10}]) # limits reversed + get_datatype([u'scaled', {u'min':10, u'max':-10}]) # limits reversed with pytest.raises(ValueError): - get_datatype(['scaled', {}, 1, 2]) # trailing data + get_datatype([u'scaled', {}, 1, 2]) # trailing data with pytest.raises(ValueError): - get_datatype(['enum']) + get_datatype([u'enum']) with pytest.raises(ValueError): - get_datatype(['enum', dict(a=-2)]) - assert isinstance(get_datatype(['enum', {'members':dict(a=-2)}]), EnumType) + get_datatype([u'enum', dict(a=-2)]) + assert isinstance(get_datatype([u'enum', {u'members':dict(a=-2)}]), EnumType) with pytest.raises(ValueError): - get_datatype(['enum', 10, -10]) + get_datatype([u'enum', 10, -10]) with pytest.raises(ValueError): - get_datatype(['enum', [1, 2, 3]]) + get_datatype([u'enum', [1, 2, 3]]) - assert isinstance(get_datatype(['blob', {'max':1}]), BLOBType) - assert isinstance(get_datatype(['blob', {'min':1, 'max':10}]), BLOBType) + assert isinstance(get_datatype([u'blob', {u'max':1}]), BLOBType) + assert isinstance(get_datatype([u'blob', {u'min':1, u'max':10}]), BLOBType) with pytest.raises(ValueError): - get_datatype(['blob', {'min':10, 'max':1}]) + get_datatype([u'blob', {u'min':10, u'max':1}]) with pytest.raises(ValueError): - get_datatype(['blob', {'min':10, 'max':-10}]) + get_datatype([u'blob', {u'min':10, u'max':-10}]) with pytest.raises(ValueError): - get_datatype(['blob', 10, -10, 1]) + get_datatype([u'blob', 10, -10, 1]) with pytest.raises(ValueError): - get_datatype(['string']) - assert isinstance(get_datatype(['string', {'min':1}]), StringType) - assert isinstance(get_datatype(['string', {'min':1, 'max':10}]), StringType) + get_datatype([u'string']) + assert isinstance(get_datatype([u'string', {u'min':1}]), StringType) + assert isinstance(get_datatype([u'string', {u'min':1, u'max':10}]), StringType) with pytest.raises(ValueError): - get_datatype(['string', {'min':10, 'max':1}]) + get_datatype([u'string', {u'min':10, u'max':1}]) with pytest.raises(ValueError): - get_datatype(['string', {'min':10, 'max':-10}]) + get_datatype([u'string', {u'min':10, u'max':-10}]) with pytest.raises(ValueError): - get_datatype(['string', 10, -10, 1]) + get_datatype([u'string', 10, -10, 1]) with pytest.raises(ValueError): - get_datatype(['array']) + get_datatype([u'array']) with pytest.raises(ValueError): - get_datatype(['array', 1]) + get_datatype([u'array', 1]) with pytest.raises(ValueError): - get_datatype(['array', [1], 2, 3]) - assert isinstance(get_datatype(['array', {'min':1, 'max':1, - 'members':['blob', {'max':1}]}] + get_datatype([u'array', [1], 2, 3]) + assert isinstance(get_datatype([u'array', {u'min':1, u'max':1, + u'members':[u'blob', {u'max':1}]}] ), ArrayOf) - assert isinstance(get_datatype(['array', {'min':1, 'max':1, - 'members':['blob', {'max':1}]}] - ).subtype, BLOBType) + assert isinstance(get_datatype([u'array', {u'min':1, u'max':1, + u'members':[u'blob', {u'max':1}]}] + ).members, BLOBType) with pytest.raises(ValueError): - get_datatype(['array', {'members':['blob', {'max':1}], 'min':-10}]) + get_datatype([u'array', {u'members':[u'blob', {u'max':1}], u'min':-10}]) with pytest.raises(ValueError): - get_datatype(['array', {'members':['blob', {'max':1}], - 'min':10, 'max':1}]) + get_datatype([u'array', {u'members':[u'blob', {u'max':1}], + u'min':10, 'max':1}]) with pytest.raises(ValueError): - get_datatype(['array', ['blob', 1], 10, -10]) + get_datatype([u'array', [u'blob', 1], 10, -10]) with pytest.raises(ValueError): - get_datatype(['tuple']) + get_datatype([u'tuple']) with pytest.raises(ValueError): - get_datatype(['tuple', 1]) + get_datatype([u'tuple', 1]) with pytest.raises(ValueError): - get_datatype(['tuple', [1], 2, 3]) - assert isinstance(get_datatype(['tuple', {'members':[['blob', - {'max':1}]]}]), TupleOf) - assert isinstance(get_datatype(['tuple', {'members':[['blob', - {'max':1}]]}]).subtypes[0], BLOBType) + get_datatype([u'tuple', [1], 2, 3]) + assert isinstance(get_datatype([u'tuple', {u'members':[[u'blob', + {u'max':1}]]}]), TupleOf) + assert isinstance(get_datatype([u'tuple', {u'members':[[u'blob', + {u'max':1}]]}]).members[0], BLOBType) with pytest.raises(ValueError): - get_datatype(['tuple', {}]) + get_datatype([u'tuple', {}]) with pytest.raises(ValueError): - get_datatype(['tuple', 10, -10]) + get_datatype([u'tuple', 10, -10]) - assert isinstance(get_datatype(['tuple', {'members':[['blob', {'max':1}], - ['bool',{}]]}]), TupleOf) + assert isinstance(get_datatype([u'tuple', {u'members':[[u'blob', {u'max':1}], + [u'bool',{}]]}]), TupleOf) with pytest.raises(ValueError): - get_datatype(['struct']) + get_datatype([u'struct']) with pytest.raises(ValueError): - get_datatype(['struct', 1]) + get_datatype([u'struct', 1]) with pytest.raises(ValueError): - get_datatype(['struct', [1], 2, 3]) - assert isinstance(get_datatype(['struct', {'members': - {'name': ['blob', {'max':1}]}}]), StructOf) - assert isinstance(get_datatype(['struct', {'members': - {'name': ['blob', {'max':1}]}}]).named_subtypes['name'], BLOBType) + get_datatype([u'struct', [1], 2, 3]) + assert isinstance(get_datatype([u'struct', {u'members': + {u'name': [u'blob', {u'max':1}]}}]), StructOf) + assert isinstance(get_datatype([u'struct', {u'members': + {u'name': [u'blob', {u'max':1}]}}]).members[u'name'], BLOBType) with pytest.raises(ValueError): - get_datatype(['struct', {}]) + get_datatype([u'struct', {}]) with pytest.raises(ValueError): - get_datatype(['struct', {'members':[1,2,3]}]) + get_datatype([u'struct', {u'members':[1,2,3]}])