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)
70 history = property(
lambda x: x._history)
73 return x
in self.
_list 76 return len(self.
_list)
78 def __setitem__(self, i, x, at=None, label="setitem", setHistory=True):
81 "Cannot modify a frozen Config")
82 if isinstance(i, slice):
83 k, stop, step = i.indices(len(self))
84 for j, xj
in enumerate(x):
85 xj = _autocast(xj, self.
_field.itemtype)
90 x = _autocast(x, self.
_field.itemtype)
102 def __delitem__(self, i, at=None, label="delitem", setHistory=True):
105 "Cannot modify a frozen Config")
113 return iter(self.
_list)
115 def insert(self, i, x, at=None, label="insert", setHistory=True):
118 self.
__setitem__(slice(i, i), [x], at=at, label=label, setHistory=setHistory)
121 return repr(self.
_list)
124 return str(self.
_list)
128 if len(self) != len(other):
131 for i, j
in zip(self, other):
135 except AttributeError:
140 return not self.
__eq__(other)
143 if hasattr(getattr(self.__class__, attr,
None),
'__set__'):
145 object.__setattr__(self, attr, value)
146 elif attr
in self.__dict__
or attr
in [
"_field",
"_config",
"_history",
"_list",
"__doc__"]:
148 object.__setattr__(self, attr, value)
151 msg =
"%s has no attribute %s" % (_typeStr(self.
_field), attr)
157 Defines a field which is a container of values of type dtype 159 If length is not None, then instances of this field must match this length 161 If minLength is not None, then instances of the field must be no shorter 163 If maxLength is not None, then instances of the field must be no longer 166 Additionally users can provide two check functions: 167 listCheck - used to validate the list as a whole, and 168 itemCheck - used to validate each item individually 170 def __init__(self, doc, dtype, default=None, optional=False,
171 listCheck=None, itemCheck=None,
172 length=None, minLength=None, maxLength=None):
173 if dtype
not in Field.supportedTypes:
174 raise ValueError(
"Unsupported dtype %s" % _typeStr(dtype))
175 if length
is not None:
177 raise ValueError(
"'length' (%d) must be positive" % length)
181 if maxLength
is not None and maxLength <= 0:
182 raise ValueError(
"'maxLength' (%d) must be positive" % maxLength)
183 if minLength
is not None and maxLength
is not None \
184 and minLength > maxLength:
185 raise ValueError(
"'maxLength' (%d) must be at least" 186 " as large as 'minLength' (%d)" % (maxLength, minLength))
188 if listCheck
is not None and not hasattr(listCheck,
"__call__"):
189 raise ValueError(
"'listCheck' must be callable")
190 if itemCheck
is not None and not hasattr(itemCheck,
"__call__"):
191 raise ValueError(
"'itemCheck' must be callable")
194 self.
_setup(doc=doc, dtype=List, default=default, check=
None, optional=optional, source=source)
204 ListField validation ensures that non-optional fields are not None, 205 and that non-None values comply with length requirements and 206 that the list passes listCheck if supplied by the user. 207 Individual Item checks are applied at set time and are not re-checked. 209 Field.validate(self, instance)
211 if value
is not None:
212 lenValue = len(value)
213 if self.
length is not None and not lenValue == self.
length:
214 msg =
"Required list length=%d, got length=%d" % (self.
length, lenValue)
217 msg =
"Minimum allowed list length=%d, got length=%d" % (self.
minLength, lenValue)
220 msg =
"Maximum allowed list length=%d, got length=%d" % (self.
maxLength, lenValue)
223 msg =
"%s is not a valid value" % str(value)
226 def __set__(self, instance, value, at=None, label="assignment"):
233 if value
is not None:
234 value =
List(instance, self, value, at, label)
236 history = instance._history.setdefault(self.name, [])
237 history.append((value, at, label))
239 instance._storage[self.name] = value
243 return list(value)
if value
is not None else None 245 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
246 """Helper function for Config.compare; used to compare two fields for equality. 248 @param[in] instance1 LHS Config instance to compare. 249 @param[in] instance2 RHS Config instance to compare. 250 @param[in] shortcut If True, return as soon as an inequality is found. 251 @param[in] rtol Relative tolerance for floating point comparisons. 252 @param[in] atol Absolute tolerance for floating point comparisons. 253 @param[in] output If not None, a callable that takes a string, used (possibly repeatedly) 254 to report inequalities. 256 Floating point comparisons are performed by numpy.allclose; refer to that for details. 258 l1 = getattr(instance1, self.name)
259 l2 = getattr(instance2, self.name)
261 _joinNamePath(instance1._name, self.name),
262 _joinNamePath(instance2._name, self.name)
264 if not compareScalars(
"isnone for %s" % name, l1
is None, l2
is None, output=output):
266 if l1
is None and l2
is None:
268 if not compareScalars(
"size for %s" % name, len(l1), len(l2), output=output):
271 for n, v1, v2
in zip(range(len(l1)), l1, l2):
273 rtol=rtol, atol=atol, output=output)
274 if not result
and shortcut:
276 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)