21from __future__
import annotations
23__all__ = (
"ConfigurableActionStructField",
"ConfigurableActionStruct")
27from types
import GenericAlias, SimpleNamespace
28from typing
import Any, Generic, TypeVar, overload
34from .
import ActionTypeVar, ConfigurableAction
38 """Abstract the logic of using a dictionary to update a
39 `ConfigurableActionStruct` through attribute assignment.
41 This is useful in the context of setting configuration through pipelines
42 or on the command line.
47 instance: ConfigurableActionStruct,
48 value: Mapping[str, ConfigurableAction] | ConfigurableActionStruct,
50 if isinstance(value, Mapping):
52 elif isinstance(value, ConfigurableActionStruct):
58 "Can only update a ConfigurableActionStruct with an instance of such, or a " "mapping"
60 for name, action
in value.items():
61 setattr(instance, name, action)
63 def __get__(self, instance, objtype=None) -> None:
69 """Abstract the logic of removing an iterable of action names from a
70 `ConfigurableActionStruct` at one time using attribute assignment.
72 This is useful in the context of setting configuration through pipelines
73 or on the command line.
78 Raised if an attribute specified for removal does not exist in the
79 ConfigurableActionStruct
82 def __set__(self, instance: ConfigurableActionStruct, value: str | Iterable[str]) ->
None:
86 if isinstance(value, str):
89 delattr(instance, name)
91 def __get__(self, instance, objtype=None) -> None:
97 """A ConfigurableActionStruct is the storage backend class that supports
98 the ConfigurableActionStructField. This class should not be created
101 This class allows managing a collection of `ConfigurableAction` with a
102 struct like interface, that is to say in an attribute like notation.
106 config : `~lsst.pex.config.Config`
108 field : `ConfigurableActionStructField`
110 value : `~collections.abc.Mapping` [`str`, `ConfigurableAction`]
112 at : `list` of `~lsst.pex.config.callStack.StackFrame` or `None`, optional
113 Stack frames to use for history recording.
114 label : `str`, optional
115 Label to use for history recording.
119 Attributes can be dynamically added or removed as such:
121 .. code-block:: python
123 ConfigurableActionStructInstance.variable1 = a_configurable_action
124 del ConfigurableActionStructInstance.variable1
126 Each action is then available to be individually configured as a normal
127 `lsst.pex.config.Config` object.
129 `ConfigurableActionStruct` supports two special convenience attributes.
131 The first is ``update``. You may assign a dict of `ConfigurableAction` or a
132 `ConfigurableActionStruct` to this attribute which will update the
133 `ConfigurableActionStruct` on which the attribute is invoked such that it
134 will be updated to contain the entries specified by the structure on the
135 right hand side of the equals sign.
137 The second convenience attribute is named ``remove``. You may assign an
138 iterable of strings which correspond to attribute names on the
139 `ConfigurableActionStruct`. All of the corresponding attributes will then
140 be removed. If any attribute does not exist, an `AttributeError` will be
141 raised. Any attributes in the Iterable prior to the name which raises will
142 have been removed from the `ConfigurableActionStruct`
146 _config_: weakref.ref
147 _attrs: dict[str, ActionTypeVar]
148 _field: ConfigurableActionStructField
149 _history: list[tuple]
158 field: ConfigurableActionStructField,
159 value: Mapping[str, ConfigurableAction],
163 object.__setattr__(self,
"_config_", weakref.ref(config))
164 object.__setattr__(self,
"_attrs", {})
165 object.__setattr__(self,
"_field", field)
166 object.__setattr__(self,
"_history", [])
168 self.
history.append((
"Struct initialized", at, label))
170 if value
is not None:
171 for k, v
in value.items():
179 assert value
is not None
183 def history(self) -> list[tuple]:
193 value: ActionTypeVar | type[ActionTypeVar],
199 msg =
"Cannot modify a frozen Config. " f
"Attempting to set item {attr} to value {value}"
204 if not attr.isidentifier():
205 raise ValueError(
"Names used in ConfigurableStructs must be valid as python variable names")
207 if attr
not in (self.__dict__.keys() | type(self).__dict__.keys()):
209 name = _joinNamePath(base_name, attr)
212 if isinstance(value, ConfigurableAction):
213 valueInst = type(value)(__name=name, __at=at, __label=label, **value._storage)
215 valueInst = value(__name=name, __at=at, __label=label)
221 if attr
in object.__getattribute__(self,
"_attrs"):
223 result.identity = attr
226 super().__getattribute__(attr)
236 yield getattr(self, name)
238 def items(self) -> Iterable[tuple[str, ActionTypeVar]]:
240 yield name, getattr(self, name)
246T = TypeVar(
"T", bound=
"ConfigurableActionStructField")
250 """`ConfigurableActionStructField` is a `~lsst.pex.config.Field` subclass
251 that allows a `ConfigurableAction` to be organized in a
252 `~lsst.pex.config.Config` class in a manner similar to how a
253 `~lsst.pipe.base.Struct` works.
255 This class uses a `ConfigurableActionStruct` as an intermediary object to
256 organize the `ConfigurableAction`. See its documentation for further
262 Documentation string.
263 default : `~collections.abc.Mapping` [ `str`, `ConfigurableAction` ] \
266 optional : `bool`, optional
267 If `True`, the field doesn't need to have a set value.
268 deprecated : `bool` or `None`, optional
269 A description of why this Field is deprecated, including removal date.
270 If not `None`, the string is appended to the docstring for this Field.
275 StructClass = ConfigurableActionStruct
280 default: Mapping[str, ConfigurableAction] |
None
285 default: Mapping[str, ConfigurableAction] |
None =
None,
286 optional: bool =
False,
289 source = getStackFrame()
292 dtype=self.__class__,
297 deprecated=deprecated,
301 return GenericAlias(cls, params)
308 | Mapping[str, ConfigurableAction]
310 | ConfigurableActionStruct
311 | ConfigurableActionStructField
312 | type[ConfigurableActionStructField]
314 at: Iterable[StackFrame] =
None,
315 label: str =
"assigment",
318 msg =
"Cannot modify a frozen Config. " "Attempting to set field to value %s" % value
325 value = self.
StructClass(instance, self, value, at=at, label=label)
331 value = self.
StructClass(instance, self, value._attrs, at=at, label=label)
332 elif isinstance(value, SimpleNamespace):
335 value = self.
StructClass(instance, self, vars(value), at=at, label=label)
337 elif type(value)
is ConfigurableActionStructField:
339 "ConfigurableActionStructFields can only be used in a class body declaration"
340 f
"Use a {self.StructClass}, SimpleNamespace or Struct"
343 raise ValueError(f
"Unrecognized value {value}, cannot be assigned to this field")
346 history.append((value, at, label))
348 if not isinstance(value, ConfigurableActionStruct):
350 self, instance,
"Can only assign things that are subclasses of Configurable Action"
356 self, instance: None, owner: Any =
None, at: Any =
None, label: str =
"default"
357 ) -> ConfigurableActionStruct[ActionTypeVar]: ...
361 self, instance: Config, owner: Any =
None, at: Any =
None, label: str =
"default"
362 ) -> ConfigurableActionStruct[ActionTypeVar]: ...
364 def __get__(self, instance, owner=None, at=None, label="default"):
365 if instance
is None or not isinstance(instance, Config):
368 field: ConfigurableActionStruct |
None = instance._storage[self.
namenamenamename]
373 if actionStruct
is not None:
374 for k, v
in actionStruct.items():
376 fullname = _joinNamePath(base_name, k)
381 if value
is not None:
387 if actionStruct
is None:
390 dict_ = {k: v.toDict()
for k, v
in actionStruct.items()}
394 def save(self, outfile, instance):
399 outfile.write(f
"{fullname}=None\n")
401 if actionStruct
is None:
404 for _, v
in sorted(actionStruct.items()):
405 outfile.write(f
"{v._name}={_typeStr(v)}()\n")
410 if actionStruct
is not None:
411 for v
in actionStruct:
417 for v
in actionStruct:
419 imports |= v._imports
421 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
422 """Compare two fields for equality.
426 instance1 : `lsst.pex.config.Config`
427 Left-hand side config instance to compare.
428 instance2 : `lsst.pex.config.Config`
429 Right-hand side config instance to compare.
431 If `True`, this function returns as soon as an inequality if found.
433 Relative tolerance for floating point comparisons.
435 Absolute tolerance for floating point comparisons.
437 A callable that takes a string, used (possibly repeatedly) to
443 `True` if the fields are equal, `False` otherwise.
447 Floating point comparisons are performed by `numpy.allclose`.
451 name = getComparisonName(
454 if not compareScalars(f
"keys for {name}",
set(d1.fieldNames),
set(d2.fieldNames), output=output):
457 for k, v1
in d1.items():
459 result = compareConfigs(
460 f
"{name}.{k}", v1, v2, shortcut=shortcut, rtol=rtol, atol=atol, output=output
462 if not result
and shortcut:
464 equal = equal
and result
std::vector< SchemaItem< Flag > > * items
__get__(self, instance, owner=None, at=None, label="default")
FieldTypeVar __get__(self, Config instance, Any owner=None, Any at=None, str label="default")
Field[FieldTypeVar] __get__(self, None instance, Any owner=None, Any at=None, str label="default")
_setup(self, doc, dtype, default, check, optional, source, deprecated)
__get__(self, instance, owner=None, at=None, label="default")
rename(self, Config instance)
ConfigurableActionStruct[ActionTypeVar] __get__(self, Config instance, Any owner=None, Any at=None, str label="default")
save(self, outfile, instance)
__class_getitem__(cls, params)
ConfigurableActionStruct[ActionTypeVar] __get__(self, None instance, Any owner=None, Any at=None, str label="default")
__set__(self, Config instance,(None|Mapping[str, ConfigurableAction]|SimpleNamespace|ConfigurableActionStruct|ConfigurableActionStructField|type[ConfigurableActionStructField]) value, Iterable[StackFrame] at=None, str label="assigment")
_collectImports(self, instance, imports)
_compare(self, instance1, instance2, shortcut, rtol, atol, output)
__init__(self, str doc, Mapping[str, ConfigurableAction]|None default=None, bool optional=False, deprecated=None)
Any __getattr__(self, attr)
ConfigurableActionStructField _field
None __setattr__(self, str attr, ActionTypeVar|type[ActionTypeVar] value, at=None, label="setattr", setHistory=False)
list[tuple] history(self)
__init__(self, Config config, ConfigurableActionStructField field, Mapping[str, ConfigurableAction] value, Any at, str label)
Iterator[ActionTypeVar] __iter__(self)
Iterable[str] fieldNames(self)
None __set__(self, ConfigurableActionStruct instance, str|Iterable[str] value)
None __get__(self, instance, objtype=None)
None __get__(self, instance, objtype=None)
None __set__(self, ConfigurableActionStruct instance, Mapping[str, ConfigurableAction]|ConfigurableActionStruct value)
daf::base::PropertySet * set