21 from __future__
import annotations
23 __all__ = (
"ConfigurableActionStructField",
"ConfigurableActionStruct")
25 from typing
import Iterable, Mapping, Optional, TypeVar, Union, Type, Tuple, List, Any, Dict
31 from .
import ConfigurableAction
37 """This descriptor exists to abstract the logic of using a dictionary to
38 update a ConfigurableActionStruct through attribute assignment. This is
39 useful in the context of setting configuration through pipelines or on
42 def __set__(self, instance: ConfigurableActionStruct,
43 value: Union[Mapping[str, ConfigurableAction], ConfigurableActionStruct]) ->
None:
44 if isinstance(value, Mapping):
46 elif isinstance(value, ConfigurableActionStruct):
51 raise ValueError(
"Can only update a ConfigurableActionStruct with an instance of such, or a "
53 for name, action
in value.items():
54 setattr(instance, name, action)
56 def __get__(self, instance, objtype=None) -> None:
62 """This descriptor exists to abstract the logic of removing an interable
63 of action names from a ConfigurableActionStruct at one time using
64 attribute assignment. This is useful in the context of setting
65 configuration through pipelines or on the command line.
70 Raised if an attribute specified for removal does not exist in the
71 ConfigurableActionStruct
73 def __set__(self, instance: ConfigurableActionStruct,
74 value: Union[str, Iterable[str]]) ->
None:
78 if isinstance(value, str):
81 delattr(instance, name)
83 def __get__(self, instance, objtype=None) -> None:
89 """A ConfigurableActionStruct is the storage backend class that supports
90 the ConfigurableActionStructField. This class should not be created
93 This class allows managing a collection of `ConfigurableActions` with a
94 struct like interface, that is to say in an attribute like notation.
96 Attributes can be dynamically added or removed as such:
98 ConfigurableActionStructInstance.variable1 = a_configurable_action
99 del ConfigurableActionStructInstance.variable1
101 Each action is then available to be individually configured as a normal
102 `lsst.pex.config.Config` object.
104 ConfigurableActionStruct supports two special convenance attributes.
106 The first is `update`. You may assign a dict of `ConfigurableActions` or
107 a `ConfigurableActionStruct` to this attribute which will update the
108 `ConfigurableActionStruct` on which the attribute is invoked such that it
109 will be updated to contain the entries specified by the structure on the
110 right hand side of the equals sign.
112 The second convenience attribute is named remove. You may assign an
113 iterable of strings which correspond to attribute names on the
114 `ConfigurableActionStruct`. All of the corresponding attributes will then
115 be removed. If any attribute does not exist, an `AttributeError` will be
116 raised. Any attributes in the Iterable prior to the name which raises will
117 have been removed from the `ConfigurableActionStruct`
121 _attrs: Dict[str, ConfigurableAction]
122 _field: ConfigurableActionStructField
123 _history: List[tuple]
129 def __init__(self, config: Config, field: ConfigurableActionStructField,
130 value: Mapping[str, ConfigurableAction], at: Any, label: str):
131 object.__setattr__(self,
'_config_', weakref.ref(config))
132 object.__setattr__(self,
'_attrs', {})
133 object.__setattr__(self,
'_field', field)
134 object.__setattr__(self,
'_history', [])
136 self.
historyhistory.
append((
"Struct initialized", at, label))
138 if value
is not None:
139 for k, v
in value.items():
143 def _config(self) -> Config:
146 assert(self._config_()
is not None)
147 return self._config_()
155 return self._attrs.
keys()
157 def __setattr__(self, attr: str, value: Union[ConfigurableAction, Type[ConfigurableAction]],
158 at=
None, label=
'setattr', setHistory=
False) ->
None:
160 if hasattr(self.
_config_config,
'_frozen')
and self.
_config_config._frozen:
161 msg =
"Cannot modify a frozen Config. "\
162 f
"Attempting to set item {attr} to value {value}"
165 if attr
not in (self.__dict__.
keys() |
type(self).__dict__.keys()):
166 name = _joinNamePath(self.
_config_config._name, self._field.name, attr)
169 if isinstance(value, ConfigurableAction):
170 valueInst =
type(value)(__name=name, __at=at, __label=label, **value._storage)
172 valueInst = value(__name=name, __at=at, __label=label)
173 self._attrs[attr] = valueInst
178 if attr
in object.__getattribute__(self,
'_attrs'):
179 return self._attrs[attr]
181 super().__getattribute__(attr)
184 if name
in self._attrs:
185 del self._attrs[name]
189 def __iter__(self) -> Iterable[ConfigurableAction]:
190 return iter(self._attrs.values())
192 def items(self) -> Iterable[Tuple[str, ConfigurableAction]]:
196 T = TypeVar(
"T", bound=
"ConfigurableActionStructField")
200 r"""`ConfigurableActionStructField` is a `~lsst.pex.config.Field` subclass
201 that allows `ConfigurableAction`\ s to be organized in a
202 `~lsst.pex.config.Config` class in a manor similar to how a
203 `~lsst.pipe.base.Struct` works.
205 This class implements a `ConfigurableActionStruct` as an intermediary
206 object to organize the `ConfigurableActions`. See it's documentation for
211 StructClass = ConfigurableActionStruct
216 default: Optional[Mapping[str, ConfigurableAction]]
218 def __init__(self, doc: str, default: Optional[Mapping[str, ConfigurableAction]] =
None,
219 optional: bool =
False,
222 self.
_setup_setup(doc=doc, dtype=self.__class__, default=default, check=
None,
223 optional=optional, source=source, deprecated=deprecated)
226 value: Union[
None, Mapping[str, ConfigurableAction], ConfigurableActionStruct],
227 at: Iterable[StackFrame] =
None, label: str =
'assigment'):
229 msg =
"Cannot modify a frozen Config. "\
230 "Attempting to set field to value %s" % value
236 if value
is None or value == self.
defaultdefault:
237 value = self.
StructClassStructClass(instance, self, value, at=at, label=label)
239 history = instance._history.setdefault(self.name, [])
240 history.append((value, at, label))
242 if not isinstance(value, ConfigurableActionStruct):
244 "Can only assign things that are subclasses of Configurable Action")
245 instance._storage[self.name] = value
247 def __get__(self: T, instance: Config, owner:
None =
None, at: Iterable[StackFrame] =
None,
248 label: str =
"default"
249 ) -> Union[
None, T, ConfigurableActionStruct]:
250 if instance
is None or not isinstance(instance, Config):
253 field: Optional[ConfigurableActionStruct] = instance._storage[self.name]
257 actionStruct: ConfigurableActionStruct = self.
__get____get____get__(instance)
258 if actionStruct
is not None:
259 for k, v
in actionStruct.items():
260 fullname = _joinNamePath(instance._name, self.name, k)
265 if value
is not None:
271 if actionStruct
is None:
274 dict_ = {k: v.toDict()
for k, v
in actionStruct.items()}
278 def save(self, outfile, instance):
280 fullname = _joinNamePath(instance._name, self.name)
281 if actionStruct
is None:
282 outfile.write(
u"{}={!r}\n".
format(fullname, actionStruct))
285 outfile.write(
u"{}={!r}\n".
format(fullname, {}))
286 for v
in actionStruct:
287 outfile.write(
u"{}={}()\n".
format(v._name, _typeStr(v)))
292 if actionStruct
is not None:
293 for v
in actionStruct:
296 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
297 """Compare two fields for equality.
301 instance1 : `lsst.pex.config.Config`
302 Left-hand side config instance to compare.
303 instance2 : `lsst.pex.config.Config`
304 Right-hand side config instance to compare.
306 If `True`, this function returns as soon as an inequality if found.
308 Relative tolerance for floating point comparisons.
310 Absolute tolerance for floating point comparisons.
312 A callable that takes a string, used (possibly repeatedly) to
318 `True` if the fields are equal, `False` otherwise.
322 Floating point comparisons are performed by `numpy.allclose`.
324 d1: ConfigurableActionStruct = getattr(instance1, self.name)
325 d2: ConfigurableActionStruct = getattr(instance2, self.name)
327 _joinNamePath(instance1._name, self.name),
328 _joinNamePath(instance2._name, self.name)
330 if not compareScalars(f
"keys for {name}",
set(d1.fieldNames),
set(d2.fieldNames), output=output):
333 for k, v1
in d1.items():
336 rtol=rtol, atol=atol, output=output)
337 if not result
and shortcut:
339 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 toDict(self, instance)
Union[None, T, ConfigurableActionStruct] __get__(T self, Config instance, None owner=None, Iterable[StackFrame] at=None, str label="default")
def freeze(self, instance)
def save(self, outfile, instance)
def validate(self, instance)
def __init__(self, str doc, Optional[Mapping[str, ConfigurableAction]] default=None, bool optional=False, deprecated=None)
def rename(self, Config instance)
def __set__(self, Config instance, Union[None, Mapping[str, ConfigurableAction], ConfigurableActionStruct] value, Iterable[StackFrame] at=None, str label='assigment')
def __init__(self, Config config, ConfigurableActionStructField field, Mapping[str, ConfigurableAction] value, Any at, str label)
Iterable[str] fieldNames(self)
def __getattr__(self, attr)
None __setattr__(self, str attr, Union[ConfigurableAction, Type[ConfigurableAction]] value, at=None, label='setattr', setHistory=False)
Iterable[ConfigurableAction] __iter__(self)
def __delattr__(self, name)
Iterable[Tuple[str, ConfigurableAction]] items(self)
List[tuple] history(self)
None __get__(self, instance, objtype=None)
None __set__(self, ConfigurableActionStruct instance, Union[str, Iterable[str]] value)
None __get__(self, instance, objtype=None)
None __set__(self, ConfigurableActionStruct instance, Union[Mapping[str, ConfigurableAction], ConfigurableActionStruct] value)
daf::base::PropertySet * set
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 compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
def compareScalars(name, v1, v2, output, rtol=1E-8, atol=1E-8, dtype=None)
def getComparisonName(name1, name2)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)