23 __all__ = [
"ListField"]
27 from .config
import Field, FieldValidationError, _typeStr, _autocast, _joinNamePath
28 from .comparison
import compareScalars, getComparisonName
29 from .callStack
import getCallStack, getStackFrame
32 class List(collections.MutableSequence):
33 def __init__(self, config, field, value, at, label, setHistory=True):
41 for i, x
in enumerate(value):
42 self.
insert(i, x, setHistory=
False)
44 msg =
"Value %s is of incorrect type %s. Sequence type expected" % (value, _typeStr(value))
51 if not isinstance(x, self.
_field.itemtype)
and x
is not None:
52 msg =
"Item at position %d with value %s is of incorrect type %s. Expected %s" % \
53 (i, x, _typeStr(x), _typeStr(self.
_field.itemtype))
56 if self.
_field.itemCheck
is not None and not self.
_field.itemCheck(x):
57 msg =
"Item at position %d is not a valid value: %s" % (i, x)
66 history = property(
lambda x: x._history)
69 return x
in self.
_list 72 return len(self.
_list)
74 def __setitem__(self, i, x, at=None, label="setitem", setHistory=True):
77 "Cannot modify a frozen Config")
78 if isinstance(i, slice):
79 k, stop, step = i.indices(len(self))
80 for j, xj
in enumerate(x):
81 xj = _autocast(xj, self.
_field.itemtype)
86 x = _autocast(x, self.
_field.itemtype)
98 def __delitem__(self, i, at=None, label="delitem", setHistory=True):
101 "Cannot modify a frozen Config")
109 return iter(self.
_list)
111 def insert(self, i, x, at=None, label="insert", setHistory=True):
114 self.
__setitem__(slice(i, i), [x], at=at, label=label, setHistory=setHistory)
117 return repr(self.
_list)
120 return str(self.
_list)
124 if len(self) != len(other):
127 for i, j
in zip(self, other):
131 except AttributeError:
136 return not self.
__eq__(other)
139 if hasattr(getattr(self.__class__, attr,
None),
'__set__'):
141 object.__setattr__(self, attr, value)
142 elif attr
in self.__dict__
or attr
in [
"_field",
"_config",
"_history",
"_list",
"__doc__"]:
144 object.__setattr__(self, attr, value)
147 msg =
"%s has no attribute %s" % (_typeStr(self.
_field), attr)
153 Defines a field which is a container of values of type dtype 155 If length is not None, then instances of this field must match this length 157 If minLength is not None, then instances of the field must be no shorter 159 If maxLength is not None, then instances of the field must be no longer 162 Additionally users can provide two check functions: 163 listCheck - used to validate the list as a whole, and 164 itemCheck - used to validate each item individually 166 def __init__(self, doc, dtype, default=None, optional=False,
167 listCheck=None, itemCheck=None,
168 length=None, minLength=None, maxLength=None):
169 if dtype
not in Field.supportedTypes:
170 raise ValueError(
"Unsupported dtype %s" % _typeStr(dtype))
171 if length
is not None:
173 raise ValueError(
"'length' (%d) must be positive" % length)
177 if maxLength
is not None and maxLength <= 0:
178 raise ValueError(
"'maxLength' (%d) must be positive" % maxLength)
179 if minLength
is not None and maxLength
is not None \
180 and minLength > maxLength:
181 raise ValueError(
"'maxLength' (%d) must be at least" 182 " as large as 'minLength' (%d)" % (maxLength, minLength))
184 if listCheck
is not None and not hasattr(listCheck,
"__call__"):
185 raise ValueError(
"'listCheck' must be callable")
186 if itemCheck
is not None and not hasattr(itemCheck,
"__call__"):
187 raise ValueError(
"'itemCheck' must be callable")
190 self.
_setup(doc=doc, dtype=List, default=default, check=
None, optional=optional, source=source)
200 ListField validation ensures that non-optional fields are not None, 201 and that non-None values comply with length requirements and 202 that the list passes listCheck if supplied by the user. 203 Individual Item checks are applied at set time and are not re-checked. 205 Field.validate(self, instance)
207 if value
is not None:
208 lenValue = len(value)
209 if self.
length is not None and not lenValue == self.
length:
210 msg =
"Required list length=%d, got length=%d" % (self.
length, lenValue)
213 msg =
"Minimum allowed list length=%d, got length=%d" % (self.
minLength, lenValue)
216 msg =
"Maximum allowed list length=%d, got length=%d" % (self.
maxLength, lenValue)
219 msg =
"%s is not a valid value" % str(value)
222 def __set__(self, instance, value, at=None, label="assignment"):
229 if value
is not None:
230 value =
List(instance, self, value, at, label)
232 history = instance._history.setdefault(self.name, [])
233 history.append((value, at, label))
235 instance._storage[self.name] = value
239 return list(value)
if value
is not None else None 241 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
242 """Helper function for Config.compare; used to compare two fields for equality. 244 @param[in] instance1 LHS Config instance to compare. 245 @param[in] instance2 RHS Config instance to compare. 246 @param[in] shortcut If True, return as soon as an inequality is found. 247 @param[in] rtol Relative tolerance for floating point comparisons. 248 @param[in] atol Absolute tolerance for floating point comparisons. 249 @param[in] output If not None, a callable that takes a string, used (possibly repeatedly) 250 to report inequalities. 252 Floating point comparisons are performed by numpy.allclose; refer to that for details. 254 l1 = getattr(instance1, self.name)
255 l2 = getattr(instance2, self.name)
257 _joinNamePath(instance1._name, self.name),
258 _joinNamePath(instance2._name, self.name)
260 if not compareScalars(
"isnone for %s" % name, l1
is None, l2
is None, output=output):
262 if l1
is None and l2
is None:
264 if not compareScalars(
"size for %s" % name, len(l1), len(l2), output=output):
267 for n, v1, v2
in zip(range(len(l1)), l1, l2):
269 rtol=rtol, atol=atol, output=output)
270 if not result
and shortcut:
272 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)