22 from builtins
import zip
23 from builtins
import str
24 from builtins
import range
28 from .config
import Field, FieldValidationError, _typeStr, _autocast, _joinNamePath
29 from .comparison
import compareScalars, getComparisonName
30 from .callStack
import getCallStack, getStackFrame
32 __all__ = [
"ListField"]
35 class List(collections.MutableSequence):
36 def __init__(self, config, field, value, at, label, setHistory=True):
44 for i, x
in enumerate(value):
45 self.
insert(i, x, setHistory=
False)
47 msg =
"Value %s is of incorrect type %s. Sequence type expected" % (value, _typeStr(value))
54 if not isinstance(x, self.
_field.itemtype)
and x
is not None:
55 msg =
"Item at position %d with value %s is of incorrect type %s. Expected %s" % \
56 (i, x, _typeStr(x), _typeStr(self.
_field.itemtype))
59 if self.
_field.itemCheck
is not None and not self.
_field.itemCheck(x):
60 msg =
"Item at position %d is not a valid value: %s" % (i, x)
69 history = property(
lambda x: x._history)
72 return x
in self.
_list 75 return len(self.
_list)
77 def __setitem__(self, i, x, at=None, label="setitem", setHistory=True):
80 "Cannot modify a frozen Config")
81 if isinstance(i, slice):
82 k, stop, step = i.indices(len(self))
83 for j, xj
in enumerate(x):
84 xj = _autocast(xj, self.
_field.itemtype)
89 x = _autocast(x, self.
_field.itemtype)
101 def __delitem__(self, i, at=None, label="delitem", setHistory=True):
104 "Cannot modify a frozen Config")
112 return iter(self.
_list)
114 def insert(self, i, x, at=None, label="insert", setHistory=True):
117 self.
__setitem__(slice(i, i), [x], at=at, label=label, setHistory=setHistory)
120 return repr(self.
_list)
123 return str(self.
_list)
127 if len(self) != len(other):
130 for i, j
in zip(self, other):
134 except AttributeError:
139 return not self.
__eq__(other)
142 if hasattr(getattr(self.__class__, attr,
None),
'__set__'):
144 object.__setattr__(self, attr, value)
145 elif attr
in self.__dict__
or attr
in [
"_field",
"_config",
"_history",
"_list",
"__doc__"]:
147 object.__setattr__(self, attr, value)
150 msg =
"%s has no attribute %s" % (_typeStr(self.
_field), attr)
156 Defines a field which is a container of values of type dtype 158 If length is not None, then instances of this field must match this length 160 If minLength is not None, then instances of the field must be no shorter 162 If maxLength is not None, then instances of the field must be no longer 165 Additionally users can provide two check functions: 166 listCheck - used to validate the list as a whole, and 167 itemCheck - used to validate each item individually 169 def __init__(self, doc, dtype, default=None, optional=False,
170 listCheck=None, itemCheck=None,
171 length=None, minLength=None, maxLength=None):
172 if dtype
not in Field.supportedTypes:
173 raise ValueError(
"Unsupported dtype %s" % _typeStr(dtype))
174 if length
is not None:
176 raise ValueError(
"'length' (%d) must be positive" % length)
180 if maxLength
is not None and maxLength <= 0:
181 raise ValueError(
"'maxLength' (%d) must be positive" % maxLength)
182 if minLength
is not None and maxLength
is not None \
183 and minLength > maxLength:
184 raise ValueError(
"'maxLength' (%d) must be at least" 185 " as large as 'minLength' (%d)" % (maxLength, minLength))
187 if listCheck
is not None and not hasattr(listCheck,
"__call__"):
188 raise ValueError(
"'listCheck' must be callable")
189 if itemCheck
is not None and not hasattr(itemCheck,
"__call__"):
190 raise ValueError(
"'itemCheck' must be callable")
193 self.
_setup(doc=doc, dtype=List, default=default, check=
None, optional=optional, source=source)
203 ListField validation ensures that non-optional fields are not None, 204 and that non-None values comply with length requirements and 205 that the list passes listCheck if supplied by the user. 206 Individual Item checks are applied at set time and are not re-checked. 208 Field.validate(self, instance)
210 if value
is not None:
211 lenValue = len(value)
212 if self.
length is not None and not lenValue == self.
length:
213 msg =
"Required list length=%d, got length=%d" % (self.
length, lenValue)
216 msg =
"Minimum allowed list length=%d, got length=%d" % (self.
minLength, lenValue)
219 msg =
"Maximum allowed list length=%d, got length=%d" % (self.
maxLength, lenValue)
222 msg =
"%s is not a valid value" % str(value)
225 def __set__(self, instance, value, at=None, label="assignment"):
232 if value
is not None:
233 value =
List(instance, self, value, at, label)
235 history = instance._history.setdefault(self.name, [])
236 history.append((value, at, label))
238 instance._storage[self.name] = value
242 return list(value)
if value
is not None else None 244 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
245 """Helper function for Config.compare; used to compare two fields for equality. 247 @param[in] instance1 LHS Config instance to compare. 248 @param[in] instance2 RHS Config instance to compare. 249 @param[in] shortcut If True, return as soon as an inequality is found. 250 @param[in] rtol Relative tolerance for floating point comparisons. 251 @param[in] atol Absolute tolerance for floating point comparisons. 252 @param[in] output If not None, a callable that takes a string, used (possibly repeatedly) 253 to report inequalities. 255 Floating point comparisons are performed by numpy.allclose; refer to that for details. 257 l1 = getattr(instance1, self.name)
258 l2 = getattr(instance2, self.name)
260 _joinNamePath(instance1._name, self.name),
261 _joinNamePath(instance2._name, self.name)
263 if not compareScalars(
"isnone for %s" % name, l1
is None, l2
is None, output=output):
265 if l1
is None and l2
is None:
267 if not compareScalars(
"size for %s" % name, len(l1), len(l2), output=output):
270 for n, v1, v2
in zip(range(len(l1)), l1, l2):
272 rtol=rtol, atol=atol, output=output)
273 if not result
and shortcut:
275 equal = equal
and result
def __init__(self, doc, dtype, default=None, optional=False, listCheck=None, itemCheck=None, length=None, minLength=None, maxLength=None)
def validate(self, instance)
def validateItem(self, i, x)
def __setitem__(self, i, x, at=None, label="setitem", setHistory=True)
def __get__(self, instance, owner=None, at=None, label="default")
def insert(self, i, x, at=None, label="insert", setHistory=True)
def __init__(self, config, field, value, at, label, setHistory=True)
def _setup(self, doc, dtype, default, check, optional, source)
def __setattr__(self, attr, value, at=None, label="assignment")
def getStackFrame(relative=0)
def __delitem__(self, i, at=None, label="delitem", setHistory=True)
def toDict(self, instance)
def compareScalars(name, v1, v2, output, rtol=1E-8, atol=1E-8, dtype=None)
def __set__(self, instance, value, at=None, label="assignment")
def __contains__(self, x)
def getComparisonName(name1, name2)