change again SECoP datatype syntax
- change from single element JSON-object to flattened JSON-object with 'type' key. - rename of some data properties (maxbytes, maxchars, maxlen) - added isUTF8 to StringType The rename of the SECoP property 'datatype' to 'datainfo' will follow in an other change. Change-Id: I7a75f0d025ff476dd19385db3487f18c4c746bcf Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/21293 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
6acc82d808
commit
596353e09a
@ -97,13 +97,24 @@ class DataType(object):
|
|||||||
if unit is given, use it, else use the unit of the datatype (if any)"""
|
if unit is given, use it, else use the unit of the datatype (if any)"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def setprop(self, key, value, default, func=lambda x:x):
|
def set_prop(self, key, value, default, func=lambda x:x):
|
||||||
"""set a datatype property and store the default"""
|
"""set an optional datatype property and store the default"""
|
||||||
self._defaults[key] = default
|
self._defaults[key] = default
|
||||||
if value is None:
|
if value is None:
|
||||||
value = default
|
value = default
|
||||||
setattr(self, key, func(value))
|
setattr(self, key, func(value))
|
||||||
|
|
||||||
|
def get_info(self, **kwds):
|
||||||
|
"""prepare dict for export or repr
|
||||||
|
|
||||||
|
get a dict with all items different from default
|
||||||
|
plus mandatory keys from kwds"""
|
||||||
|
for k,v in self._defaults.items():
|
||||||
|
value = getattr(self, k)
|
||||||
|
if value != v:
|
||||||
|
kwds[k] = value
|
||||||
|
return kwds
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""make a deep copy of the datatype"""
|
"""make a deep copy of the datatype"""
|
||||||
|
|
||||||
@ -118,12 +129,12 @@ class FloatRange(DataType):
|
|||||||
absolute_resolution=None, relative_resolution=None,):
|
absolute_resolution=None, relative_resolution=None,):
|
||||||
self.default = 0 if minval <= 0 <= maxval else minval
|
self.default = 0 if minval <= 0 <= maxval else minval
|
||||||
self._defaults = {}
|
self._defaults = {}
|
||||||
self.setprop('min', minval, float(u'-inf'), float)
|
self.set_prop('min', minval, float(u'-inf'), float)
|
||||||
self.setprop('max', maxval, float(u'+inf'), float)
|
self.set_prop('max', maxval, float(u'+inf'), float)
|
||||||
self.setprop('unit', unit, u'', unicode)
|
self.set_prop('unit', unit, u'', unicode)
|
||||||
self.setprop('fmtstr', fmtstr, u'%g', unicode)
|
self.set_prop('fmtstr', fmtstr, u'%g', unicode)
|
||||||
self.setprop('absolute_resolution', absolute_resolution, 0.0, float)
|
self.set_prop('absolute_resolution', absolute_resolution, 0.0, float)
|
||||||
self.setprop('relative_resolution', relative_resolution, 1.2e-7, float)
|
self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float)
|
||||||
|
|
||||||
# check values
|
# check values
|
||||||
if self.min > self.max:
|
if self.min > self.max:
|
||||||
@ -136,8 +147,7 @@ class FloatRange(DataType):
|
|||||||
raise BadValueError(u'relative_resolution MUST be >=0')
|
raise BadValueError(u'relative_resolution MUST be >=0')
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'double': {k: getattr(self, k) for k, v in self._defaults.items()
|
return self.get_info(type='double')
|
||||||
if v != getattr(self, k)}}
|
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
try:
|
try:
|
||||||
@ -151,8 +161,12 @@ class FloatRange(DataType):
|
|||||||
(value, self.min, self.max))
|
(value, self.min, self.max))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
items = [u'%s=%r' % (k,v) for k,v in self.export_datatype()['double'].items()]
|
hints = self.get_info()
|
||||||
return u'FloatRange(%s)' % (', '.join(items))
|
if 'min' in hints:
|
||||||
|
hints['minval'] = hints.pop('min')
|
||||||
|
if 'max' in hints:
|
||||||
|
hints['maxval'] = hints.pop('max')
|
||||||
|
return u'FloatRange(%s)' % (', '.join('%s=%r' % (k,v) for k,v in hints.items()))
|
||||||
|
|
||||||
def export_value(self, value):
|
def export_value(self, value):
|
||||||
"""returns a python object fit for serialisation"""
|
"""returns a python object fit for serialisation"""
|
||||||
@ -181,13 +195,15 @@ class IntRange(DataType):
|
|||||||
self.min = DEFAULT_MIN_INT if minval is None else int(minval)
|
self.min = DEFAULT_MIN_INT if minval is None else int(minval)
|
||||||
self.max = DEFAULT_MAX_INT if maxval is None else int(maxval)
|
self.max = DEFAULT_MAX_INT if maxval is None else int(maxval)
|
||||||
self.default = 0 if minval <= 0 <= maxval else minval
|
self.default = 0 if minval <= 0 <= maxval else minval
|
||||||
|
# a unit on an int is now allowed in SECoP, but do we need them in Frappy?
|
||||||
|
# self.set_prop('unit', unit, u'', unicode)
|
||||||
|
|
||||||
# check values
|
# check values
|
||||||
if self.min > self.max:
|
if self.min > self.max:
|
||||||
raise BadValueError(u'Max must be larger then min!')
|
raise BadValueError(u'Max must be larger then min!')
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'int': {"min": self.min, "max": self.max}}
|
return dict(type='int', min=self.min, max=self.max)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
try:
|
try:
|
||||||
@ -234,10 +250,10 @@ class ScaledInteger(DataType):
|
|||||||
self.scale = float(scale)
|
self.scale = float(scale)
|
||||||
if not self.scale > 0:
|
if not self.scale > 0:
|
||||||
raise BadValueError(u'Scale MUST be positive!')
|
raise BadValueError(u'Scale MUST be positive!')
|
||||||
self.setprop('unit', unit, u'', unicode)
|
self.set_prop('unit', unit, u'', unicode)
|
||||||
self.setprop('fmtstr', fmtstr, u'%g', unicode)
|
self.set_prop('fmtstr', fmtstr, u'%g', unicode)
|
||||||
self.setprop('absolute_resolution', absolute_resolution, self.scale, float)
|
self.set_prop('absolute_resolution', absolute_resolution, self.scale, float)
|
||||||
self.setprop('relative_resolution', relative_resolution, 1.2e-7, float)
|
self.set_prop('relative_resolution', relative_resolution, 1.2e-7, float)
|
||||||
|
|
||||||
self.min = DEFAULT_MIN_INT * self.scale if minval is None else float(minval)
|
self.min = DEFAULT_MIN_INT * self.scale if minval is None else float(minval)
|
||||||
self.max = DEFAULT_MAX_INT * self.scale if maxval is None else float(maxval)
|
self.max = DEFAULT_MAX_INT * self.scale if maxval is None else float(maxval)
|
||||||
@ -255,12 +271,9 @@ class ScaledInteger(DataType):
|
|||||||
# this should be o.k.
|
# this should be o.k.
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
info = {k: getattr(self, k) for k, v in self._defaults.items()
|
return self.get_info(type='scaled', scale=self.scale,
|
||||||
if v != getattr(self, k)}
|
min = int((self.min + self.scale * 0.5) // self.scale),
|
||||||
info['scale'] = self.scale
|
max = int((self.max + self.scale * 0.5) // self.scale))
|
||||||
info['min'] = int((self.min + self.scale * 0.5) // self.scale)
|
|
||||||
info['max'] = int((self.max + self.scale * 0.5) // self.scale)
|
|
||||||
return {u'scaled': info}
|
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
try:
|
try:
|
||||||
@ -279,12 +292,10 @@ class ScaledInteger(DataType):
|
|||||||
return value # return 'actual' value (which is more discrete than a float)
|
return value # return 'actual' value (which is more discrete than a float)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
hints = self.export_datatype()['scaled']
|
hints = self.get_info(scale='%g' % self.scale,
|
||||||
hints.pop('scale')
|
min = int((self.min + self.scale * 0.5) // self.scale),
|
||||||
items = ['%g' % self.scale]
|
max = int((self.max + self.scale * 0.5) // self.scale))
|
||||||
for k,v in hints.items():
|
return u'ScaledInteger(%s)' % (', '.join('%s=%r' % kv for kv in hints.items()))
|
||||||
items.append(u'%s=%r' % (k,v))
|
|
||||||
return u'ScaledInteger(%s)' % (', '.join(items))
|
|
||||||
|
|
||||||
def export_value(self, value):
|
def export_value(self, value):
|
||||||
"""returns a python object fit for serialisation"""
|
"""returns a python object fit for serialisation"""
|
||||||
@ -322,7 +333,7 @@ class EnumType(DataType):
|
|||||||
return EnumType(self._enum)
|
return EnumType(self._enum)
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'enum': {u"members":dict((m.name, m.value) for m in self._enum.members)}}
|
return {'type': 'enum', 'members':dict((m.name, m.value) for m in self._enum.members)}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u"EnumType(%r, %s)" % (self._enum.name, ', '.join(u'%s=%d' %(m.name, m.value) for m in self._enum.members))
|
return u"EnumType(%r, %s)" % (self._enum.name, ', '.join(u'%s=%d' %(m.name, m.value) for m in self._enum.members))
|
||||||
@ -350,39 +361,40 @@ class EnumType(DataType):
|
|||||||
|
|
||||||
|
|
||||||
class BLOBType(DataType):
|
class BLOBType(DataType):
|
||||||
minsize = None
|
minbytes = None
|
||||||
maxsize = None
|
maxbytes = None
|
||||||
|
|
||||||
def __init__(self, minsize=0, maxsize=None):
|
def __init__(self, minbytes=0, maxbytes=None):
|
||||||
# if only one argument is given, use exactly that many bytes
|
# if only one argument is given, use exactly that many bytes
|
||||||
# if nothing is given, default to 255
|
# if nothing is given, default to 255
|
||||||
if maxsize is None:
|
if maxbytes is None:
|
||||||
maxsize = minsize or 255
|
maxbytes = minbytes or 255
|
||||||
self.minsize = int(minsize)
|
self._defaults = {}
|
||||||
self.maxsize = int(maxsize)
|
self.set_prop('minbytes', minbytes, 0, int)
|
||||||
if self.minsize < 0:
|
self.maxbytes = int(maxbytes)
|
||||||
|
if self.minbytes < 0:
|
||||||
raise BadValueError(u'sizes must be bigger than or equal to 0!')
|
raise BadValueError(u'sizes must be bigger than or equal to 0!')
|
||||||
elif self.minsize > self.maxsize:
|
elif self.minbytes > self.maxbytes:
|
||||||
raise BadValueError(u'maxsize must be bigger than or equal to minsize!')
|
raise BadValueError(u'maxbytes must be bigger than or equal to minbytes!')
|
||||||
self.default = b'\0' * self.minsize
|
self.default = b'\0' * self.minbytes
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'blob': dict(min=self.minsize, max=self.maxsize)}
|
return self.get_info(type='blob', maxbytes=self.maxbytes)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'BLOB(%d, %d)' % (self.minsize, self.maxsize)
|
return u'BLOBType(%d, %d)' % (self.minbytes, self.maxbytes)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""return the validated (internal) value or raise"""
|
"""return the validated (internal) value or raise"""
|
||||||
if type(value) not in [unicode, str]:
|
if type(value) not in [unicode, str]:
|
||||||
raise BadValueError(u'%r has the wrong type!' % value)
|
raise BadValueError(u'%r has the wrong type!' % value)
|
||||||
size = len(value)
|
size = len(value)
|
||||||
if size < self.minsize:
|
if size < self.minbytes:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'%r must be at least %d bytes long!' % (value, self.minsize))
|
u'%r must be at least %d bytes long!' % (value, self.minbytes))
|
||||||
if size > self.maxsize:
|
if size > self.maxbytes:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'%r must be at most %d bytes long!' % (value, self.maxsize))
|
u'%r must be at most %d bytes long!' % (value, self.maxbytes))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def export_value(self, value):
|
def export_value(self, value):
|
||||||
@ -403,37 +415,43 @@ class BLOBType(DataType):
|
|||||||
|
|
||||||
|
|
||||||
class StringType(DataType):
|
class StringType(DataType):
|
||||||
minsize = None
|
MAXCHARS = 0xffffffff
|
||||||
maxsize = None
|
|
||||||
|
|
||||||
def __init__(self, minsize=0, maxsize=None):
|
def __init__(self, minchars=0, maxchars=None, isUTF8=False):
|
||||||
if maxsize is None:
|
if maxchars is None:
|
||||||
maxsize = minsize or 100
|
maxchars = minchars or self.MAXCHARS
|
||||||
self.minsize = int(minsize)
|
self._defaults = {}
|
||||||
self.maxsize = int(maxsize)
|
self.set_prop('minchars', minchars, 0, int)
|
||||||
if self.minsize < 0:
|
self.set_prop('maxchars', maxchars, self.MAXCHARS, int)
|
||||||
|
self.set_prop('isUTF8', isUTF8, False, bool)
|
||||||
|
if self.minchars < 0:
|
||||||
raise BadValueError(u'sizes must be bigger than or equal to 0!')
|
raise BadValueError(u'sizes must be bigger than or equal to 0!')
|
||||||
elif self.minsize > self.maxsize:
|
elif self.minchars > self.maxchars:
|
||||||
raise BadValueError(u'maxsize must be bigger than or equal to minsize!')
|
raise BadValueError(u'maxchars must be bigger than or equal to minchars!')
|
||||||
self.default = u' ' * self.minsize
|
self.default = u' ' * self.minchars
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'string': dict(min=self.minsize, max=self.maxsize)}
|
return self.get_info(type='string')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'StringType(%d, %d)' % (self.minsize, self.maxsize)
|
return u'StringType(%s)' % (', '.join('%s=%r' % kv for kv in self.get_info().items()))
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""return the validated (internal) value or raise"""
|
"""return the validated (internal) value or raise"""
|
||||||
if type(value) not in (unicode, str):
|
if type(value) not in (unicode, str):
|
||||||
raise BadValueError(u'%r has the wrong type!' % value)
|
raise BadValueError(u'%r has the wrong type!' % value)
|
||||||
|
if not self.isUTF8:
|
||||||
|
try:
|
||||||
|
value.encode('ascii')
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
raise BadValueError(u'%r contains non-ascii character!' % value)
|
||||||
size = len(value)
|
size = len(value)
|
||||||
if size < self.minsize:
|
if size < self.minchars:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'%r must be at least %d bytes long!' % (value, self.minsize))
|
u'%r must be at least %d bytes long!' % (value, self.minchars))
|
||||||
if size > self.maxsize:
|
if size > self.maxchars:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'%r must be at most %d bytes long!' % (value, self.maxsize))
|
u'%r must be at most %d bytes long!' % (value, self.maxchars))
|
||||||
if u'\0' in value:
|
if u'\0' in value:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'Strings are not allowed to embed a \\0! Use a Blob instead!')
|
u'Strings are not allowed to embed a \\0! Use a Blob instead!')
|
||||||
@ -461,17 +479,17 @@ class StringType(DataType):
|
|||||||
# unfortunately, SECoP makes no distinction here....
|
# unfortunately, SECoP makes no distinction here....
|
||||||
# note: content is supposed to follow the format of a git commit message, i.e. a line of text, 2 '\n' + a longer explanation
|
# note: content is supposed to follow the format of a git commit message, i.e. a line of text, 2 '\n' + a longer explanation
|
||||||
class TextType(StringType):
|
class TextType(StringType):
|
||||||
def __init__(self, maxsize=None):
|
def __init__(self, maxchars=None):
|
||||||
if maxsize is None:
|
if maxchars is None:
|
||||||
maxsize = 8000
|
maxchars = self.MAXCHARS
|
||||||
super(TextType, self).__init__(0, maxsize)
|
super(TextType, self).__init__(0, maxchars)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'TextType(%d, %d)' % (self.minsize, self.maxsize)
|
return u'TextType(%d, %d)' % (self.minchars, self.maxchars)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
# DataType.copy will not work, because it is exported as 'string'
|
# DataType.copy will not work, because it is exported as 'string'
|
||||||
return TextType(self.maxsize)
|
return TextType(self.maxchars)
|
||||||
|
|
||||||
|
|
||||||
# Bool is a special enum
|
# Bool is a special enum
|
||||||
@ -479,7 +497,7 @@ class BoolType(DataType):
|
|||||||
default = False
|
default = False
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'bool': {}}
|
return {'type': 'bool'}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'BoolType()'
|
return u'BoolType()'
|
||||||
@ -514,51 +532,51 @@ class BoolType(DataType):
|
|||||||
|
|
||||||
|
|
||||||
class ArrayOf(DataType):
|
class ArrayOf(DataType):
|
||||||
minsize = None
|
minlen = None
|
||||||
maxsize = None
|
maxlen = None
|
||||||
members = None
|
members = None
|
||||||
|
|
||||||
def __init__(self, members, minsize=0, maxsize=None, unit=None):
|
def __init__(self, members, minlen=0, maxlen=None, unit=None):
|
||||||
if not isinstance(members, DataType):
|
if not isinstance(members, DataType):
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'ArrayOf only works with a DataType as first argument!')
|
u'ArrayOf only works with a DataType as first argument!')
|
||||||
# one argument -> exactly that size
|
# one argument -> exactly that size
|
||||||
# argument default to 100
|
# argument default to 100
|
||||||
if maxsize is None:
|
if maxlen is None:
|
||||||
maxsize = minsize or 100
|
maxlen = minlen or 100
|
||||||
self.members = members
|
self.members = members
|
||||||
if unit:
|
if unit:
|
||||||
self.members.unit = unit
|
self.members.unit = unit
|
||||||
|
|
||||||
self.minsize = int(minsize)
|
self.minlen = int(minlen)
|
||||||
self.maxsize = int(maxsize)
|
self.maxlen = int(maxlen)
|
||||||
if self.minsize < 0:
|
if self.minlen < 0:
|
||||||
raise BadValueError(u'sizes must be > 0')
|
raise BadValueError(u'sizes must be > 0')
|
||||||
elif self.maxsize < 1:
|
elif self.maxlen < 1:
|
||||||
raise BadValueError(u'Maximum size must be >= 1!')
|
raise BadValueError(u'Maximum size must be >= 1!')
|
||||||
elif self.minsize > self.maxsize:
|
elif self.minlen > self.maxlen:
|
||||||
raise BadValueError(u'maxsize must be bigger than or equal to minsize!')
|
raise BadValueError(u'maxlen must be bigger than or equal to minlen!')
|
||||||
self.default = [members.default] * self.minsize
|
self.default = [members.default] * self.minlen
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'array': dict(min=self.minsize, max=self.maxsize,
|
return dict(type='array', minlen=self.minlen, maxlen=self.maxlen,
|
||||||
members=self.members.export_datatype())}
|
members=self.members.export_datatype())
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'ArrayOf(%s, %s, %s)' % (
|
return u'ArrayOf(%s, %s, %s)' % (
|
||||||
repr(self.members), self.minsize, self.maxsize)
|
repr(self.members), self.minlen, self.maxlen)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""validate an external representation to an internal one"""
|
"""validate an external representation to an internal one"""
|
||||||
if isinstance(value, (tuple, list)):
|
if isinstance(value, (tuple, list)):
|
||||||
# check number of elements
|
# check number of elements
|
||||||
if self.minsize is not None and len(value) < self.minsize:
|
if self.minlen is not None and len(value) < self.minlen:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'Array too small, needs at least %d elements!' %
|
u'Array too small, needs at least %d elements!' %
|
||||||
self.minsize)
|
self.minlen)
|
||||||
if self.maxsize is not None and len(value) > self.maxsize:
|
if self.maxlen is not None and len(value) > self.maxlen:
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
u'Array too big, holds at most %d elements!' % self.minsize)
|
u'Array too big, holds at most %d elements!' % self.minlen)
|
||||||
# apply subtype valiation to all elements and return as list
|
# apply subtype valiation to all elements and return as list
|
||||||
return [self.members(elem) for elem in value]
|
return [self.members(elem) for elem in value]
|
||||||
raise BadValueError(
|
raise BadValueError(
|
||||||
@ -600,7 +618,7 @@ class TupleOf(DataType):
|
|||||||
self.default = tuple(el.default for el in members)
|
self.default = tuple(el.default for el in members)
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
return {u'tuple': dict(members=[subtype.export_datatype() for subtype in self.members])}
|
return dict(type='tuple', members=[subtype.export_datatype() for subtype in self.members])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.members])
|
return u'TupleOf(%s)' % u', '.join([repr(st) for st in self.members])
|
||||||
@ -659,15 +677,16 @@ class StructOf(DataType):
|
|||||||
self.default = dict((k,el.default) for k, el in members.items())
|
self.default = dict((k,el.default) for k, el in members.items())
|
||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
res = {u'struct': dict(members=dict((n, s.export_datatype())
|
res = dict(type='struct', members=dict((n, s.export_datatype())
|
||||||
for n, s in list(self.members.items())))}
|
for n, s in list(self.members.items())))
|
||||||
if self.optional:
|
if self.optional:
|
||||||
res['struct']['optional'] = self.optional
|
res['optional'] = self.optional
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return u'StructOf(%s)' % u', '.join(
|
opt = self.optional if self.optional else ''
|
||||||
[u'%s=%s' % (n, repr(st)) for n, st in list(self.members.items())])
|
return u'StructOf(%s%s)' % (u', '.join(
|
||||||
|
[u'%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]), opt)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""return the validated value or raise"""
|
"""return the validated value or raise"""
|
||||||
@ -728,12 +747,12 @@ class CommandType(DataType):
|
|||||||
|
|
||||||
def export_datatype(self):
|
def export_datatype(self):
|
||||||
a, r = self.argument, self.result
|
a, r = self.argument, self.result
|
||||||
props = {}
|
props = {'type': 'command'}
|
||||||
if a is not None:
|
if a is not None:
|
||||||
props['argument'] = a.export_datatype()
|
props['argument'] = a.export_datatype()
|
||||||
if r is not None:
|
if r is not None:
|
||||||
props['result'] = r.export_datatype()
|
props['result'] = r.export_datatype()
|
||||||
return {u'command': props}
|
return props
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
argstr = repr(self.argument) if self.argument else ''
|
argstr = repr(self.argument) if self.argument else ''
|
||||||
@ -876,9 +895,9 @@ DATATYPES = dict(
|
|||||||
int =lambda min, max, **kwds: IntRange(minval=min, maxval=max, **kwds),
|
int =lambda min, max, **kwds: IntRange(minval=min, maxval=max, **kwds),
|
||||||
scaled =lambda scale, min, max, **kwds: ScaledInteger(scale=scale, minval=min*scale, maxval=max*scale, **kwds),
|
scaled =lambda scale, min, max, **kwds: ScaledInteger(scale=scale, minval=min*scale, maxval=max*scale, **kwds),
|
||||||
double =lambda min=None, max=None, **kwds: FloatRange(minval=min, maxval=max, **kwds),
|
double =lambda min=None, max=None, **kwds: FloatRange(minval=min, maxval=max, **kwds),
|
||||||
blob =lambda max, min=0: BLOBType(minsize=min, maxsize=max),
|
blob =lambda maxbytes, minbytes=0: BLOBType(minbytes=minbytes, maxbytes=maxbytes),
|
||||||
string =lambda max, min=0: StringType(minsize=min, maxsize=max),
|
string =lambda minchars=0, maxchars=None: StringType(minchars=minchars, maxchars=maxchars),
|
||||||
array =lambda max, members, min=0: ArrayOf(get_datatype(members), minsize=min, maxsize=max),
|
array =lambda maxlen, members, minlen=0: ArrayOf(get_datatype(members), minlen=minlen, maxlen=maxlen),
|
||||||
tuple =lambda members: TupleOf(*map(get_datatype, members)),
|
tuple =lambda members: TupleOf(*map(get_datatype, members)),
|
||||||
enum =lambda members: EnumType('', members=members),
|
enum =lambda members: EnumType('', members=members),
|
||||||
struct =lambda members, optional=None: StructOf(optional,
|
struct =lambda members, optional=None: StructOf(optional,
|
||||||
@ -897,10 +916,12 @@ def get_datatype(json):
|
|||||||
return json
|
return json
|
||||||
if isinstance(json, list) and len(json) == 2:
|
if isinstance(json, list) and len(json) == 2:
|
||||||
base, args = json # still allow old syntax
|
base, args = json # still allow old syntax
|
||||||
elif isinstance(json, dict) and len(json) == 1:
|
|
||||||
base, args = tuple(json.items())[0]
|
|
||||||
else:
|
else:
|
||||||
raise BadValueError('a data descriptor must be a dict (len=1), not %r' % json)
|
try:
|
||||||
|
args = json.copy()
|
||||||
|
base = args.pop('type')
|
||||||
|
except (TypeError, KeyError, AttributeError):
|
||||||
|
raise BadValueError('a data descriptor must be a dict containing a "type" key, not %r' % json)
|
||||||
try:
|
try:
|
||||||
return DATATYPES[base](**args)
|
return DATATYPES[base](**args)
|
||||||
except (TypeError, AttributeError, KeyError):
|
except (TypeError, AttributeError, KeyError):
|
||||||
|
@ -49,7 +49,7 @@ def test_DataType():
|
|||||||
def test_FloatRange():
|
def test_FloatRange():
|
||||||
dt = FloatRange(-3.14, 3.14)
|
dt = FloatRange(-3.14, 3.14)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'double': {u'min':-3.14, u'max':3.14}}
|
assert dt.export_datatype() == {'type': 'double', 'min':-3.14, 'max':3.14}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -68,18 +68,18 @@ def test_FloatRange():
|
|||||||
FloatRange(u'x', u'Y')
|
FloatRange(u'x', u'Y')
|
||||||
# check that unit can be changed
|
# check that unit can be changed
|
||||||
dt.unit = u'K'
|
dt.unit = u'K'
|
||||||
assert dt.export_datatype() == {u'double': {u'min':-3.14, u'max':3.14, u'unit': u'K'}}
|
assert dt.export_datatype() == {'type': 'double', 'min':-3.14, 'max':3.14, 'unit': u'K'}
|
||||||
|
|
||||||
dt = FloatRange()
|
dt = FloatRange()
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'double': {}}
|
assert dt.export_datatype() == {'type': 'double'}
|
||||||
|
|
||||||
dt = FloatRange(unit=u'X', fmtstr=u'%.2f', absolute_resolution=1,
|
dt = FloatRange(unit=u'X', fmtstr=u'%.2f', absolute_resolution=1,
|
||||||
relative_resolution=0.1)
|
relative_resolution=0.1)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'double': {u'unit':u'X', u'fmtstr':u'%.2f',
|
assert dt.export_datatype() == {'type': 'double', 'unit':'X', 'fmtstr':'%.2f',
|
||||||
u'absolute_resolution':1.0,
|
'absolute_resolution':1.0,
|
||||||
u'relative_resolution':0.1}}
|
'relative_resolution':0.1}
|
||||||
assert dt(4) == 4
|
assert dt(4) == 4
|
||||||
assert dt.format_value(3.14) == u'3.14 X'
|
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'
|
||||||
@ -89,7 +89,7 @@ def test_FloatRange():
|
|||||||
def test_IntRange():
|
def test_IntRange():
|
||||||
dt = IntRange(-3, 3)
|
dt = IntRange(-3, 3)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'int': {u'min':-3, u'max':3}}
|
assert dt.export_datatype() == {'type': 'int', 'min':-3, 'max':3}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -106,16 +106,16 @@ def test_IntRange():
|
|||||||
|
|
||||||
dt = IntRange()
|
dt = IntRange()
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert tuple(dt.export_datatype()) == ('int',)
|
assert dt.export_datatype()['type'] == 'int'
|
||||||
assert dt.export_datatype()['int'][u'min'] < 0 < dt.export_datatype()['int'][u'max']
|
assert dt.export_datatype()['min'] < 0 < dt.export_datatype()['max']
|
||||||
assert dt.export_datatype() == {u'int': {u'max': 16777216, u'min': -16777216}}
|
assert dt.export_datatype() == {'type': 'int', 'max': 16777216,u'min': -16777216}
|
||||||
assert dt.format_value(42) == u'42'
|
assert dt.format_value(42) == u'42'
|
||||||
|
|
||||||
def test_ScaledInteger():
|
def test_ScaledInteger():
|
||||||
dt = ScaledInteger(0.01, -3, 3)
|
dt = ScaledInteger(0.01, -3, 3)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
# serialisation of datatype contains limits on the 'integer' value
|
# serialisation of datatype contains limits on the 'integer' value
|
||||||
assert dt.export_datatype() == {u'scaled': {u'scale':0.01, u'min':-300, u'max':300}}
|
assert dt.export_datatype() == {'type': 'scaled', 'scale':0.01, 'min':-300, 'max':300}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -135,7 +135,7 @@ def test_ScaledInteger():
|
|||||||
ScaledInteger(scale=-10, minval=1, maxval=2)
|
ScaledInteger(scale=-10, minval=1, maxval=2)
|
||||||
# check that unit can be changed
|
# check that unit can be changed
|
||||||
dt.unit = u'A'
|
dt.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_datatype() == {'type': 'scaled', 'scale':0.01, 'min':-300, 'max':300, 'unit': 'A'}
|
||||||
|
|
||||||
assert dt.export_value(0.0001) == int(0)
|
assert dt.export_value(0.0001) == int(0)
|
||||||
assert dt.export_value(2.71819) == int(272)
|
assert dt.export_value(2.71819) == int(272)
|
||||||
@ -144,10 +144,10 @@ def test_ScaledInteger():
|
|||||||
dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%.1f',
|
dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%.1f',
|
||||||
absolute_resolution=0.001, relative_resolution=1e-5)
|
absolute_resolution=0.001, relative_resolution=1e-5)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'scaled': {u'scale':0.003, u'min':0, u'max':333,
|
assert dt.export_datatype() == {'type': 'scaled', 'scale':0.003, 'min':0, 'max':333,
|
||||||
u'unit':u'X', u'fmtstr':u'%.1f',
|
u'unit':u'X', u'fmtstr':u'%.1f',
|
||||||
u'absolute_resolution':0.001,
|
u'absolute_resolution':0.001,
|
||||||
u'relative_resolution':1e-5}}
|
u'relative_resolution':1e-5}
|
||||||
assert dt(0.4) == 0.399
|
assert dt(0.4) == 0.399
|
||||||
assert dt.format_value(0.4) == u'0.4 X'
|
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'') == u'0.4'
|
||||||
@ -166,7 +166,7 @@ def test_EnumType():
|
|||||||
|
|
||||||
dt = EnumType(u'dt', a=3, c=7, stuff=1)
|
dt = EnumType(u'dt', a=3, c=7, stuff=1)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'enum': dict(members=dict(a=3, c=7, stuff=1))}
|
assert dt.export_datatype() == {'type': 'enum', 'members': dict(a=3, c=7, stuff=1)}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -201,14 +201,14 @@ def test_BLOBType():
|
|||||||
# test constructor catching illegal arguments
|
# test constructor catching illegal arguments
|
||||||
dt = BLOBType()
|
dt = BLOBType()
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'blob': {u'min':0, u'max':255}}
|
assert dt.export_datatype() == {'type': 'blob', 'maxbytes':255}
|
||||||
dt = BLOBType(10)
|
dt = BLOBType(10)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'blob': {u'min':10, u'max':10}}
|
assert dt.export_datatype() == {'type': 'blob', 'minbytes':10, 'maxbytes':10}
|
||||||
|
|
||||||
dt = BLOBType(3, 10)
|
dt = BLOBType(3, 10)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'blob': {u'min':3, u'max':10}}
|
assert dt.export_datatype() == {'type': 'blob', 'minbytes':3, 'maxbytes':10}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -233,13 +233,14 @@ def test_StringType():
|
|||||||
# test constructor catching illegal arguments
|
# test constructor catching illegal arguments
|
||||||
dt = StringType()
|
dt = StringType()
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
|
assert dt.export_datatype() == {'type': 'string'}
|
||||||
dt = StringType(12)
|
dt = StringType(12)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'string': {u'min':12, u'max':12}}
|
assert dt.export_datatype() == {'type': 'string', 'minchars':12, 'maxchars':12}
|
||||||
|
|
||||||
dt = StringType(4, 11)
|
dt = StringType(4, 11)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'string': {u'min':4, u'max':11}}
|
assert dt.export_datatype() == {'type': 'string', 'minchars':4, 'maxchars':11}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -265,7 +266,7 @@ def test_TextType():
|
|||||||
# test constructor catching illegal arguments
|
# test constructor catching illegal arguments
|
||||||
dt = TextType(12)
|
dt = TextType(12)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'string': {u'min':0, u'max':12}}
|
assert dt.export_datatype() == {'type': 'string', 'maxchars':12}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -287,7 +288,7 @@ def test_BoolType():
|
|||||||
# test constructor catching illegal arguments
|
# test constructor catching illegal arguments
|
||||||
dt = BoolType()
|
dt = BoolType()
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'bool': {}}
|
assert dt.export_datatype() == {'type': 'bool'}
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -319,16 +320,15 @@ def test_ArrayOf():
|
|||||||
ArrayOf(-3, IntRange(-10,10))
|
ArrayOf(-3, IntRange(-10,10))
|
||||||
dt = ArrayOf(IntRange(-10, 10), 5)
|
dt = ArrayOf(IntRange(-10, 10), 5)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'array': {u'min':5, u'max':5,
|
assert dt.export_datatype() == {'type': 'array', 'minlen':5, 'maxlen':5,
|
||||||
u'members':{u'int': {u'min':-10,
|
'members': {'type': 'int', 'min':-10,
|
||||||
u'max':10}}}}
|
'max':10}}
|
||||||
|
|
||||||
dt = ArrayOf(FloatRange(-10, 10, unit=u'Z'), 1, 3)
|
dt = ArrayOf(FloatRange(-10, 10, unit=u'Z'), 1, 3)
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'array': {u'min':1, u'max':3,
|
assert dt.export_datatype() == {'type': 'array', 'minlen':1, 'maxlen':3,
|
||||||
u'members':{u'double': {u'min':-10,
|
'members':{'type': 'double', 'min':-10,
|
||||||
u'max':10,
|
'max':10, 'unit': 'Z'}}
|
||||||
u'unit':u'Z'}}}}
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@ -351,10 +351,8 @@ def test_TupleOf():
|
|||||||
|
|
||||||
dt = TupleOf(IntRange(-10, 10), BoolType())
|
dt = TupleOf(IntRange(-10, 10), BoolType())
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'tuple': {u'members':[{u'int': {u'min':-10,
|
assert dt.export_datatype() == {'type': 'tuple',
|
||||||
u'max':10}},
|
'members':[{'type': 'int', 'min':-10, 'max':10}, {'type': 'bool'}]}
|
||||||
{u'bool': {}}]}}
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@ -378,12 +376,10 @@ def test_StructOf():
|
|||||||
dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999),
|
dt = StructOf(a_string=StringType(0, 55), an_int=IntRange(0, 999),
|
||||||
optional=[u'an_int'])
|
optional=[u'an_int'])
|
||||||
copytest(dt)
|
copytest(dt)
|
||||||
assert dt.export_datatype() == {u'struct': {u'members':{u'a_string':
|
assert dt.export_datatype() == {'type': 'struct',
|
||||||
{u'string': {u'min':0, u'max':55}},
|
'members':{'a_string': {'type': 'string', 'maxchars':55},
|
||||||
u'an_int':
|
'an_int': {'type': 'int', 'min':0, 'max':999}},
|
||||||
{u'int': {u'min':0, u'max':999}},},
|
'optional':['an_int']}
|
||||||
u'optional':[u'an_int'],
|
|
||||||
}}
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
dt(9)
|
dt(9)
|
||||||
@ -404,14 +400,15 @@ def test_StructOf():
|
|||||||
|
|
||||||
def test_Command():
|
def test_Command():
|
||||||
dt = CommandType()
|
dt = CommandType()
|
||||||
assert dt.export_datatype() == {u'command': {}}
|
assert dt.export_datatype() == {'type': 'command'}
|
||||||
|
|
||||||
dt = CommandType(IntRange(-1,1))
|
dt = CommandType(IntRange(-1,1))
|
||||||
assert dt.export_datatype() == {u'command': {u'argument':{u'int': {u'min':-1, u'max':1}}}}
|
assert dt.export_datatype() == {'type': 'command', 'argument':{'type': 'int', 'min':-1, 'max':1}}
|
||||||
|
|
||||||
dt = CommandType(IntRange(-1,1), IntRange(-3,3))
|
dt = CommandType(IntRange(-1,1), IntRange(-3,3))
|
||||||
assert dt.export_datatype() == {u'command': {u'argument':{u'int': {u'min':-1, u'max':1}},
|
assert dt.export_datatype() == {'type': 'command',
|
||||||
u'result':{u'int': {u'min':-3, u'max':3}}}}
|
'argument':{'type': 'int', 'min':-1, 'max':1},
|
||||||
|
'result':{'type': 'int', 'min':-3, 'max':3}}
|
||||||
|
|
||||||
|
|
||||||
def test_get_datatype():
|
def test_get_datatype():
|
||||||
@ -424,144 +421,129 @@ def test_get_datatype():
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'undefined': {}})
|
get_datatype({u'undefined': {}})
|
||||||
|
|
||||||
assert isinstance(get_datatype({u'bool': {}}), BoolType)
|
assert isinstance(get_datatype({'type': 'bool'}), BoolType)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'bool'])
|
get_datatype([u'bool'])
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype({u'bool': 3})
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'int': {u'min':-10}})
|
get_datatype({'type': 'int', 'min':-10}) # missing max
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'int': {u'max':10}})
|
get_datatype({'type': 'int', 'max':10}) # missing min
|
||||||
assert isinstance(get_datatype({u'int': {u'min':-10, u'max':10}}), IntRange)
|
assert isinstance(get_datatype({'type': 'int', 'min':-10, 'max':10}), IntRange)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'int': {u'min':10, u'max':-10}})
|
get_datatype({'type': 'int', 'min':10, 'max':-10}) # min > max
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'int'])
|
get_datatype({'type': 'int'}) # missing limits
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'int': {}})
|
get_datatype({'type': 'int', 'x': 2})
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype({u'int': 1, u'x': 2})
|
|
||||||
|
|
||||||
assert isinstance(get_datatype({u'double': {}}), FloatRange)
|
assert isinstance(get_datatype({'type': 'double'}), FloatRange)
|
||||||
assert isinstance(get_datatype({u'double': {u'min':-2.718}}), FloatRange)
|
assert isinstance(get_datatype({'type': 'double', 'min':-2.718}), FloatRange)
|
||||||
assert isinstance(get_datatype({u'double': {u'max':3.14}}), FloatRange)
|
assert isinstance(get_datatype({'type': 'double', 'max':3.14}), FloatRange)
|
||||||
assert isinstance(get_datatype({u'double': {u'min':-9.9, u'max':11.1}}),
|
assert isinstance(get_datatype({'type': 'double', 'min':-9.9, 'max':11.1}),
|
||||||
FloatRange)
|
FloatRange)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'double'])
|
get_datatype([u'double'])
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'double': {u'min':10, u'max':-10}})
|
get_datatype({'type': 'double', 'min':10, 'max':-10})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'double': {}, u'x': 2})
|
get_datatype(['double', {}, 2])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'scaled': {u'scale':0.01,u'min':-2.718}})
|
get_datatype({'type': 'scaled', 'scale':0.01, 'min':-2.718})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'scaled': {u'scale':0.02,u'max':3.14}})
|
get_datatype({'type': 'scaled', 'scale':0.02, 'max':3.14})
|
||||||
assert isinstance(get_datatype({u'scaled': {u'scale':0.03,
|
assert isinstance(get_datatype(
|
||||||
u'min':-99,
|
{'type': 'scaled', 'scale':0.03, 'min':-99, 'max':111}), ScaledInteger)
|
||||||
u'max':111}}), ScaledInteger)
|
|
||||||
|
|
||||||
dt = ScaledInteger(scale=0.03, minval=0, maxval=9.9)
|
dt = ScaledInteger(scale=0.03, minval=0, maxval=9.9)
|
||||||
assert dt.export_datatype() == {u'scaled': {u'max':330, u'min':0, u'scale':0.03}}
|
assert dt.export_datatype() == {'type': 'scaled', 'max':330, 'min':0, 'scale':0.03}
|
||||||
assert get_datatype(dt.export_datatype()).export_datatype() == dt.export_datatype()
|
assert get_datatype(dt.export_datatype()).export_datatype() == dt.export_datatype()
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'scaled']) # dict missing
|
get_datatype([u'scaled']) # dict missing
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'scaled': {u'min':-10, u'max':10}}) # no scale
|
get_datatype({'type': 'scaled', 'min':-10, 'max':10}) # no scale
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'scaled': {u'min':10, u'max':-10}}) # limits reversed
|
get_datatype({'type': 'scaled', 'min':10, 'max':-10, 'scale': 1}) # limits reversed
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'scaled': {u'min':10, u'max':-10, u'x': 2}})
|
get_datatype(['scaled', {'min':10, 'max':-10, 'scale': 1}, 2])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'enum'])
|
get_datatype([u'enum'])
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'enum': dict(a=-2)})
|
get_datatype({'type': 'enum', 'a': -2})
|
||||||
assert isinstance(get_datatype({u'enum': {u'members':dict(a=-2)}}), EnumType)
|
assert isinstance(get_datatype({'type': 'enum', 'members':dict(a=-2)}), EnumType)
|
||||||
|
|
||||||
|
assert isinstance(get_datatype({'type': 'blob', 'maxbytes':1}), BLOBType)
|
||||||
|
assert isinstance(get_datatype({'type': 'blob', 'minbytes':1, 'maxbytes':10}), BLOBType)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'enum': dict(a=-2), u'x': 1})
|
get_datatype({'type': 'blob', 'minbytes':10, 'maxbytes':1})
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
get_datatype({'type': 'blob', 'minbytes':10, 'maxbytes':-10})
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
get_datatype(['blob', {'maxbytes':10}, 'x'])
|
||||||
|
|
||||||
assert isinstance(get_datatype({u'blob': {u'max':1}}), BLOBType)
|
assert isinstance(get_datatype({'type': 'string', 'maxchars':1}), StringType)
|
||||||
assert isinstance(get_datatype({u'blob': {u'min':1, u'max':10}}), BLOBType)
|
assert isinstance(get_datatype({'type': 'string', 'maxchars':1}), StringType)
|
||||||
|
assert isinstance(get_datatype({'type': 'string', 'minchars':1, 'maxchars':10}), StringType)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'blob': {u'min':10, u'max':1}})
|
get_datatype({'type': 'string', 'minchars':10, 'maxchars':1})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'blob': {u'min':10, u'max':-10}})
|
get_datatype({'type': 'string', 'minchars':10, 'maxchars':-10})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'blob': {u'min':10, u'max':-10}, u'x': 0})
|
get_datatype(['string', {'maxchars':-0}, 'x'])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype([u'string'])
|
|
||||||
assert isinstance(get_datatype({u'string': {u'max':1}}), StringType)
|
|
||||||
assert isinstance(get_datatype({u'string': {u'min':1, u'max':10}}), StringType)
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype({u'string': {u'min':10, u'max':1}})
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype({u'string': {u'min':10, u'max':-10}})
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
get_datatype({u'string': {u'min':10, u'max':-10, u'x': 0}})
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'array'])
|
get_datatype([u'array'])
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'array': 1})
|
get_datatype({'type': 'array', 'members': [1]})
|
||||||
with pytest.raises(ValueError):
|
assert isinstance(get_datatype({'type': 'array', 'minlen':1, 'maxlen':1,
|
||||||
get_datatype({u'array': [1]})
|
'members':{'type': 'blob', 'maxbytes':1}}
|
||||||
assert isinstance(get_datatype({u'array': {u'min':1, u'max':1,
|
|
||||||
u'members':{u'blob': {u'max':1}}}}
|
|
||||||
), ArrayOf)
|
), ArrayOf)
|
||||||
assert isinstance(get_datatype({u'array': {u'min':1, u'max':1,
|
assert isinstance(get_datatype({'type': 'array', 'minlen':1, u'maxlen':1,
|
||||||
u'members':{u'blob': {u'max':1}}}}
|
'members':{'type': 'blob', 'maxbytes':1}}
|
||||||
).members, BLOBType)
|
).members, BLOBType)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'array': {u'members':{u'blob': {u'max':1}}, u'min':-10}})
|
get_datatype({'type': 'array', 'members':{'type': 'blob', 'maxbytes':1}, 'minbytes':-10})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'array': {u'members':{u'blob': {u'max':1}},
|
get_datatype({'type': 'array', 'members':{'type': 'blob', 'maxbytes':1},
|
||||||
u'min':10, 'max':1}})
|
'min':10, 'max':1})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'array': {u'blob': dict(max=4)}, u'max': 10})
|
get_datatype({'type': 'array', 'blob': dict(max=4), 'maxbytes': 10})
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'tuple'])
|
get_datatype(['tuple'])
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'tuple': 1})
|
get_datatype(['tuple', [1], 2, 3])
|
||||||
with pytest.raises(ValueError):
|
assert isinstance(get_datatype(
|
||||||
get_datatype([u'tuple', [1], 2, 3])
|
{'type': 'tuple', 'members':[{'type': 'blob', 'maxbytes':1}]}), TupleOf)
|
||||||
assert isinstance(get_datatype({u'tuple': {u'members':[{u'blob':
|
assert isinstance(get_datatype(
|
||||||
{u'max':1}}]}}), TupleOf)
|
{'type': 'tuple', 'members':[{'type': 'blob', 'maxbytes':1}]}).members[0], BLOBType)
|
||||||
assert isinstance(get_datatype({u'tuple': {u'members':[{u'blob':
|
|
||||||
{u'max':1}}]}}).members[0], BLOBType)
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'tuple': {}})
|
get_datatype({'type': 'tuple', 'members': {}})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'tuple', 10, -10])
|
get_datatype([u'tuple', 10, -10])
|
||||||
|
|
||||||
assert isinstance(get_datatype({u'tuple': {u'members':[{u'blob': {u'max':1}},
|
assert isinstance(get_datatype({'type': 'tuple', 'members':[{'type': 'blob', 'maxbytes':1},
|
||||||
{u'bool':{}}]}}), TupleOf)
|
{'type': 'bool'}]}), TupleOf)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype([u'struct'])
|
get_datatype(['struct'])
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'struct': 1})
|
get_datatype(['struct', [1], 2, 3])
|
||||||
with pytest.raises(ValueError):
|
assert isinstance(get_datatype({'type': 'struct', 'members':
|
||||||
get_datatype([u'struct', [1], 2, 3])
|
{u'name': {'type': 'blob', 'maxbytes':1}}}), StructOf)
|
||||||
assert isinstance(get_datatype({u'struct': {u'members':
|
assert isinstance(get_datatype({'type': 'struct', 'members':
|
||||||
{u'name': {u'blob': {u'max':1}}}}}), StructOf)
|
{u'name': {'type': 'blob', 'maxbytes':1}}}).members[u'name'], BLOBType)
|
||||||
assert isinstance(get_datatype({u'struct': {u'members':
|
|
||||||
{u'name': {u'blob': {u'max':1}}}}}).members[u'name'], BLOBType)
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'struct': {}})
|
get_datatype({'type': 'struct', 'members': {}})
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_datatype({u'struct': {u'members':[1,2,3]}})
|
get_datatype({'type': 'struct', 'members':[1,2,3]})
|
||||||
|
@ -36,18 +36,18 @@ def test_Command():
|
|||||||
assert cmd.ctr
|
assert cmd.ctr
|
||||||
assert cmd.argument is None
|
assert cmd.argument is None
|
||||||
assert cmd.result is None
|
assert cmd.result is None
|
||||||
assert cmd.for_export() == {u'datatype': {u'command': {}},
|
assert cmd.for_export() == {u'datatype': {'type': 'command'},
|
||||||
u'description': u'do_something'}
|
u'description': u'do_something'}
|
||||||
|
|
||||||
cmd = Command(u'do_something', argument=IntRange(-9,9), result=IntRange(-1,1))
|
cmd = Command(u'do_something', argument=IntRange(-9,9), result=IntRange(-1,1))
|
||||||
assert cmd.description
|
assert cmd.description
|
||||||
assert isinstance(cmd.argument, IntRange)
|
assert isinstance(cmd.argument, IntRange)
|
||||||
assert isinstance(cmd.result, IntRange)
|
assert isinstance(cmd.result, IntRange)
|
||||||
assert cmd.for_export() == {u'datatype': {u'command': {u'argument': {u'int': {u'min':-9, u'max':9}},
|
assert cmd.for_export() == {u'datatype': {'type': 'command', 'argument': {'type': 'int', 'min':-9, 'max':9},
|
||||||
u'result': {u'int': {u'min':-1, u'max':1}}}},
|
u'result': {'type': 'int', 'min':-1, 'max':1}},
|
||||||
u'description': u'do_something'}
|
u'description': u'do_something'}
|
||||||
assert cmd.exportProperties() == {u'datatype': {u'command': {u'argument': {u'int': {u'max': 9, u'min': -9}},
|
assert cmd.exportProperties() == {u'datatype': {'type': 'command', 'argument': {'type': 'int', 'max': 9, 'min': -9},
|
||||||
u'result': {u'int': {u'max': 1, u'min': -1}}}},
|
'result': {'type': 'int', 'max': 1, 'min': -1}},
|
||||||
u'description': u'do_something'}
|
u'description': u'do_something'}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user