rework EnumType to use better Enum's

unfortunately IntEnum can't be bent like we would need it (extensible).
So we had to write our own....

The members of the Enum still behave like ints, but also have
.name and .value attributes, should they be needed.

needed adoptions to correctly use (and test) the EnumType are included.

Change-Id: Ie019d2f449a244c4fab00554b6c6daaac8948b59
Reviewed-on: https://forge.frm2.tum.de/review/17843
Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
Enrico Faulhaber
2018-04-26 16:29:09 +02:00
parent 927ca854a2
commit 574a66c65b
15 changed files with 644 additions and 298 deletions

View File

@ -21,17 +21,21 @@
# *****************************************************************************
"""Define validated data types."""
from __future__ import print_function
try:
# py2
unicode(u'')
unicode
except NameError:
# py3
unicode = str # pylint: disable=redefined-builtin
from base64 import b64encode, b64decode
from .errors import ProgrammingError, ParsingError
from .parse import Parser
from secop.lib.enum import Enum
from secop.errors import ProgrammingError, ParsingError
from secop.parse import Parser
Parser = Parser()
@ -181,64 +185,33 @@ class IntRange(DataType):
class EnumType(DataType):
as_json = [u'enum']
def __init__(self, enum_or_name='', **kwds):
self._enum = Enum(enum_or_name, **kwds)
def __init__(self, *args, **kwds):
# enum keys are ints! remember mapping from intvalue to 'name'
self.entries = {} # maps ints to strings
num = 0
for arg in args:
if not isinstance(arg, (str, unicode)):
raise ValueError(u'EnumType entries MUST be strings!')
self.entries[num] = arg
num += 1
for k, v in list(kwds.items()):
v = int(v)
if v in self.entries:
raise ValueError(
u'keyword argument %r=%d is already assigned %r' %
(k, v, self.entries[v]))
self.entries[v] = unicode(k)
# if len(self.entries) == 0:
# raise ValueError('Empty enums ae not allowed!')
# also keep a mapping from name strings to numbers
self.reversed = {} # maps Strings to ints
for k, v in self.entries.items():
if v in self.reversed:
raise ValueError(u'Mapping for %r=%r is not Unique!' % (v, k))
self.reversed[v] = k
self.as_json = [u'enum', self.reversed.copy()]
@property
def as_json(self):
return [u'enum'] + [dict((m.name, m.value) for m in self._enum.members)]
def __repr__(self):
return u'EnumType(%s)' % u', '.join(
[u'%s=%d' % (v, k) for k, v in list(self.entries.items())])
return "EnumType(%r, %s" % (self._enum.name, ', '.join('%s=%d' %(m.name, m.value) for m in self._enum.members))
def export_value(self, value):
"""returns a python object fit for serialisation"""
if value in self.reversed:
return self.reversed[value]
if int(value) in self.entries:
return int(value)
raise ValueError(u'%r is not one of %s' %
(unicode(value), u', '.join(list(self.reversed.keys()))))
return int(self.validate(value))
def import_value(self, value):
"""returns a python object from serialisation"""
# internally we store the key (which is a string)
return self.entries[int(value)]
return self.validate(value)
def validate(self, value):
"""return the validated (internal) value or raise"""
if value in self.reversed:
return self.reversed[value]
if int(value) in self.entries:
return int(value)
raise ValueError(u'%r is not one of %s' %
(unicode(value), u', '.join(map(unicode, self.entries))))
try:
return self._enum[value]
except KeyError:
raise ValueError('%r is not a member of enum %r' % (value, self._enum))
def from_string(self, text):
value = text
return self.validate(value)
return self.validate(text)
class BLOBType(DataType):
@ -606,7 +579,7 @@ DATATYPES = dict(
string=lambda _max=None, _min=0: StringType(_max, _min),
array=lambda subtype, _max=None, _min=0: ArrayOf(get_datatype(subtype), _max, _min),
tuple=lambda subtypes: TupleOf(*map(get_datatype, subtypes)),
enum=lambda kwds: EnumType(**kwds),
enum=lambda kwds: EnumType('', **kwds),
struct=lambda named_subtypes: StructOf(
**dict((n, get_datatype(t)) for n, t in list(named_subtypes.items()))),
command=Command,