28 __all__ = [
"ListField"]
32 from .config
import Field, FieldValidationError, _typeStr, _autocast, _joinNamePath, Config
33 from .comparison
import compareScalars, getComparisonName
34 from .callStack
import getCallStack, getStackFrame
39 class List(collections.abc.MutableSequence):
40 """List collection used internally by `ListField`.
44 config : `lsst.pex.config.Config`
45 Config instance that contains the ``field``.
47 Instance of the `ListField` using this ``List``.
49 Sequence of values that are inserted into this ``List``.
50 at : `list` of `lsst.pex.config.callStack.StackFrame`
51 The call stack (created by `lsst.pex.config.callStack.getCallStack`).
53 Event label for the history.
54 setHistory : `bool`, optional
55 Enable setting the field's history, using the value of the ``at``
56 parameter. Default is `True`.
61 Raised if an item in the ``value`` parameter does not have the
62 appropriate type for this field or does not pass the
63 `ListField.itemCheck` method of the ``field`` parameter.
66 def __init__(self, config, field, value, at, label, setHistory=True):
68 self.
_config__config_ = weakref.ref(config)
74 for i, x
in enumerate(value):
75 self.
insertinsert(i, x, setHistory=
False)
77 msg =
"Value %s is of incorrect type %s. Sequence type expected" % (value, _typeStr(value))
83 def _config(self) -> Config:
86 assert(self.
_config__config_()
is not None)
90 """Validate an item to determine if it can be included in the list.
95 Index of the item in the `list`.
102 Raised if an item in the ``value`` parameter does not have the
103 appropriate type for this field or does not pass the field's
104 `ListField.itemCheck` method.
107 if not isinstance(x, self.
_field_field.itemtype)
and x
is not None:
108 msg =
"Item at position %d with value %s is of incorrect type %s. Expected %s" % \
109 (i, x, _typeStr(x), _typeStr(self.
_field_field.itemtype))
112 if self.
_field_field.itemCheck
is not None and not self.
_field_field.itemCheck(x):
113 msg =
"Item at position %d is not a valid value: %s" % (i, x)
117 """Sequence of items contained by the `List` (`list`).
119 return self.
_list_list
121 history = property(
lambda x: x._history)
122 """Read-only history.
126 return x
in self.
_list_list
129 return len(self.
_list_list)
131 def __setitem__(self, i, x, at=None, label="setitem", setHistory=True):
132 if self.
_config_config._frozen:
134 "Cannot modify a frozen Config")
135 if isinstance(i, slice):
136 k, stop, step = i.indices(len(self))
137 for j, xj
in enumerate(x):
138 xj = _autocast(xj, self.
_field_field.itemtype)
143 x = _autocast(x, self.
_field_field.itemtype)
146 self.
_list_list[i] = x
153 return self.
_list_list[i]
155 def __delitem__(self, i, at=None, label="delitem", setHistory=True):
156 if self.
_config_config._frozen:
158 "Cannot modify a frozen Config")
159 del self.
_list_list[i]
168 def insert(self, i, x, at=None, label="insert", setHistory=True):
169 """Insert an item into the list at the given index.
174 Index where the item is inserted.
176 Item that is inserted.
177 at : `list` of `lsst.pex.config.callStack.StackFrame`, optional
178 The call stack (created by
179 `lsst.pex.config.callStack.getCallStack`).
180 label : `str`, optional
181 Event label for the history.
182 setHistory : `bool`, optional
183 Enable setting the field's history, using the value of the ``at``
184 parameter. Default is `True`.
188 self.
__setitem____setitem__(slice(i, i), [x], at=at, label=label, setHistory=setHistory)
191 return repr(self.
_list_list)
194 return str(self.
_list_list)
198 if len(self) != len(other):
201 for i, j
in zip(self, other):
205 except AttributeError:
210 return not self.
__eq____eq__(other)
213 if hasattr(getattr(self.__class__, attr,
None),
'__set__'):
215 object.__setattr__(self, attr, value)
216 elif attr
in self.__dict__
or attr
in [
"_field",
"_config_",
"_history",
"_list",
"__doc__"]:
218 object.__setattr__(self, attr, value)
221 msg =
"%s has no attribute %s" % (_typeStr(self.
_field_field), attr)
226 """A configuration field (`~lsst.pex.config.Field` subclass) that contains
227 a list of values of a specific type.
232 A description of the field.
234 The data type of items in the list.
235 default : sequence, optional
236 The default items for the field.
237 optional : `bool`, optional
238 Set whether the field is *optional*. When `False`,
239 `lsst.pex.config.Config.validate` will fail if the field's value is
241 listCheck : callable, optional
242 A callable that validates the list as a whole.
243 itemCheck : callable, optional
244 A callable that validates individual items in the list.
245 length : `int`, optional
246 If set, this field must contain exactly ``length`` number of items.
247 minLength : `int`, optional
248 If set, this field must contain *at least* ``minLength`` number of
250 maxLength : `int`, optional
251 If set, this field must contain *no more than* ``maxLength`` number of
253 deprecated : None or `str`, optional
254 A description of why this Field is deprecated, including removal date.
255 If not None, the string is appended to the docstring for this Field.
269 def __init__(self, doc, dtype, default=None, optional=False,
270 listCheck=None, itemCheck=None,
271 length=None, minLength=None, maxLength=None,
273 if dtype
not in Field.supportedTypes:
274 raise ValueError(
"Unsupported dtype %s" % _typeStr(dtype))
275 if length
is not None:
277 raise ValueError(
"'length' (%d) must be positive" % length)
281 if maxLength
is not None and maxLength <= 0:
282 raise ValueError(
"'maxLength' (%d) must be positive" % maxLength)
283 if minLength
is not None and maxLength
is not None \
284 and minLength > maxLength:
285 raise ValueError(
"'maxLength' (%d) must be at least"
286 " as large as 'minLength' (%d)" % (maxLength, minLength))
288 if listCheck
is not None and not hasattr(listCheck,
"__call__"):
289 raise ValueError(
"'listCheck' must be callable")
290 if itemCheck
is not None and not hasattr(itemCheck,
"__call__"):
291 raise ValueError(
"'itemCheck' must be callable")
294 self.
_setup_setup(doc=doc, dtype=List, default=default, check=
None, optional=optional, source=source,
295 deprecated=deprecated)
298 """Callable used to check the list as a whole.
302 """Callable used to validate individual items as they are inserted
307 """Data type of list items.
311 """Number of items that must be present in the list (or `None` to
312 disable checking the list's length).
316 """Minimum number of items that must be present in the list (or `None`
317 to disable checking the list's minimum length).
321 """Maximum number of items that must be present in the list (or `None`
322 to disable checking the list's maximum length).
326 """Validate the field.
330 instance : `lsst.pex.config.Config`
331 The config instance that contains this field.
335 lsst.pex.config.FieldValidationError
338 - The field is not optional, but the value is `None`.
339 - The list itself does not meet the requirements of the `length`,
340 `minLength`, or `maxLength` attributes.
341 - The `listCheck` callable returns `False`.
345 Individual item checks (`itemCheck`) are applied when each item is
346 set and are not re-checked by this method.
348 Field.validate(self, instance)
349 value = self.
__get____get__(instance)
350 if value
is not None:
351 lenValue = len(value)
352 if self.
lengthlength
is not None and not lenValue == self.
lengthlength:
353 msg =
"Required list length=%d, got length=%d" % (self.
lengthlength, lenValue)
356 msg =
"Minimum allowed list length=%d, got length=%d" % (self.
minLengthminLength, lenValue)
359 msg =
"Maximum allowed list length=%d, got length=%d" % (self.
maxLengthmaxLength, lenValue)
362 msg =
"%s is not a valid value" % str(value)
365 def __set__(self, instance, value, at=None, label="assignment"):
372 if value
is not None:
373 value =
List(instance, self, value, at, label)
375 history = instance._history.setdefault(self.name, [])
376 history.append((value, at, label))
378 instance._storage[self.name] = value
381 """Convert the value of this field to a plain `list`.
383 `lsst.pex.config.Config.toDict` is the primary user of this method.
387 instance : `lsst.pex.config.Config`
388 The config instance that contains this field.
393 Plain `list` of items, or `None` if the field is not set.
395 value = self.
__get____get__(instance)
396 return list(value)
if value
is not None else None
398 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
399 """Compare two config instances for equality with respect to this
402 `lsst.pex.config.config.compare` is the primary user of this method.
406 instance1 : `lsst.pex.config.Config`
407 Left-hand-side `~lsst.pex.config.Config` instance in the
409 instance2 : `lsst.pex.config.Config`
410 Right-hand-side `~lsst.pex.config.Config` instance in the
413 If `True`, return as soon as an **inequality** is found.
415 Relative tolerance for floating point comparisons.
417 Absolute tolerance for floating point comparisons.
419 If not None, a callable that takes a `str`, used (possibly
420 repeatedly) to report inequalities.
425 `True` if the fields are equal; `False` otherwise.
429 Floating point comparisons are performed by `numpy.allclose`.
431 l1 = getattr(instance1, self.name)
432 l2 = getattr(instance2, self.name)
434 _joinNamePath(instance1._name, self.name),
435 _joinNamePath(instance2._name, self.name)
437 if not compareScalars(
"isnone for %s" % name, l1
is None, l2
is None, output=output):
439 if l1
is None and l2
is None:
441 if not compareScalars(
"size for %s" % name, len(l1), len(l2), output=output):
444 for n, v1, v2
in zip(range(len(l1)), l1, l2):
446 rtol=rtol, atol=atol, output=output)
447 if not result
and shortcut:
449 equal = equal
and result
def __get__(self, instance, owner=None, at=None, label="default")
def _setup(self, doc, dtype, default, check, optional, source, deprecated)
def __init__(self, doc, dtype, default=None, optional=False, listCheck=None, itemCheck=None, length=None, minLength=None, maxLength=None, deprecated=None)
def toDict(self, instance)
def __set__(self, instance, value, at=None, label="assignment")
def validate(self, instance)
def __delitem__(self, i, at=None, label="delitem", setHistory=True)
def __setattr__(self, attr, value, at=None, label="assignment")
def __contains__(self, x)
def __init__(self, config, field, value, at, label, setHistory=True)
def insert(self, i, x, at=None, label="insert", setHistory=True)
def __setitem__(self, i, x, at=None, label="setitem", setHistory=True)
def validateItem(self, i, x)
daf::base::PropertyList * list
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
def getStackFrame(relative=0)
def compareScalars(name, v1, v2, output, rtol=1E-8, atol=1E-8, dtype=None)
def getComparisonName(name1, name2)