28__all__ = [
"ConfigField"]
30from typing
import Any, Optional, overload
32from .callStack
import getCallStack, getStackFrame
33from .comparison
import compareConfigs, getComparisonName
34from .config
import Config, Field, FieldTypeVar, FieldValidationError, _joinNamePath, _typeStr
38 """A configuration field (`~lsst.pex.config.Field` subclass) that takes a
44 A description of the configuration field.
46 The type of the field, which must be a subclass of
49 If default
is `
None`, the field will default to a default-constructed
50 instance of ``dtype``. Additionally, to allow
for fewer deep-copies,
51 assigning an instance of ``ConfigField`` to ``dtype`` itself,
is
52 considered equivalent to assigning a default-constructed sub-config.
53 This means that the argument default can be ``dtype``,
as well
as an
54 instance of ``dtype``.
55 check : callable, optional
56 A callback function that validates the field
's value, returning `True`
57 if the value
is valid,
and `
False` otherwise.
58 deprecated :
None or `str`, optional
59 A description of why this Field
is deprecated, including removal date.
60 If
not None, the string
is appended to the docstring
for this Field.
76 The behavior of this type of field
is much like that of the base `Field`
79 Assigning to ``ConfigField`` will update all of the fields
in the
83 def __init__(self, doc, dtype=None, default=None, check=None, deprecated=None):
84 if dtype
is None or not issubclass(dtype, Config):
85 raise ValueError(
"dtype=%s is not a subclass of Config" % _typeStr(dtype))
88 source = getStackFrame()
96 deprecated=deprecated,
101 self, instance: None, owner: Any =
None, at: Any =
None, label: str =
"default"
102 ) ->
"ConfigField[FieldTypeVar]":
107 self, instance: Config, owner: Any =
None, at: Any =
None, label: str =
"default"
111 def __get__(self, instance, owner=None, at=None, label="default"):
112 if instance
is None or not isinstance(instance, Config):
115 value = instance._storage.get(self.name,
None)
123 self, instance: Config, value: Optional[FieldTypeVar], at: Any =
None, label: str =
"assignment"
127 name = _joinNamePath(prefix=instance._name, name=self.name)
130 msg =
"Value %s is of incorrect type %s. Expected %s" % (
133 _typeStr(self.
dtype),
140 oldValue = instance._storage.get(self.name,
None)
142 if value == self.
dtype:
143 instance._storage[self.name] = self.
dtype(__name=name, __at=at, __label=label)
145 instance._storage[self.name] = self.
dtype(
146 __name=name, __at=at, __label=label, **value._storage
149 if value == self.
dtype:
151 oldValue.update(__at=at, __label=label, **value._storage)
152 history = instance._history.setdefault(self.name, [])
153 history.append((
"config value set", at, label))
156 """Rename the field in a `~lsst.pex.config.Config` (for internal use
162 The config instance that contains this field.
167 contains this field
and should
not be called directly.
170 hold subconfigs. `~lsst.pex.config.Fields` that hold subconfigs should
171 rename each subconfig
with the full field name
as generated by
172 `lsst.pex.config.config._joinNamePath`.
175 value._rename(_joinNamePath(instance._name, self.name))
177 def _collectImports(self, instance, imports):
179 value._collectImports()
180 imports |= value._imports
182 def save(self, outfile, instance):
183 """Save this field to a file (for internal use only).
187 outfile : file-like object
188 A writeable field handle.
190 The `Config` instance that contains this field.
195 contains this field
and should
not be called directly.
197 The output consists of the documentation string
198 (`lsst.pex.config.Field.doc`) formatted
as a Python comment. The second
199 line
is formatted
as an assignment: ``{fullname}={value}``.
201 This output can be executed
with Python.
207 """Make this field read-only.
212 The config instance that contains this field.
216 Freezing is only relevant
for fields that hold subconfigs. Fields which
217 hold subconfigs should freeze each subconfig.
219 **Subclasses should implement this method.**
225 """Convert the field value so that it can be set as the value of an
226 item in a `dict` (
for internal use only).
231 The `Config` that contains this field.
236 The field
's value. See *Notes*.
241 should
not be called directly.
243 Simple values are passed through. Complex data structures must be
245 subconfig should, instead of the subconfig object,
return a `dict`
246 where the keys are the field names
in the subconfig,
and the values are
247 the field values
in the subconfig.
250 return value.toDict()
253 """Validate the field (for internal use only).
258 The config instance that contains this field.
263 Raised if verification fails.
267 This method provides basic validation:
269 - Ensures that the value
is not `
None`
if the field
is not optional.
270 - Ensures type correctness.
271 - Ensures that the user-provided ``check`` function
is valid.
274 `lsst.pex.config.field.Field.validate`
if they re-implement
275 `~lsst.pex.config.field.Field.validate`.
280 if self.
check is not None and not self.
check(value):
281 msg =
"%s is not a valid value" %
str(value)
284 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
285 """Compare two fields for equality.
287 Used by `ConfigField.compare`.
292 Left-hand side config instance to compare.
294 Right-hand side config instance to compare.
296 If `True`, this function returns
as soon
as an inequality
if found.
298 Relative tolerance
for floating point comparisons.
300 Absolute tolerance
for floating point comparisons.
302 A callable that takes a string, used (possibly repeatedly) to
308 `
True`
if the fields are equal, `
False` otherwise.
312 Floating point comparisons are performed by `numpy.allclose`.
314 c1 = getattr(instance1, self.name)
315 c2 = getattr(instance2, self.name)
316 name = getComparisonName(
317 _joinNamePath(instance1._name, self.name), _joinNamePath(instance2._name, self.name)
319 return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
"Field[FieldTypeVar]" __get__(self, None instance, Any owner=None, Any at=None, str label="default")
None __set__(self, "Config" instance, Optional[FieldTypeVar] value, Any at=None, str label="assignment")
def __get__(self, instance, owner=None, at=None, label="default")
FieldTypeVar __get__(self, "Config" instance, Any owner=None, Any at=None, str label="default")
def _setup(self, doc, dtype, default, check, optional, source, deprecated)
def __init__(self, doc, dtype=None, default=None, check=None, deprecated=None)
def rename(self, instance)
"ConfigField[FieldTypeVar]" __get__(self, None instance, Any owner=None, Any at=None, str label="default")
def freeze(self, instance)
def toDict(self, instance)
FieldTypeVar __get__(self, Config instance, Any owner=None, Any at=None, str label="default")
def save(self, outfile, instance)
def __get__(self, instance, owner=None, at=None, label="default")
None __set__(self, Config instance, Optional[FieldTypeVar] value, Any at=None, str label="assignment")