27from __future__
import annotations
33 "FieldValidationError",
34 "UnexpectedProxyUsageError",
49from typing
import Any, ForwardRef, Generic, TypeVar, cast, overload
52 from types
import GenericAlias
55 GenericAlias = type(Mapping[int, int])
64from .callStack
import getCallStack, getStackFrame
65from .comparison
import compareConfigs, compareScalars, getComparisonName
68 YamlLoaders: tuple[Any, ...] = (yaml.Loader, yaml.FullLoader, yaml.SafeLoader, yaml.UnsafeLoader)
72 from yaml
import CLoader
74 YamlLoaders += (CLoader,)
83 """A Subclass of python's GenericAlias used in defining and instantiating
86 This class differs from `types.GenericAlias` in that it calls a method
87 named _parseTypingArgs defined on Fields. This method gives Field and its
88 subclasses an opportunity to transform type parameters into class key word
89 arguments. Code authors do not need to implement any returns of this object
90 directly, and instead only need implement _parseTypingArgs, if a Field
91 subclass differs from the base class implementation.
93 This class is intended to be an implementation detail, returned from a
94 Field's `__class_getitem__` method.
97 def __call__(self, *args: Any, **kwds: Any) -> Any:
98 origin_kwargs = self._parseTypingArgs(self.__args__, kwds)
99 return super().
__call__(*args, **{**kwds, **origin_kwargs})
102FieldTypeVar = TypeVar(
"FieldTypeVar")
106 """Exception raised when a proxy class is used in a context that suggests
107 it should have already been converted to the thing it proxies.
112 """Generate nested configuration names."""
113 if not prefix
and not name:
114 raise ValueError(
"Invalid name: cannot be None")
117 elif prefix
and name:
118 name = prefix +
"." + name
120 if index
is not None:
121 return f
"{name}[{index!r}]"
127 """Cast a value to a type, if appropriate.
134 Data type, such as `float`, `int`, or `str`.
139 If appropriate, the returned value is ``x`` cast to the given type
140 ``dtype``. If the cast cannot be performed the original value of
143 if dtype == float
and isinstance(x, int):
149 """Generate a fully-qualified type name.
154 Fully-qualified type name.
158 This function is used primarily for writing config files to be executed
159 later upon with the 'load' function.
161 if hasattr(x,
"__module__")
and hasattr(x,
"__name__"):
165 if xtype.__module__ ==
"builtins":
166 return xtype.__name__
168 return f
"{xtype.__module__}.{xtype.__name__}"
174 """Represent a Config object in a form suitable for YAML.
176 Stores the serialized stream as a scalar block string.
178 stream = io.StringIO()
179 data.saveToStream(stream)
180 config_py = stream.getvalue()
184 config_py = config_py.rstrip() +
"\n"
188 config_py = re.sub(
r"\s+$",
"\n", config_py, flags=re.MULTILINE)
191 return dumper.represent_scalar(
"lsst.pex.config.Config", config_py, style=
"|")
194 """Construct a config from YAML."""
195 config_py = loader.construct_scalar(node)
196 return Config._fromPython(config_py)
200 for loader
in YamlLoaders:
201 yaml.add_constructor(
"lsst.pex.config.Config", _yaml_config_constructor, Loader=loader)
205 """A metaclass for `lsst.pex.config.Config`.
210 Name to use for class.
211 bases : `~collections.abc.Iterable`
214 Additional parameters.
218 ``ConfigMeta`` adds a dictionary containing all `~lsst.pex.config.Field`
219 class attributes as a class attribute called ``_fields``, and adds
220 the name of each field as an instance variable of the field itself (so you
221 don't have to pass the name of the field to the field constructor).
225 type.__init__(cls, name, bases, dict_)
229 def getFields(classtype):
231 bases = list(classtype.__bases__)
234 fields.update(getFields(b))
236 for k, v
in classtype.__dict__.items():
237 if isinstance(v, Field):
241 fields = getFields(cls)
242 for k, v
in fields.items():
243 setattr(cls, k, copy.deepcopy(v))
246 if isinstance(value, Field):
249 type.__setattr__(cls, name, value)
253 """Raised when a ``~lsst.pex.config.Field`` is not valid in a
254 particular ``~lsst.pex.config.Config``.
258 field : `lsst.pex.config.Field`
259 The field that was not valid.
260 config : `lsst.pex.config.Config`
261 The config containing the invalid field.
263 Text describing why the field was not valid.
268 """Type of the `~lsst.pex.config.Field` that incurred the error.
272 """Name of the `~lsst.pex.config.Field` instance that incurred the
277 lsst.pex.config.Field.name
280 self.
fullname = _joinNamePath(config._name, field.name)
281 """Fully-qualified name of the `~lsst.pex.config.Field` instance
285 self.
history = config.history.setdefault(field.name, [])
286 """Full history of all changes to the `~lsst.pex.config.Field`
291 """File and line number of the `~lsst.pex.config.Field` definition.
296 "%s '%s' failed validation: %s\n"
297 "For more information see the Field definition at:\n%s"
298 " and the Config definition at:\n%s"
311 """A field in a `~lsst.pex.config.Config` that supports `int`, `float`,
312 `complex`, `bool`, and `str` data types.
317 A description of the field for users.
318 dtype : type, optional
319 The field's data type. ``Field`` only supports basic data types:
320 `int`, `float`, `complex`, `bool`, and `str`. See
321 `Field.supportedTypes`. Optional if supplied as a typing argument to
323 default : object, optional
324 The field's default value.
325 check : callable, optional
326 A callable that is called with the field's value. This callable should
327 return `False` if the value is invalid. More complex inter-field
328 validation can be written as part of the
329 `lsst.pex.config.Config.validate` method.
330 optional : `bool`, optional
331 This sets whether the field is considered optional, and therefore
332 doesn't need to be set by the user. When `False`,
333 `lsst.pex.config.Config.validate` fails if the field's value is `None`.
334 deprecated : None or `str`, optional
335 A description of why this Field is deprecated, including removal date.
336 If not None, the string is appended to the docstring for this Field.
341 Raised when the ``dtype`` parameter is not one of the supported types
342 (see `Field.supportedTypes`).
358 ``Field`` instances (including those of any subclass of ``Field``) are used
359 as class attributes of `~lsst.pex.config.Config` subclasses (see the
360 example, below). ``Field`` attributes work like the `property` attributes
361 of classes that implement custom setters and getters. `Field` attributes
362 belong to the class, but operate on the instance. Formally speaking,
363 `Field` attributes are `descriptors
364 <https://docs.python.org/3/howto/descriptor.html>`_.
366 When you access a `Field` attribute on a `Config` instance, you don't
367 get the `Field` instance itself. Instead, you get the value of that field,
368 which might be a simple type (`int`, `float`, `str`, `bool`) or a custom
369 container type (like a `lsst.pex.config.List`) depending on the field's
370 type. See the example, below.
372 Fields can be annotated with a type similar to other python classes (python
373 specification `here <https://peps.python.org/pep-0484/#generics>`_ ).
374 See the name field in the Config example below for an example of this.
375 Unlike most other uses in python, this has an effect at type checking *and*
376 runtime. If the type is specified with a class annotation, it will be used
377 as the value of the ``dtype`` in the ``Field`` and there is no need to
378 specify it as an argument during instantiation.
380 There are Some notes on dtype through type annotation syntax. Type
381 annotation syntax supports supplying the argument as a string of a type
382 name. i.e. "float", but this cannot be used to resolve circular references.
383 Type annotation syntax can be used on an identifier in addition to Class
384 assignment i.e. ``variable: Field[str] = Config.someField`` vs
385 ``someField = Field[str](doc="some doc"). However, this syntax is only
386 useful for annotating the type of the identifier (i.e. variable in previous
387 example) and does nothing for assigning the dtype of the ``Field``.
391 Instances of ``Field`` should be used as class attributes of
392 `lsst.pex.config.Config` subclasses:
394 >>> from lsst.pex.config import Config, Field
395 >>> class Example(Config):
396 ... myInt = Field("An integer field.", int, default=0)
397 ... name = Field[str](doc="A string Field")
399 >>> print(config.myInt)
402 >>> print(config.myInt)
407 """Identifier (variable name) used to refer to a Field within a Config
411 supportedTypes = {str, bool, float, int, complex}
412 """Supported data types for field values (`set` of types).
417 params: tuple[type, ...] | tuple[str, ...], kwds: Mapping[str, Any]
418 ) -> Mapping[str, Any]:
419 """Parse type annotations into keyword constructor arguments.
421 This is a special private method that interprets type arguments (i.e.
422 Field[str]) into keyword arguments to be passed on to the constructor.
424 Subclasses of Field can implement this method to customize how they
425 handle turning type parameters into keyword arguments (see DictField
430 params : `tuple` of `type` or `tuple` of str
431 Parameters passed to the type annotation. These will either be
432 types or strings. Strings are to interpreted as forward references
433 and will be treated as such.
434 kwds : `MutableMapping` with keys of `str` and values of `Any`
435 These are the user supplied keywords that are to be passed to the
440 kwds : `MutableMapping` with keys of `str` and values of `Any`
441 The mapping of keywords that will be passed onto the constructor
442 of the Field. Should be filled in with any information gleaned
443 from the input parameters.
448 Raised if params is of incorrect length.
449 Raised if a forward reference could not be resolved
450 Raised if there is a conflict between params and values in kwds
453 raise ValueError(
"Only single type parameters are supported")
454 unpackedParams = params[0]
455 if isinstance(unpackedParams, str):
456 _typ = ForwardRef(unpackedParams)
462 result = _typ._evaluate(globals(), locals(),
set())
465 result = _typ._evaluate(globals(), locals())
467 raise ValueError(
"Could not deduce type from input")
468 unpackedParams = cast(type, result)
469 if "dtype" in kwds
and kwds[
"dtype"] != unpackedParams:
470 raise ValueError(
"Conflicting definition for dtype")
471 elif "dtype" not in kwds:
472 kwds = {**kwds, **{
"dtype": unpackedParams}}
478 def __init__(self, doc, dtype=None, default=None, check=None, optional=False, deprecated=None):
481 "dtype must either be supplied as an argument or as a type argument to the class"
484 raise ValueError(
"Unsupported Field dtype %s" % _typeStr(dtype))
486 source = getStackFrame()
494 deprecated=deprecated,
497 def _setup(self, doc, dtype, default, check, optional, source, deprecated):
498 """Set attributes, usually during initialization."""
500 """Data type for the field.
504 raise ValueError(
"Docstring is empty.")
507 if deprecated
is not None:
508 doc = f
"{doc} Deprecated: {deprecated}"
510 """A description of the field (`str`).
514 """If not None, a description of why this field is deprecated (`str`).
517 self.
__doc__ = f
"{doc} (`{dtype.__name__}`"
518 if optional
or default
is not None:
519 self.
__doc__ += f
", default ``{default!r}``"
523 """Default value for this field.
527 """A user-defined function that validates the value of the field.
531 """Flag that determines if the field is required to be set (`bool`).
533 When `False`, `lsst.pex.config.Config.validate` will fail if the
534 field's value is `None`.
538 """The stack frame where this field is defined (`list` of
539 `~lsst.pex.config.callStack.StackFrame`).
543 r"""Rename the field in a `~lsst.pex.config.Config` (for internal use
548 instance : `lsst.pex.config.Config`
549 The config instance that contains this field.
553 This method is invoked by the `lsst.pex.config.Config` object that
554 contains this field and should not be called directly.
556 Renaming is only relevant for `~lsst.pex.config.Field` instances that
557 hold subconfigs. `~lsst.pex.config.Field`\s that hold subconfigs should
558 rename each subconfig with the full field name as generated by
559 `lsst.pex.config.config._joinNamePath`.
564 """Validate the field (for internal use only).
568 instance : `lsst.pex.config.Config`
569 The config instance that contains this field.
573 lsst.pex.config.FieldValidationError
574 Raised if verification fails.
578 This method provides basic validation:
580 - Ensures that the value is not `None` if the field is not optional.
581 - Ensures type correctness.
582 - Ensures that the user-provided ``check`` function is valid.
584 Most `~lsst.pex.config.Field` subclasses should call
585 `lsst.pex.config.Field.validate` if they re-implement
586 `~lsst.pex.config.Field.validate`.
588 value = self.__get__(instance)
589 if not self.optional
and value
is None:
590 raise FieldValidationError(self, instance,
"Required value cannot be None")
593 """Make this field read-only (for internal use only).
597 instance : `lsst.pex.config.Config`
598 The config instance that contains this field.
602 Freezing is only relevant for fields that hold subconfigs. Fields which
603 hold subconfigs should freeze each subconfig.
605 **Subclasses should implement this method.**
615 The value being validated.
620 Raised if the value's type is incompatible with the field's
623 Raised if the value is rejected by the ``check`` method.
628 if not isinstance(value, self.dtype):
629 msg =
"Value {} is of incorrect type {}. Expected type {}".format(
632 _typeStr(self.dtype),
635 if self.check
is not None and not self.check(value):
636 msg =
"Value %s is not a valid value" % str(value)
637 raise ValueError(msg)
640 """Call the _collectImports method on all config
641 objects the field may own, and union them with the supplied imports
646 instance : instance or subclass of `lsst.pex.config.Config`
647 A config object that has this field defined on it
649 Set of python modules that need imported after persistence
653 def save(self, outfile, instance):
654 """Save this field to a file (for internal use only).
658 outfile : file-like object
659 A writeable field handle.
660 instance : `~lsst.pex.config.Config`
661 The `~lsst.pex.config.Config` instance that contains this field.
665 This method is invoked by the `~lsst.pex.config.Config` object that
666 contains this field and should not be called directly.
668 The output consists of the documentation string
669 (`lsst.pex.config.Field.doc`) formatted as a Python comment. The second
670 line is formatted as an assignment: ``{fullname}={value}``.
672 This output can be executed with Python.
674 value = self.__get__(instance)
675 fullname = _joinNamePath(instance._name, self.name)
677 if self.deprecated
and value == self.default:
682 doc =
"# " + str(self.doc).replace(
"\n",
"\n# ")
683 if isinstance(value, float)
and not math.isfinite(value):
685 outfile.write(f
"{doc}\n{fullname}=float('{value!r}')\n\n")
687 outfile.write(f
"{doc}\n{fullname}={value!r}\n\n")
690 """Convert the field value so that it can be set as the value of an
691 item in a `dict` (for internal use only).
695 instance : `~lsst.pex.config.Config`
696 The `~lsst.pex.config.Config` that contains this field.
701 The field's value. See *Notes*.
705 This method invoked by the owning `~lsst.pex.config.Config` object and
706 should not be called directly.
708 Simple values are passed through. Complex data structures must be
709 manipulated. For example, a `~lsst.pex.config.Field` holding a
710 subconfig should, instead of the subconfig object, return a `dict`
711 where the keys are the field names in the subconfig, and the values are
712 the field values in the subconfig.
718 self, instance: None, owner: Any =
None, at: Any =
None, label: str =
"default"
719 ) -> Field[FieldTypeVar]: ...
723 self, instance: Config, owner: Any =
None, at: Any =
None, label: str =
"default"
724 ) -> FieldTypeVar: ...
726 def __get__(self, instance, owner=None, at=None, label="default"):
727 """Define how attribute access should occur on the Config instance
728 This is invoked by the owning config object and should not be called
731 When the field attribute is accessed on a Config class object, it
732 returns the field object itself in order to allow inspection of
735 When the field attribute is access on a config instance, the actual
736 value described by the field (and held by the Config instance) is
744 return instance._storage[self.
namename]
745 except AttributeError:
746 if not isinstance(instance, Config):
749 raise AttributeError(
750 f
"Config {instance} is missing _storage attribute, likely incorrectly initialized"
754 self, instance: Config, value: FieldTypeVar |
None, at: Any =
None, label: str =
"assignment"
756 """Set an attribute on the config instance.
760 instance : `lsst.pex.config.Config`
761 The config instance that contains this field.
763 Value to set on this field.
764 at : `list` of `~lsst.pex.config.callStack.StackFrame` or `None`,\
766 The call stack (created by
767 `lsst.pex.config.callStack.getCallStack`).
768 label : `str`, optional
769 Event label for the history.
773 This method is invoked by the owning `lsst.pex.config.Config` object
774 and should not be called directly.
776 Derived `~lsst.pex.config.Field` classes may need to override the
777 behavior. When overriding ``__set__``, `~lsst.pex.config.Field` authors
778 should follow the following rules:
780 - Do not allow modification of frozen configs.
781 - Validate the new value **before** modifying the field. Except if the
782 new value is `None`. `None` is special and no attempt should be made
783 to validate it until `lsst.pex.config.Config.validate` is called.
784 - Do not modify the `~lsst.pex.config.Config` instance to contain
786 - If the field is modified, update the history of the
787 `lsst.pex.config.field.Field` to reflect the changes.
789 In order to decrease the need to implement this method in derived
790 `~lsst.pex.config.Field` types, value validation is performed in the
791 `lsst.pex.config.Field._validateValue`. If only the validation step
792 differs in the derived `~lsst.pex.config.Field`, it is simpler to
793 implement `lsst.pex.config.Field._validateValue` than to reimplement
794 ``__set__``. More complicated behavior, however, may require
800 history = instance._history.setdefault(self.
namename, [])
801 if value
is not None:
802 value = _autocast(value, self.
dtype)
805 except BaseException
as e:
808 instance._storage[self.
namename] = value
811 history.append((value, at, label))
814 """Delete an attribute from a `lsst.pex.config.Config` instance.
818 instance : `lsst.pex.config.Config`
819 The config instance that contains this field.
820 at : `list` of `lsst.pex.config.callStack.StackFrame`
821 The call stack (created by
822 `lsst.pex.config.callStack.getCallStack`).
823 label : `str`, optional
824 Event label for the history.
828 This is invoked by the owning `~lsst.pex.config.Config` object and
829 should not be called directly.
833 self.
__set__(instance,
None, at=at, label=label)
835 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
836 """Compare a field (named `Field.name`) in two
837 `~lsst.pex.config.Config` instances for equality.
841 instance1 : `lsst.pex.config.Config`
842 Left-hand side `Config` instance to compare.
843 instance2 : `lsst.pex.config.Config`
844 Right-hand side `Config` instance to compare.
845 shortcut : `bool`, optional
847 rtol : `float`, optional
848 Relative tolerance for floating point comparisons.
849 atol : `float`, optional
850 Absolute tolerance for floating point comparisons.
851 output : callable, optional
852 A callable that takes a string, used (possibly repeatedly) to
857 This method must be overridden by more complex `Field` subclasses.
861 lsst.pex.config.compareScalars
863 v1 = getattr(instance1, self.
namename)
864 v2 = getattr(instance2, self.
namename)
865 name = getComparisonName(
866 _joinNamePath(instance1._name, self.
namename), _joinNamePath(instance2._name, self.
namename)
868 return compareScalars(name, v1, v2, dtype=self.
dtype, rtol=rtol, atol=atol, output=output)
872 """Importer (for `sys.meta_path`) that records which modules are being
875 *This class does not do any importing itself.*
879 Use this class as a context manager to ensure it is properly uninstalled
882 >>> with RecordingImporter() as importer:
884 ... import numpy as np
885 ... print("Imported: " + importer.getModules())
893 sys.meta_path = [self] + sys.meta_path
901 """Uninstall the importer."""
907 Called as part of the ``import`` chain of events.
913 path : `list` [`str`]
915 target : `~typing.Any`, optional
923 """Get the set of modules that were imported.
927 modules : `set` of `str`
928 Set of imported module names.
935 """Base class for configuration (*config*) objects.
939 A ``Config`` object will usually have several `~lsst.pex.config.Field`
940 instances as class attributes. These are used to define most of the base
943 ``Config`` implements a mapping API that provides many `dict`-like methods,
944 such as `keys`, `values`, and `items`. ``Config`` instances also support
945 the ``in`` operator to test if a field is in the config. Unlike a `dict`,
946 ``Config`` classes are not subscriptable. Instead, access individual
947 fields as attributes of the configuration instance.
951 Config classes are subclasses of ``Config`` that have
952 `~lsst.pex.config.Field` instances (or instances of
953 `~lsst.pex.config.Field` subclasses) as class attributes:
955 >>> from lsst.pex.config import Config, Field, ListField
956 >>> class DemoConfig(Config):
957 ... intField = Field(doc="An integer field", dtype=int, default=42)
958 ... listField = ListField(doc="List of favorite beverages.", dtype=str,
959 ... default=['coffee', 'green tea', 'water'])
961 >>> config = DemoConfig()
963 Configs support many `dict`-like APIs:
966 ['intField', 'listField']
967 >>> 'intField' in config
970 Individual fields can be accessed as attributes of the configuration:
974 >>> config.listField.append('earl grey tea')
975 >>> print(config.listField)
976 ['coffee', 'green tea', 'water', 'earl grey tea']
979 _storage: dict[str, Any]
980 _fields: dict[str, Field]
981 _history: dict[str, list[Any]]
985 """Iterate over fields."""
993 names : `~collections.abc.KeysView`
994 List of `lsst.pex.config.Field` names.
1003 values : `~collections.abc.ValuesView`
1004 Iterator of field values.
1009 """Get configurations as ``(field name, field value)`` pairs.
1013 items : `~collections.abc.ItemsView`
1014 Iterator of tuples for each configuration. Tuple items are:
1022 """Return `True` if the specified field exists in this config.
1027 Field name to test for.
1032 `True` if the specified field exists in the config.
1037 """Allocate a new `lsst.pex.config.Config` object.
1039 In order to ensure that all Config object are always in a proper state
1040 when handed to users or to derived `~lsst.pex.config.Config` classes,
1041 some attributes are handled at allocation time rather than at
1044 This ensures that even if a derived `~lsst.pex.config.Config` class
1045 implements ``__init__``, its author does not need to be concerned about
1046 when or even the base ``Config.__init__`` should be called.
1048 name = kw.pop(
"__name",
None)
1049 at = kw.pop(
"__at", getCallStack())
1051 kw.pop(
"__label",
"default")
1053 instance = object.__new__(cls)
1054 instance._frozen =
False
1055 instance._name = name
1056 instance._storage = {}
1057 instance._history = {}
1058 instance._imports =
set()
1060 for field
in instance._fields.values():
1061 instance._history[field.name] = []
1062 field.__set__(instance, field.default, at=at + [field.source], label=
"default")
1064 instance.setDefaults()
1066 instance.update(__at=at, **kw)
1070 """Reduction for pickling (function with arguments to reproduce).
1072 We need to condense and reconstitute the `~lsst.pex.config.Config`,
1073 since it may contain lambdas (as the ``check`` elements) that cannot
1078 stream = io.StringIO()
1080 return (unreduceConfig, (self.
__class__, stream.getvalue().encode()))
1083 """Subclass hook for computing defaults.
1087 Derived `~lsst.pex.config.Config` classes that must compute defaults
1088 rather than using the `~lsst.pex.config.Field` instances's defaults
1089 should do so here. To correctly use inherited defaults,
1090 implementations of ``setDefaults`` must call their base class's
1096 """Update values of fields specified by the keyword arguments.
1101 Keywords are configuration field names. Values are configuration
1106 The ``__at`` and ``__label`` keyword arguments are special internal
1107 keywords. They are used to strip out any internal steps from the
1108 history tracebacks of the config. Do not modify these keywords to
1109 subvert a `~lsst.pex.config.Config` instance's history.
1113 This is a config with three fields:
1115 >>> from lsst.pex.config import Config, Field
1116 >>> class DemoConfig(Config):
1117 ... fieldA = Field(doc='Field A', dtype=int, default=42)
1118 ... fieldB = Field(doc='Field B', dtype=bool, default=True)
1119 ... fieldC = Field(doc='Field C', dtype=str, default='Hello world')
1121 >>> config = DemoConfig()
1123 These are the default values of each field:
1125 >>> for name, value in config.iteritems():
1126 ... print(f"{name}: {value}")
1130 fieldC: 'Hello world'
1132 Using this method to update ``fieldA`` and ``fieldC``:
1134 >>> config.update(fieldA=13, fieldC='Updated!')
1136 Now the values of each field are:
1138 >>> for name, value in config.iteritems():
1139 ... print(f"{name}: {value}")
1145 at = kw.pop(
"__at", getCallStack())
1146 label = kw.pop(
"__label",
"update")
1148 for name, value
in kw.items():
1150 field = self._fields[name]
1151 field.__set__(self, value, at=at, label=label)
1153 raise KeyError(f
"No field of name {name} exists in config type {_typeStr(self)}")
1155 def load(self, filename, root="config"):
1156 """Modify this config in place by executing the Python code in a
1162 Name of the configuration file. A configuration file is Python
1164 root : `str`, optional
1165 Name of the variable in file that refers to the config being
1168 For example, the value of root is ``"config"`` and the file
1173 Then this config's field ``myField`` is set to ``5``.
1177 lsst.pex.config.Config.loadFromStream
1178 lsst.pex.config.Config.loadFromString
1179 lsst.pex.config.Config.save
1180 lsst.pex.config.Config.saveToStream
1181 lsst.pex.config.Config.saveToString
1183 with open(filename)
as f:
1184 code = compile(f.read(), filename=filename, mode=
"exec")
1188 """Modify this Config in place by executing the Python code in the
1193 stream : file-like object, `str`, `bytes`, or `~types.CodeType`
1194 Stream containing configuration override code. If this is a
1195 code object, it should be compiled with ``mode="exec"``.
1196 root : `str`, optional
1197 Name of the variable in file that refers to the config being
1200 For example, the value of root is ``"config"`` and the file
1205 Then this config's field ``myField`` is set to ``5``.
1206 filename : `str`, optional
1207 Name of the configuration file, or `None` if unknown or contained
1208 in the stream. Used for error reporting.
1209 extraLocals : `dict` of `str` to `object`, optional
1210 Any extra variables to include in local scope when loading.
1214 For backwards compatibility reasons, this method accepts strings, bytes
1215 and code objects as well as file-like objects. New code should use
1216 `loadFromString` instead for most of these types.
1220 lsst.pex.config.Config.load
1221 lsst.pex.config.Config.loadFromString
1222 lsst.pex.config.Config.save
1223 lsst.pex.config.Config.saveToStream
1224 lsst.pex.config.Config.saveToString
1226 if hasattr(stream,
"read"):
1227 if filename
is None:
1228 filename = getattr(stream,
"name",
"?")
1229 code = compile(stream.read(), filename=filename, mode=
"exec")
1232 self.
loadFromString(code, root=root, filename=filename, extraLocals=extraLocals)
1235 """Modify this Config in place by executing the Python code in the
1240 code : `str`, `bytes`, or `~types.CodeType`
1241 Stream containing configuration override code.
1242 root : `str`, optional
1243 Name of the variable in file that refers to the config being
1246 For example, the value of root is ``"config"`` and the file
1251 Then this config's field ``myField`` is set to ``5``.
1252 filename : `str`, optional
1253 Name of the configuration file, or `None` if unknown or contained
1254 in the stream. Used for error reporting.
1255 extraLocals : `dict` of `str` to `object`, optional
1256 Any extra variables to include in local scope when loading.
1261 Raised if a key in extraLocals is the same value as the value of
1266 lsst.pex.config.Config.load
1267 lsst.pex.config.Config.loadFromStream
1268 lsst.pex.config.Config.save
1269 lsst.pex.config.Config.saveToStream
1270 lsst.pex.config.Config.saveToString
1272 if filename
is None:
1275 filename = getattr(code,
"co_filename",
"?")
1277 globals = {
"__file__": filename}
1278 local = {root: self}
1279 if extraLocals
is not None:
1281 if root
in extraLocals:
1283 f
"{root} is reserved and cannot be used as a variable name in extraLocals"
1285 local.update(extraLocals)
1286 exec(code, globals, local)
1290 def save(self, filename, root="config"):
1291 """Save a Python script to the named file, which, when loaded,
1292 reproduces this config.
1297 Desination filename of this configuration.
1298 root : `str`, optional
1299 Name to use for the root config variable. The same value must be
1300 used when loading (see `lsst.pex.config.Config.load`).
1304 lsst.pex.config.Config.saveToStream
1305 lsst.pex.config.Config.saveToString
1306 lsst.pex.config.Config.load
1307 lsst.pex.config.Config.loadFromStream
1308 lsst.pex.config.Config.loadFromString
1310 d = os.path.dirname(filename)
1311 with tempfile.NamedTemporaryFile(mode=
"w", delete=
False, dir=d)
as outfile:
1316 umask = os.umask(0o077)
1318 os.chmod(outfile.name, (~umask & 0o666))
1322 shutil.move(outfile.name, filename)
1325 """Return the Python script form of this configuration as an executable
1330 skipImports : `bool`, optional
1331 If `True` then do not include ``import`` statements in output,
1332 this is to support human-oriented output from ``pipetask`` where
1333 additional clutter is not useful.
1338 A code string readable by `loadFromString`.
1342 lsst.pex.config.Config.save
1343 lsst.pex.config.Config.saveToStream
1344 lsst.pex.config.Config.load
1345 lsst.pex.config.Config.loadFromStream
1346 lsst.pex.config.Config.loadFromString
1348 buffer = io.StringIO()
1350 return buffer.getvalue()
1353 """Save a configuration file to a stream, which, when loaded,
1354 reproduces this config.
1358 outfile : file-like object
1359 Destination file object write the config into. Accepts strings not
1361 root : `str`, optional
1362 Name to use for the root config variable. The same value must be
1363 used when loading (see `lsst.pex.config.Config.load`).
1364 skipImports : `bool`, optional
1365 If `True` then do not include ``import`` statements in output,
1366 this is to support human-oriented output from ``pipetask`` where
1367 additional clutter is not useful.
1371 lsst.pex.config.Config.save
1372 lsst.pex.config.Config.saveToString
1373 lsst.pex.config.Config.load
1374 lsst.pex.config.Config.loadFromStream
1375 lsst.pex.config.Config.loadFromString
1384 configType = type(self)
1385 typeString = _typeStr(configType)
1386 outfile.write(f
"import {configType.__module__}\n")
1388 f
"assert type({root})=={typeString}, 'config is of type %s.%s instead of "
1389 f
"{typeString}' % (type({root}).__module__, type({root}).__name__)\n"
1392 if imp
in sys.modules
and sys.modules[imp]
is not None:
1393 outfile.write(f
"import {imp}\n")
1399 """Make this config, and all subconfigs, read-only."""
1405 """Save this config to an open stream object.
1409 outfile : file-like object
1410 Destination file object write the config into. Accepts strings not
1414 field.save(outfile, self)
1417 """Add module containing self to the list of things to import and
1418 then loops over all the fields in the config calling a corresponding
1421 The field method will call _collectImports on any
1422 configs it may own and return the set of things to import. This
1423 returned set will be merged with the set of imports for this config
1431 """Make a dictionary of field names and their values.
1436 Dictionary with keys that are `~lsst.pex.config.Field` names.
1437 Values are `~lsst.pex.config.Field` values.
1441 lsst.pex.config.Field.toDict
1445 This method uses the `~lsst.pex.config.Field.toDict` method of
1446 individual fields. Subclasses of `~lsst.pex.config.Field` may need to
1447 implement a ``toDict`` method for *this* method to work.
1451 dict_[name] = field.toDict(self)
1455 """Get all the field names in the config, recursively.
1459 names : `list` of `str`
1466 with io.StringIO()
as strFd:
1468 contents = strFd.getvalue()
1474 for line
in contents.split(
"\n"):
1475 if re.search(
r"^((assert|import)\s+|\s*$|#)", line):
1478 mat = re.search(
r"^(?:config\.)?([^=]+)\s*=\s*.*", line)
1480 keys.append(mat.group(1))
1485 """Rename this config object in its parent `~lsst.pex.config.Config`.
1490 New name for this config in its parent `~lsst.pex.config.Config`.
1494 This method uses the `~lsst.pex.config.Field.rename` method of
1495 individual `lsst.pex.config.Field` instances.
1496 `lsst.pex.config.Field` subclasses may need to implement a ``rename``
1497 method for *this* method to work.
1501 lsst.pex.config.Field.rename
1508 """Validate the Config, raising an exception if invalid.
1512 lsst.pex.config.FieldValidationError
1513 Raised if verification fails.
1517 The base class implementation performs type checks on all fields by
1518 calling their `~lsst.pex.config.Field.validate` methods.
1520 Complex single-field validation can be defined by deriving new Field
1521 types. For convenience, some derived `lsst.pex.config.Field`-types
1522 (`~lsst.pex.config.ConfigField` and
1523 `~lsst.pex.config.ConfigChoiceField`) are defined in
1524 ``lsst.pex.config`` that handle recursing into subconfigs.
1526 Inter-field relationships should only be checked in derived
1527 `~lsst.pex.config.Config` classes after calling this method, and base
1528 validation is complete.
1531 field.validate(self)
1534 """Format a configuration field's history to a human-readable format.
1539 Name of a `~lsst.pex.config.Field` in this config.
1541 Keyword arguments passed to `lsst.pex.config.history.format`.
1546 A string containing the formatted history.
1550 lsst.pex.config.history.format
1554 return pexHist.format(self, name, **kwargs)
1556 history = property(
lambda x: x._history)
1557 """Read-only history.
1561 """Set an attribute (such as a field's value).
1565 Unlike normal Python objects, `~lsst.pex.config.Config` objects are
1566 locked such that no additional attributes nor properties may be added
1567 to them dynamically.
1569 Although this is not the standard Python behavior, it helps to protect
1570 users from accidentally mispelling a field name, or trying to set a
1577 f
"Config field {fullname} is deprecated: {self._fields[attr].deprecated}",
1584 self.
_fields_fields[attr].__set__(self, value, at=at, label=label)
1585 elif hasattr(getattr(self.
__class__, attr,
None),
"__set__"):
1587 return object.__setattr__(self, attr, value)
1588 elif attr
in self.__dict__
or attr
in (
"_name",
"_history",
"_storage",
"_frozen",
"_imports"):
1590 self.__dict__[attr] = value
1593 raise AttributeError(f
"{_typeStr(self)} has no attribute {attr}")
1601 object.__delattr__(self, attr)
1604 if type(other)
is type(self):
1606 thisValue = getattr(self, name)
1607 otherValue = getattr(other, name)
1608 if isinstance(thisValue, float)
and math.isnan(thisValue):
1609 if not math.isnan(otherValue):
1611 elif thisValue != otherValue:
1617 return not self.
__eq__(other)
1620 return str(self.
toDict())
1623 return "{}({})".format(
1625 ", ".join(f
"{k}={v!r}" for k, v
in self.
toDict().
items()
if v
is not None),
1628 def compare(self, other, shortcut=True, rtol=1e-8, atol=1e-8, output=None):
1629 """Compare this configuration to another `~lsst.pex.config.Config` for
1634 other : `lsst.pex.config.Config`
1635 Other `~lsst.pex.config.Config` object to compare against this
1637 shortcut : `bool`, optional
1638 If `True`, return as soon as an inequality is found. Default is
1640 rtol : `float`, optional
1641 Relative tolerance for floating point comparisons.
1642 atol : `float`, optional
1643 Absolute tolerance for floating point comparisons.
1644 output : callable, optional
1645 A callable that takes a string, used (possibly repeatedly) to
1646 report inequalities.
1651 `True` when the two `lsst.pex.config.Config` instances are equal.
1652 `False` if there is an inequality.
1656 lsst.pex.config.compareConfigs
1660 Unselected targets of `~lsst.pex.config.RegistryField` fields and
1661 unselected choices of `~lsst.pex.config.ConfigChoiceField` fields
1662 are not considered by this method.
1664 Floating point comparisons are performed by `numpy.allclose`.
1666 name1 = self.
_name if self.
_name is not None else "config"
1667 name2 = other._name
if other._name
is not None else "config"
1668 name = getComparisonName(name1, name2)
1669 return compareConfigs(name, self, other, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
1673 """Run initialization for every subclass.
1675 Specifically registers the subclass with a YAML representer
1676 and YAML constructor (if pyyaml is available)
1683 yaml.add_representer(cls, _yaml_config_representer)
1687 """Instantiate a `Config`-subclass from serialized Python form.
1692 A serialized form of the Config as created by
1693 `Config.saveToStream`.
1698 Reconstructed `Config` instant.
1705 """Return the Config subclass required by this Config serialization.
1710 A serialized form of the Config as created by
1711 `Config.saveToStream`.
1716 The `Config` subclass associated with this config.
1725 matches = re.search(
r"^import ([\w.]+)\nassert .*==(.*?),", config_py)
1728 first_line, second_line, _ = config_py.split(
"\n", 2)
1730 f
"First two lines did not match expected form. Got:\n - {first_line}\n - {second_line}"
1733 module_name = matches.group(1)
1734 module = importlib.import_module(module_name)
1737 full_name = matches.group(2)
1740 if not full_name.startswith(module_name):
1741 raise ValueError(f
"Module name ({module_name}) inconsistent with full name ({full_name})")
1746 remainder = full_name[len(module_name) + 1 :]
1747 components = remainder.split(
".")
1749 for component
in components:
1750 pytype = getattr(pytype, component)
1755 """Create a `~lsst.pex.config.Config` from a stream.
1759 cls_ : `lsst.pex.config.Config`-type
1760 A `lsst.pex.config.Config` type (not an instance) that is instantiated
1761 with configurations in the ``stream``.
1762 stream : file-like object, `str`, or `~types.CodeType`
1763 Stream containing configuration override code.
1767 config : `lsst.pex.config.Config`
1772 lsst.pex.config.Config.loadFromStream
1775 config.loadFromStream(stream)
std::vector< SchemaItem< Flag > > * items
Any __call__(self, *Any args, **Any kwds)
saveToStream(self, outfile, root="config", skipImports=False)
__setattr__(self, attr, value, at=None, label="assignment")
loadFromStream(self, stream, root="config", filename=None, extraLocals=None)
__new__(cls, *args, **kw)
save(self, filename, root="config")
_fromPython(cls, config_py)
loadFromString(self, code, root="config", filename=None, extraLocals=None)
__delattr__(self, attr, at=None, label="deletion")
saveToString(self, skipImports=False)
formatHistory(self, name, **kwargs)
__init_subclass__(cls, **kwargs)
load(self, filename, root="config")
compare(self, other, shortcut=True, rtol=1e-8, atol=1e-8, output=None)
Mapping[str, Any] _parseTypingArgs(tuple[type,...]|tuple[str,...] params, Mapping[str, Any] kwds)
save(self, outfile, instance)
_collectImports(self, instance, imports)
__get__(self, instance, owner=None, at=None, label="default")
FieldTypeVar __get__(self, Config instance, Any owner=None, Any at=None, str label="default")
__delete__(self, instance, at=None, label="deletion")
Field[FieldTypeVar] __get__(self, None instance, Any owner=None, Any at=None, str label="default")
_compare(self, instance1, instance2, shortcut, rtol, atol, output)
_validateValue(self, value)
None __set__(self, Config instance, FieldTypeVar|None value, Any at=None, str label="assignment")
__class_getitem__(cls, tuple[type,...]|type|ForwardRef params)
__init__(self, doc, dtype=None, default=None, check=None, optional=False, deprecated=None)
_setup(self, doc, dtype, default, check, optional, source, deprecated)
__init__(self, field, config, msg)
find_spec(self, fullname, path, target=None)
daf::base::PropertySet * set
_yaml_config_representer(dumper, data)
_classFromPython(config_py)
_joinNamePath(prefix=None, name=None, index=None)
unreduceConfig(cls_, stream)