22 __all__ = [
"ListField"]
24 import collections.abc
26 from .config
import Field, FieldValidationError, _typeStr, _autocast, _joinNamePath
27 from .comparison
import compareScalars, getComparisonName
28 from .callStack
import getCallStack, getStackFrame
31 class List(collections.abc.MutableSequence):
32 """List collection used internally by `ListField`. 36 config : `lsst.pex.config.Config` 37 Config instance that contains the ``field``. 39 Instance of the `ListField` using this ``List``. 41 Sequence of values that are inserted into this ``List``. 42 at : `list` of `lsst.pex.config.callStack.StackFrame` 43 The call stack (created by `lsst.pex.config.callStack.getCallStack`). 45 Event label for the history. 46 setHistory : `bool`, optional 47 Enable setting the field's history, using the value of the ``at`` 48 parameter. Default is `True`. 53 Raised if an item in the ``value`` parameter does not have the 54 appropriate type for this field or does not pass the 55 `ListField.itemCheck` method of the ``field`` parameter. 58 def __init__(self, config, field, value, at, label, setHistory=True):
66 for i, x
in enumerate(value):
67 self.
insert(i, x, setHistory=
False)
69 msg =
"Value %s is of incorrect type %s. Sequence type expected" % (value, _typeStr(value))
75 """Validate an item to determine if it can be included in the list. 80 Index of the item in the `list`. 87 Raised if an item in the ``value`` parameter does not have the 88 appropriate type for this field or does not pass the field's 89 `ListField.itemCheck` method. 92 if not isinstance(x, self.
_field.itemtype)
and x
is not None:
93 msg =
"Item at position %d with value %s is of incorrect type %s. Expected %s" % \
94 (i, x, _typeStr(x), _typeStr(self.
_field.itemtype))
97 if self.
_field.itemCheck
is not None and not self.
_field.itemCheck(x):
98 msg =
"Item at position %d is not a valid value: %s" % (i, x)
102 """Sequence of items contained by the `List` (`list`). 106 history = property(
lambda x: x._history)
107 """Read-only history. 111 return x
in self.
_list 114 return len(self.
_list)
116 def __setitem__(self, i, x, at=None, label="setitem", setHistory=True):
119 "Cannot modify a frozen Config")
120 if isinstance(i, slice):
121 k, stop, step = i.indices(len(self))
122 for j, xj
in enumerate(x):
123 xj = _autocast(xj, self.
_field.itemtype)
128 x = _autocast(x, self.
_field.itemtype)
140 def __delitem__(self, i, at=None, label="delitem", setHistory=True):
143 "Cannot modify a frozen Config")
151 return iter(self.
_list)
153 def insert(self, i, x, at=None, label="insert", setHistory=True):
154 """Insert an item into the list at the given index. 159 Index where the item is inserted. 161 Item that is inserted. 162 at : `list` of `lsst.pex.config.callStack.StackFrame`, optional 163 The call stack (created by 164 `lsst.pex.config.callStack.getCallStack`). 165 label : `str`, optional 166 Event label for the history. 167 setHistory : `bool`, optional 168 Enable setting the field's history, using the value of the ``at`` 169 parameter. Default is `True`. 173 self.
__setitem__(slice(i, i), [x], at=at, label=label, setHistory=setHistory)
176 return repr(self.
_list)
179 return str(self.
_list)
183 if len(self) != len(other):
186 for i, j
in zip(self, other):
190 except AttributeError:
195 return not self.
__eq__(other)
198 if hasattr(getattr(self.__class__, attr,
None),
'__set__'):
200 object.__setattr__(self, attr, value)
201 elif attr
in self.__dict__
or attr
in [
"_field",
"_config",
"_history",
"_list",
"__doc__"]:
203 object.__setattr__(self, attr, value)
206 msg =
"%s has no attribute %s" % (_typeStr(self.
_field), attr)
211 """A configuration field (`~lsst.pex.config.Field` subclass) that contains 212 a list of values of a specific type. 217 A description of the field. 219 The data type of items in the list. 220 default : sequence, optional 221 The default items for the field. 222 optional : `bool`, optional 223 Set whether the field is *optional*. When `False`, 224 `lsst.pex.config.Config.validate` will fail if the field's value is 226 listCheck : callable, optional 227 A callable that validates the list as a whole. 228 itemCheck : callable, optional 229 A callable that validates individual items in the list. 230 length : `int`, optional 231 If set, this field must contain exactly ``length`` number of items. 232 minLength : `int`, optional 233 If set, this field must contain *at least* ``minLength`` number of 235 maxLength : `int`, optional 236 If set, this field must contain *no more than* ``maxLength`` number of 238 deprecated : None or `str`, optional 239 A description of why this Field is deprecated, including removal date. 240 If not None, the string is appended to the docstring for this Field. 254 def __init__(self, doc, dtype, default=None, optional=False,
255 listCheck=None, itemCheck=None,
256 length=None, minLength=None, maxLength=None,
258 if dtype
not in Field.supportedTypes:
259 raise ValueError(
"Unsupported dtype %s" % _typeStr(dtype))
260 if length
is not None:
262 raise ValueError(
"'length' (%d) must be positive" % length)
266 if maxLength
is not None and maxLength <= 0:
267 raise ValueError(
"'maxLength' (%d) must be positive" % maxLength)
268 if minLength
is not None and maxLength
is not None \
269 and minLength > maxLength:
270 raise ValueError(
"'maxLength' (%d) must be at least" 271 " as large as 'minLength' (%d)" % (maxLength, minLength))
273 if listCheck
is not None and not hasattr(listCheck,
"__call__"):
274 raise ValueError(
"'listCheck' must be callable")
275 if itemCheck
is not None and not hasattr(itemCheck,
"__call__"):
276 raise ValueError(
"'itemCheck' must be callable")
279 self.
_setup(doc=doc, dtype=List, default=default, check=
None, optional=optional, source=source,
280 deprecated=deprecated)
283 """Callable used to check the list as a whole. 287 """Callable used to validate individual items as they are inserted 292 """Data type of list items. 296 """Number of items that must be present in the list (or `None` to 297 disable checking the list's length). 301 """Minimum number of items that must be present in the list (or `None` 302 to disable checking the list's minimum length). 306 """Maximum number of items that must be present in the list (or `None` 307 to disable checking the list's maximum length). 311 """Validate the field. 315 instance : `lsst.pex.config.Config` 316 The config instance that contains this field. 320 lsst.pex.config.FieldValidationError 323 - The field is not optional, but the value is `None`. 324 - The list itself does not meet the requirements of the `length`, 325 `minLength`, or `maxLength` attributes. 326 - The `listCheck` callable returns `False`. 330 Individual item checks (`itemCheck`) are applied when each item is 331 set and are not re-checked by this method. 333 Field.validate(self, instance)
335 if value
is not None:
336 lenValue = len(value)
337 if self.
length is not None and not lenValue == self.
length:
338 msg =
"Required list length=%d, got length=%d" % (self.
length, lenValue)
341 msg =
"Minimum allowed list length=%d, got length=%d" % (self.
minLength, lenValue)
344 msg =
"Maximum allowed list length=%d, got length=%d" % (self.
maxLength, lenValue)
347 msg =
"%s is not a valid value" % str(value)
350 def __set__(self, instance, value, at=None, label="assignment"):
357 if value
is not None:
358 value =
List(instance, self, value, at, label)
360 history = instance._history.setdefault(self.name, [])
361 history.append((value, at, label))
363 instance._storage[self.name] = value
366 """Convert the value of this field to a plain `list`. 368 `lsst.pex.config.Config.toDict` is the primary user of this method. 372 instance : `lsst.pex.config.Config` 373 The config instance that contains this field. 378 Plain `list` of items, or `None` if the field is not set. 381 return list(value)
if value
is not None else None 383 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
384 """Compare two config instances for equality with respect to this 387 `lsst.pex.config.config.compare` is the primary user of this method. 391 instance1 : `lsst.pex.config.Config` 392 Left-hand-side `~lsst.pex.config.Config` instance in the 394 instance2 : `lsst.pex.config.Config` 395 Right-hand-side `~lsst.pex.config.Config` instance in the 398 If `True`, return as soon as an **inequality** is found. 400 Relative tolerance for floating point comparisons. 402 Absolute tolerance for floating point comparisons. 404 If not None, a callable that takes a `str`, used (possibly 405 repeatedly) to report inequalities. 410 `True` if the fields are equal; `False` otherwise. 414 Floating point comparisons are performed by `numpy.allclose`. 416 l1 = getattr(instance1, self.name)
417 l2 = getattr(instance2, self.name)
419 _joinNamePath(instance1._name, self.name),
420 _joinNamePath(instance2._name, self.name)
422 if not compareScalars(
"isnone for %s" % name, l1
is None, l2
is None, output=output):
424 if l1
is None and l2
is None:
426 if not compareScalars(
"size for %s" % name, len(l1), len(l2), output=output):
429 for n, v1, v2
in zip(range(len(l1)), l1, l2):
431 rtol=rtol, atol=atol, output=output)
432 if not result
and shortcut:
434 equal = equal
and result
def __set__(self, instance, value, at=None, label="assignment")
def validate(self, instance)
def __init__(self, config, field, value, at, label, setHistory=True)
def insert(self, i, x, at=None, label="insert", setHistory=True)
def __contains__(self, x)
def getStackFrame(relative=0)
def toDict(self, instance)
def __setattr__(self, attr, value, at=None, label="assignment")
def __get__(self, instance, owner=None, at=None, label="default")
def validateItem(self, i, x)
def __setitem__(self, i, x, at=None, label="setitem", setHistory=True)
def getComparisonName(name1, name2)
def __init__(self, doc, dtype, default=None, optional=False, listCheck=None, itemCheck=None, length=None, minLength=None, maxLength=None, deprecated=None)
def compareScalars(name, v1, v2, output, rtol=1E-8, atol=1E-8, dtype=None)
def __delitem__(self, i, at=None, label="delitem", setHistory=True)
def _setup(self, doc, dtype, default, check, optional, source, deprecated)