make datatypes immutable

in order to prevent modifying parameters without automatically
trigger updates, all datatypes must be immutable.

TupleOf and ArrayOf: change from list to tuple
StructOf: use ImmutableDict

most existing code should work properly, the only thing to consider are
equality comparisons with lists, which will result to False all the time

the changes in secop_psi/ppms.py (using tuples instead of lists for status values)
are not really necessary, but lead to less confusing code

Change-Id: I181f412b5cd55af296b2e5120af82449beb03f54
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/22972
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:
2020-04-15 16:56:40 +02:00
parent ae7727dda8
commit da7a027949
4 changed files with 74 additions and 66 deletions

View File

@ -705,7 +705,7 @@ class ArrayOf(DataType):
raise BadValueError(
'Array too big, holds at most %d elements!' % self.minlen)
# apply subtype valiation to all elements and return as list
return [self.members(elem) for elem in value]
return tuple(self.members(elem) for elem in value)
raise BadValueError(
'Can not convert %s to ArrayOf DataType!' % repr(value))
@ -715,7 +715,7 @@ class ArrayOf(DataType):
def import_value(self, value):
"""returns a python object from serialisation"""
return [self.members.import_value(elem) for elem in value]
return tuple(self.members.import_value(elem) for elem in value)
def from_string(self, text):
value, rem = Parser.parse(text)
@ -772,8 +772,8 @@ class TupleOf(DataType):
'Illegal number of Arguments! Need %d arguments.' %
(len(self.members)))
# validate elements and return as list
return [sub(elem)
for sub, elem in zip(self.members, value)]
return tuple(sub(elem)
for sub, elem in zip(self.members, value))
except Exception as exc:
raise BadValueError('Can not validate:', str(exc))
@ -783,7 +783,7 @@ class TupleOf(DataType):
def import_value(self, value):
"""returns a python object from serialisation"""
return [sub.import_value(elem) for sub, elem in zip(self.members, value)]
return tuple(sub.import_value(elem) for sub, elem in zip(self.members, value))
def from_string(self, text):
value, rem = Parser.parse(text)
@ -804,6 +804,11 @@ class TupleOf(DataType):
a.compatible(b)
class ImmutableDict(dict):
def _no(self, *args, **kwds):
raise TypeError('a struct can not be modified, please overwrite instead')
__setitem__ = __delitem__ = clear = pop = popitem = setdefault = update = _no
class StructOf(DataType):
@ -843,7 +848,10 @@ class StructOf(DataType):
['%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]), opt)
def __call__(self, value):
"""return the validated value or raise"""
"""return the validated value or raise
in principle, we should make it some sort of frozen dict
"""
try:
# XXX: handle optional elements !!!
if len(list(value.keys())) != len(list(self.members.keys())):
@ -851,8 +859,8 @@ class StructOf(DataType):
'Illegal number of Arguments! Need %d arguments.' %
len(list(self.members.keys())))
# validate elements and return as dict
return dict((str(k), self.members[k](v))
for k, v in list(value.items()))
return ImmutableDict((str(k), self.members[k](v))
for k, v in list(value.items()))
except Exception as exc:
raise BadValueError('Can not validate %s: %s' % (repr(value), str(exc)))
@ -871,8 +879,8 @@ class StructOf(DataType):
raise BadValueError(
'Illegal number of Arguments! Need %d arguments.' % len(
list(self.members.keys())))
return dict((str(k), self.members[k].import_value(v))
for k, v in list(value.items()))
return ImmutableDict((str(k), self.members[k].import_value(v))
for k, v in list(value.items()))
def from_string(self, text):
value, rem = Parser.parse(text)