28 __all__ = (
"Config",
"ConfigMeta",
"Field",
"FieldValidationError")
50 from .comparison
import getComparisonName, compareScalars, compareConfigs
51 from .callStack
import getStackFrame, getCallStack
54 YamlLoaders = (yaml.Loader, yaml.FullLoader, yaml.SafeLoader, yaml.UnsafeLoader)
58 from yaml
import CLoader
59 YamlLoaders += (CLoader,)
64 def _joinNamePath(prefix=None, name=None, index=None):
65 """Generate nested configuration names.
67 if not prefix
and not name:
68 raise ValueError(
"Invalid name: cannot be None")
72 name = prefix +
"." + name
75 return "%s[%r]" % (name, index)
80 def _autocast(x, dtype):
81 """Cast a value to a type, if appropriate.
88 Data type, such as `float`, `int`, or `str`.
93 If appropriate, the returned value is ``x`` cast to the given type
94 ``dtype``. If the cast cannot be performed the original value of
97 if dtype == float
and isinstance(x, int):
103 """Generate a fully-qualified type name.
108 Fully-qualified type name.
112 This function is used primarily for writing config files to be executed
113 later upon with the 'load' function.
115 if hasattr(x,
'__module__')
and hasattr(x,
'__name__'):
119 if (sys.version_info.major <= 2
and xtype.__module__ ==
'__builtin__')
or xtype.__module__ ==
'builtins':
120 return xtype.__name__
122 return "%s.%s" % (xtype.__module__, xtype.__name__)
126 def _yaml_config_representer(dumper, data):
127 """Represent a Config object in a form suitable for YAML.
129 Stores the serialized stream as a scalar block string.
131 stream = io.StringIO()
132 data.saveToStream(stream)
133 config_py = stream.getvalue()
137 config_py = config_py.rstrip() +
"\n"
141 config_py = re.sub(
r"\s+$",
"\n", config_py, flags=re.MULTILINE)
144 return dumper.represent_scalar(
"lsst.pex.config.Config", config_py, style=
"|")
146 def _yaml_config_constructor(loader, node):
147 """Construct a config from YAML"""
148 config_py = loader.construct_scalar(node)
149 return Config._fromPython(config_py)
153 for loader
in YamlLoaders:
154 yaml.add_constructor(
"lsst.pex.config.Config", _yaml_config_constructor, Loader=loader)
158 """A metaclass for `lsst.pex.config.Config`.
162 ``ConfigMeta`` adds a dictionary containing all `~lsst.pex.config.Field`
163 class attributes as a class attribute called ``_fields``, and adds
164 the name of each field as an instance variable of the field itself (so you
165 don't have to pass the name of the field to the field constructor).
169 type.__init__(cls, name, bases, dict_)
173 def getFields(classtype):
175 bases =
list(classtype.__bases__)
178 fields.update(getFields(b))
180 for k, v
in classtype.__dict__.items():
181 if isinstance(v, Field):
185 fields = getFields(cls)
186 for k, v
in fields.items():
187 setattr(cls, k, copy.deepcopy(v))
190 if isinstance(value, Field):
192 cls.
_fields_fields[name] = value
193 type.__setattr__(cls, name, value)
197 """Raised when a ``~lsst.pex.config.Field`` is not valid in a
198 particular ``~lsst.pex.config.Config``.
202 field : `lsst.pex.config.Field`
203 The field that was not valid.
204 config : `lsst.pex.config.Config`
205 The config containing the invalid field.
207 Text describing why the field was not valid.
212 """Type of the `~lsst.pex.config.Field` that incurred the error.
216 """Name of the `~lsst.pex.config.Field` instance that incurred the
221 lsst.pex.config.Field.name
224 self.
fullnamefullname = _joinNamePath(config._name, field.name)
225 """Fully-qualified name of the `~lsst.pex.config.Field` instance
229 self.
historyhistory = config.history.setdefault(field.name, [])
230 """Full history of all changes to the `~lsst.pex.config.Field`
235 """File and line number of the `~lsst.pex.config.Field` definition.
239 error =
"%s '%s' failed validation: %s\n"\
240 "For more information see the Field definition at:\n%s"\
241 " and the Config definition at:\n%s" % \
248 """A field in a `~lsst.pex.config.Config` that supports `int`, `float`,
249 `complex`, `bool`, and `str` data types.
254 A description of the field for users.
256 The field's data type. ``Field`` only supports basic data types:
257 `int`, `float`, `complex`, `bool`, and `str`. See
258 `Field.supportedTypes`.
259 default : object, optional
260 The field's default value.
261 check : callable, optional
262 A callable that is called with the field's value. This callable should
263 return `False` if the value is invalid. More complex inter-field
264 validation can be written as part of the
265 `lsst.pex.config.Config.validate` method.
266 optional : `bool`, optional
267 This sets whether the field is considered optional, and therefore
268 doesn't need to be set by the user. When `False`,
269 `lsst.pex.config.Config.validate` fails if the field's value is `None`.
270 deprecated : None or `str`, optional
271 A description of why this Field is deprecated, including removal date.
272 If not None, the string is appended to the docstring for this Field.
277 Raised when the ``dtype`` parameter is not one of the supported types
278 (see `Field.supportedTypes`).
294 ``Field`` instances (including those of any subclass of ``Field``) are used
295 as class attributes of `~lsst.pex.config.Config` subclasses (see the
296 example, below). ``Field`` attributes work like the `property` attributes
297 of classes that implement custom setters and getters. `Field` attributes
298 belong to the class, but operate on the instance. Formally speaking,
299 `Field` attributes are `descriptors
300 <https://docs.python.org/3/howto/descriptor.html>`_.
302 When you access a `Field` attribute on a `Config` instance, you don't
303 get the `Field` instance itself. Instead, you get the value of that field,
304 which might be a simple type (`int`, `float`, `str`, `bool`) or a custom
305 container type (like a `lsst.pex.config.List`) depending on the field's
306 type. See the example, below.
310 Instances of ``Field`` should be used as class attributes of
311 `lsst.pex.config.Config` subclasses:
313 >>> from lsst.pex.config import Config, Field
314 >>> class Example(Config):
315 ... myInt = Field("An integer field.", int, default=0)
317 >>> print(config.myInt)
320 >>> print(config.myInt)
324 supportedTypes =
set((str, bool, float, int, complex))
325 """Supported data types for field values (`set` of types).
328 def __init__(self, doc, dtype, default=None, check=None, optional=False, deprecated=None):
330 raise ValueError(
"Unsupported Field dtype %s" % _typeStr(dtype))
333 self.
_setup_setup(doc=doc, dtype=dtype, default=default, check=check, optional=optional, source=source,
334 deprecated=deprecated)
336 def _setup(self, doc, dtype, default, check, optional, source, deprecated):
337 """Set attributes, usually during initialization.
340 """Data type for the field.
344 if deprecated
is not None:
345 doc = f
"{doc} Deprecated: {deprecated}"
347 """A description of the field (`str`).
351 """If not None, a description of why this field is deprecated (`str`).
354 self.
__doc____doc__ = f
"{doc} (`{dtype.__name__}`"
355 if optional
or default
is not None:
356 self.
__doc____doc__ += f
", default ``{default!r}``"
360 """Default value for this field.
364 """A user-defined function that validates the value of the field.
368 """Flag that determines if the field is required to be set (`bool`).
370 When `False`, `lsst.pex.config.Config.validate` will fail if the
371 field's value is `None`.
375 """The stack frame where this field is defined (`list` of
376 `lsst.pex.config.callStack.StackFrame`).
380 """Rename the field in a `~lsst.pex.config.Config` (for internal use
385 instance : `lsst.pex.config.Config`
386 The config instance that contains this field.
390 This method is invoked by the `lsst.pex.config.Config` object that
391 contains this field and should not be called directly.
393 Renaming is only relevant for `~lsst.pex.config.Field` instances that
394 hold subconfigs. `~lsst.pex.config.Fields` that hold subconfigs should
395 rename each subconfig with the full field name as generated by
396 `lsst.pex.config.config._joinNamePath`.
401 """Validate the field (for internal use only).
405 instance : `lsst.pex.config.Config`
406 The config instance that contains this field.
410 lsst.pex.config.FieldValidationError
411 Raised if verification fails.
415 This method provides basic validation:
417 - Ensures that the value is not `None` if the field is not optional.
418 - Ensures type correctness.
419 - Ensures that the user-provided ``check`` function is valid.
421 Most `~lsst.pex.config.Field` subclasses should call
422 `lsst.pex.config.field.Field.validate` if they re-implement
423 `~lsst.pex.config.field.Field.validate`.
425 value = self.__get__(instance)
426 if not self.optional
and value
is None:
427 raise FieldValidationError(self, instance,
"Required value cannot be None")
430 """Make this field read-only (for internal use only).
434 instance : `lsst.pex.config.Config`
435 The config instance that contains this field.
439 Freezing is only relevant for fields that hold subconfigs. Fields which
440 hold subconfigs should freeze each subconfig.
442 **Subclasses should implement this method.**
446 def _validateValue(self, value):
452 The value being validated.
457 Raised if the value's type is incompatible with the field's
460 Raised if the value is rejected by the ``check`` method.
465 if not isinstance(value, self.dtype):
466 msg =
"Value %s is of incorrect type %s. Expected type %s" % \
467 (value, _typeStr(value), _typeStr(self.dtype))
469 if self.check
is not None and not self.check(value):
470 msg =
"Value %s is not a valid value" % str(value)
471 raise ValueError(msg)
473 def _collectImports(self, instance, imports):
474 """This function should call the _collectImports method on all config
475 objects the field may own, and union them with the supplied imports
480 instance : instance or subclass of `lsst.pex.config.Config`
481 A config object that has this field defined on it
483 Set of python modules that need imported after persistence
487 def save(self, outfile, instance):
488 """Save this field to a file (for internal use only).
492 outfile : file-like object
493 A writeable field handle.
495 The `Config` instance that contains this field.
499 This method is invoked by the `~lsst.pex.config.Config` object that
500 contains this field and should not be called directly.
502 The output consists of the documentation string
503 (`lsst.pex.config.Field.doc`) formatted as a Python comment. The second
504 line is formatted as an assignment: ``{fullname}={value}``.
506 This output can be executed with Python.
508 value = self.__get__(instance)
509 fullname = _joinNamePath(instance._name, self.name)
511 if self.deprecated
and value == self.default:
516 doc =
"# " + str(self.doc).replace(
"\n",
"\n# ")
517 if isinstance(value, float)
and not math.isfinite(value):
519 outfile.write(
u"{}\n{}=float('{!r}')\n\n".
format(doc, fullname, value))
521 outfile.write(
u"{}\n{}={!r}\n\n".
format(doc, fullname, value))
524 """Convert the field value so that it can be set as the value of an
525 item in a `dict` (for internal use only).
530 The `Config` that contains this field.
535 The field's value. See *Notes*.
539 This method invoked by the owning `~lsst.pex.config.Config` object and
540 should not be called directly.
542 Simple values are passed through. Complex data structures must be
543 manipulated. For example, a `~lsst.pex.config.Field` holding a
544 subconfig should, instead of the subconfig object, return a `dict`
545 where the keys are the field names in the subconfig, and the values are
546 the field values in the subconfig.
548 return self.
__get____get__(instance)
550 def __get__(self, instance, owner=None, at=None, label="default"):
551 """Define how attribute access should occur on the Config instance
552 This is invoked by the owning config object and should not be called
555 When the field attribute is accessed on a Config class object, it
556 returns the field object itself in order to allow inspection of
559 When the field attribute is access on a config instance, the actual
560 value described by the field (and held by the Config instance) is
568 return instance._storage[self.name]
569 except AttributeError:
570 if not isinstance(instance, Config):
573 raise AttributeError(f
"Config {instance} is missing "
574 "_storage attribute, likely"
575 " incorrectly initialized")
577 def __set__(self, instance, value, at=None, label='assignment'):
578 """Set an attribute on the config instance.
582 instance : `lsst.pex.config.Config`
583 The config instance that contains this field.
585 Value to set on this field.
586 at : `list` of `lsst.pex.config.callStack.StackFrame`
587 The call stack (created by
588 `lsst.pex.config.callStack.getCallStack`).
589 label : `str`, optional
590 Event label for the history.
594 This method is invoked by the owning `lsst.pex.config.Config` object
595 and should not be called directly.
597 Derived `~lsst.pex.config.Field` classes may need to override the
598 behavior. When overriding ``__set__``, `~lsst.pex.config.Field` authors
599 should follow the following rules:
601 - Do not allow modification of frozen configs.
602 - Validate the new value **before** modifying the field. Except if the
603 new value is `None`. `None` is special and no attempt should be made
604 to validate it until `lsst.pex.config.Config.validate` is called.
605 - Do not modify the `~lsst.pex.config.Config` instance to contain
607 - If the field is modified, update the history of the
608 `lsst.pex.config.field.Field` to reflect the changes.
610 In order to decrease the need to implement this method in derived
611 `~lsst.pex.config.Field` types, value validation is performed in the
612 `lsst.pex.config.Field._validateValue`. If only the validation step
613 differs in the derived `~lsst.pex.config.Field`, it is simpler to
614 implement `lsst.pex.config.Field._validateValue` than to reimplement
615 ``__set__``. More complicated behavior, however, may require
621 history = instance._history.setdefault(self.name, [])
622 if value
is not None:
623 value = _autocast(value, self.
dtypedtype)
626 except BaseException
as e:
629 instance._storage[self.name] = value
632 history.append((value, at, label))
635 """Delete an attribute from a `lsst.pex.config.Config` instance.
639 instance : `lsst.pex.config.Config`
640 The config instance that contains this field.
641 at : `list` of `lsst.pex.config.callStack.StackFrame`
642 The call stack (created by
643 `lsst.pex.config.callStack.getCallStack`).
644 label : `str`, optional
645 Event label for the history.
649 This is invoked by the owning `~lsst.pex.config.Config` object and
650 should not be called directly.
654 self.
__set____set__(instance,
None, at=at, label=label)
656 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
657 """Compare a field (named `Field.name`) in two
658 `~lsst.pex.config.Config` instances for equality.
662 instance1 : `lsst.pex.config.Config`
663 Left-hand side `Config` instance to compare.
664 instance2 : `lsst.pex.config.Config`
665 Right-hand side `Config` instance to compare.
666 shortcut : `bool`, optional
668 rtol : `float`, optional
669 Relative tolerance for floating point comparisons.
670 atol : `float`, optional
671 Absolute tolerance for floating point comparisons.
672 output : callable, optional
673 A callable that takes a string, used (possibly repeatedly) to
678 This method must be overridden by more complex `Field` subclasses.
682 lsst.pex.config.compareScalars
684 v1 = getattr(instance1, self.name)
685 v2 = getattr(instance2, self.name)
687 _joinNamePath(instance1._name, self.name),
688 _joinNamePath(instance2._name, self.name)
690 return compareScalars(name, v1, v2, dtype=self.
dtypedtype, rtol=rtol, atol=atol, output=output)
694 """Importer (for `sys.meta_path`) that records which modules are being
697 *This class does not do any importing itself.*
701 Use this class as a context manager to ensure it is properly uninstalled
704 >>> with RecordingImporter() as importer:
706 ... import numpy as np
707 ... print("Imported: " + importer.getModules())
715 sys.meta_path = [self] + sys.meta_path
723 """Uninstall the importer.
728 """Called as part of the ``import`` chain of events.
735 """Get the set of modules that were imported.
739 modules : `set` of `str`
740 Set of imported module names.
746 """Base class for configuration (*config*) objects.
750 A ``Config`` object will usually have several `~lsst.pex.config.Field`
751 instances as class attributes. These are used to define most of the base
754 ``Config`` implements a mapping API that provides many `dict`-like methods,
755 such as `keys`, `values`, `items`, `iteritems`, `iterkeys`, and
756 `itervalues`. ``Config`` instances also support the ``in`` operator to
757 test if a field is in the config. Unlike a `dict`, ``Config`` classes are
758 not subscriptable. Instead, access individual fields as attributes of the
759 configuration instance.
763 Config classes are subclasses of ``Config`` that have
764 `~lsst.pex.config.Field` instances (or instances of
765 `~lsst.pex.config.Field` subclasses) as class attributes:
767 >>> from lsst.pex.config import Config, Field, ListField
768 >>> class DemoConfig(Config):
769 ... intField = Field(doc="An integer field", dtype=int, default=42)
770 ... listField = ListField(doc="List of favorite beverages.", dtype=str,
771 ... default=['coffee', 'green tea', 'water'])
773 >>> config = DemoConfig()
775 Configs support many `dict`-like APIs:
778 ['intField', 'listField']
779 >>> 'intField' in config
782 Individual fields can be accessed as attributes of the configuration:
786 >>> config.listField.append('earl grey tea')
787 >>> print(config.listField)
788 ['coffee', 'green tea', 'water', 'earl grey tea']
792 """Iterate over fields.
802 List of `lsst.pex.config.Field` names.
806 lsst.pex.config.Config.iterkeys
816 List of field values.
820 lsst.pex.config.Config.itervalues
825 """Get configurations as ``(field name, field value)`` pairs.
830 List of tuples for each configuration. Tuple items are:
837 lsst.pex.config.Config.iteritems
842 """Iterate over (field name, field value) pairs.
854 lsst.pex.config.Config.items
859 """Iterate over field values.
868 lsst.pex.config.Config.values
873 """Iterate over field names
878 A field's key (attribute name).
882 lsst.pex.config.Config.values
887 """!Return True if the specified field exists in this config
889 @param[in] name field name to test for
894 """Allocate a new `lsst.pex.config.Config` object.
896 In order to ensure that all Config object are always in a proper state
897 when handed to users or to derived `~lsst.pex.config.Config` classes,
898 some attributes are handled at allocation time rather than at
901 This ensures that even if a derived `~lsst.pex.config.Config` class
902 implements ``__init__``, its author does not need to be concerned about
903 when or even the base ``Config.__init__`` should be called.
905 name = kw.pop(
"__name",
None)
908 kw.pop(
"__label",
"default")
910 instance = object.__new__(cls)
911 instance._frozen =
False
912 instance._name = name
913 instance._storage = {}
914 instance._history = {}
915 instance._imports =
set()
917 for field
in instance._fields.values():
918 instance._history[field.name] = []
919 field.__set__(instance, field.default, at=at + [field.source], label=
"default")
921 instance.setDefaults()
923 instance.update(__at=at, **kw)
927 """Reduction for pickling (function with arguments to reproduce).
929 We need to condense and reconstitute the `~lsst.pex.config.Config`,
930 since it may contain lambdas (as the ``check`` elements) that cannot
935 stream = io.StringIO()
937 return (unreduceConfig, (self.__class__, stream.getvalue().
encode()))
940 """Subclass hook for computing defaults.
944 Derived `~lsst.pex.config.Config` classes that must compute defaults
945 rather than using the `~lsst.pex.config.Field` instances's defaults
946 should do so here. To correctly use inherited defaults,
947 implementations of ``setDefaults`` must call their base class's
953 """Update values of fields specified by the keyword arguments.
958 Keywords are configuration field names. Values are configuration
963 The ``__at`` and ``__label`` keyword arguments are special internal
964 keywords. They are used to strip out any internal steps from the
965 history tracebacks of the config. Do not modify these keywords to
966 subvert a `~lsst.pex.config.Config` instance's history.
970 This is a config with three fields:
972 >>> from lsst.pex.config import Config, Field
973 >>> class DemoConfig(Config):
974 ... fieldA = Field(doc='Field A', dtype=int, default=42)
975 ... fieldB = Field(doc='Field B', dtype=bool, default=True)
976 ... fieldC = Field(doc='Field C', dtype=str, default='Hello world')
978 >>> config = DemoConfig()
980 These are the default values of each field:
982 >>> for name, value in config.iteritems():
983 ... print(f"{name}: {value}")
987 fieldC: 'Hello world'
989 Using this method to update ``fieldA`` and ``fieldC``:
991 >>> config.update(fieldA=13, fieldC='Updated!')
993 Now the values of each field are:
995 >>> for name, value in config.iteritems():
996 ... print(f"{name}: {value}")
1003 label = kw.pop(
"__label",
"update")
1005 for name, value
in kw.items():
1007 field = self._fields[name]
1008 field.__set__(self, value, at=at, label=label)
1010 raise KeyError(
"No field of name %s exists in config type %s" % (name, _typeStr(self)))
1012 def load(self, filename, root="config"):
1013 """Modify this config in place by executing the Python code in a
1019 Name of the configuration file. A configuration file is Python
1021 root : `str`, optional
1022 Name of the variable in file that refers to the config being
1025 For example, the value of root is ``"config"`` and the file
1030 Then this config's field ``myField`` is set to ``5``.
1032 **Deprecated:** For backwards compatibility, older config files
1033 that use ``root="root"`` instead of ``root="config"`` will be
1034 loaded with a warning printed to `sys.stderr`. This feature will be
1035 removed at some point.
1039 lsst.pex.config.Config.loadFromStream
1040 lsst.pex.config.Config.save
1041 lsst.pex.config.Config.saveFromStream
1043 with open(filename,
"r")
as f:
1044 code = compile(f.read(), filename=filename, mode=
"exec")
1045 self.
loadFromStreamloadFromStream(stream=code, root=root, filename=filename)
1048 """Modify this Config in place by executing the Python code in the
1053 stream : file-like object, `str`, or compiled string
1054 Stream containing configuration override code.
1055 root : `str`, optional
1056 Name of the variable in file that refers to the config being
1059 For example, the value of root is ``"config"`` and the file
1064 Then this config's field ``myField`` is set to ``5``.
1066 **Deprecated:** For backwards compatibility, older config files
1067 that use ``root="root"`` instead of ``root="config"`` will be
1068 loaded with a warning printed to `sys.stderr`. This feature will be
1069 removed at some point.
1070 filename : `str`, optional
1071 Name of the configuration file, or `None` if unknown or contained
1072 in the stream. Used for error reporting.
1076 lsst.pex.config.Config.load
1077 lsst.pex.config.Config.save
1078 lsst.pex.config.Config.saveFromStream
1081 globals = {
"__file__": filename}
1083 local = {root: self}
1084 exec(stream, globals, local)
1085 except NameError
as e:
1086 if root ==
"config" and "root" in e.args[0]:
1087 if filename
is None:
1091 filename = getattr(stream,
"co_filename",
None)
1092 if filename
is None:
1093 filename = getattr(stream,
"name",
"?")
1094 print(f
"Config override file {filename!r}"
1095 " appears to use 'root' instead of 'config'; trying with 'root'", file=sys.stderr)
1096 local = {
"root": self}
1097 exec(stream, globals, local)
1101 self._imports.
update(importer.getModules())
1103 def save(self, filename, root="config"):
1104 """Save a Python script to the named file, which, when loaded,
1105 reproduces this config.
1110 Desination filename of this configuration.
1111 root : `str`, optional
1112 Name to use for the root config variable. The same value must be
1113 used when loading (see `lsst.pex.config.Config.load`).
1117 lsst.pex.config.Config.saveToStream
1118 lsst.pex.config.Config.load
1119 lsst.pex.config.Config.loadFromStream
1121 d = os.path.dirname(filename)
1122 with tempfile.NamedTemporaryFile(mode=
"w", delete=
False, dir=d)
as outfile:
1127 umask = os.umask(0o077)
1129 os.chmod(outfile.name, (~umask & 0o666))
1133 shutil.move(outfile.name, filename)
1136 """Save a configuration file to a stream, which, when loaded,
1137 reproduces this config.
1141 outfile : file-like object
1142 Destination file object write the config into. Accepts strings not
1145 Name to use for the root config variable. The same value must be
1146 used when loading (see `lsst.pex.config.Config.load`).
1147 skipImports : `bool`, optional
1148 If `True` then do not include ``import`` statements in output,
1149 this is to support human-oriented output from ``pipetask`` where
1150 additional clutter is not useful.
1154 lsst.pex.config.Config.save
1155 lsst.pex.config.Config.load
1156 lsst.pex.config.Config.loadFromStream
1158 tmp = self.
_name_name
1164 self._imports.remove(self.__module__)
1165 configType =
type(self)
1166 typeString = _typeStr(configType)
1167 outfile.write(f
"import {configType.__module__}\n")
1168 outfile.write(f
"assert type({root})=={typeString}, 'config is of type %s.%s instead of "
1169 f
"{typeString}' % (type({root}).__module__, type({root}).__name__)\n")
1170 for imp
in self._imports:
1171 if imp
in sys.modules
and sys.modules[imp]
is not None:
1172 outfile.write(
u"import {}\n".
format(imp))
1173 self.
_save_save(outfile)
1178 """Make this config, and all subconfigs, read-only.
1184 def _save(self, outfile):
1185 """Save this config to an open stream object.
1189 outfile : file-like object
1190 Destination file object write the config into. Accepts strings not
1194 field.save(outfile, self)
1196 def _collectImports(self):
1197 """Adds module containing self to the list of things to import and
1198 then loops over all the fields in the config calling a corresponding
1199 collect method. The field method will call _collectImports on any
1200 configs it may own and return the set of things to import. This
1201 returned set will be merged with the set of imports for this config
1204 self._imports.add(self.__module__)
1206 field._collectImports(self, self._imports)
1209 """Make a dictionary of field names and their values.
1214 Dictionary with keys that are `~lsst.pex.config.Field` names.
1215 Values are `~lsst.pex.config.Field` values.
1219 lsst.pex.config.Field.toDict
1223 This method uses the `~lsst.pex.config.Field.toDict` method of
1224 individual fields. Subclasses of `~lsst.pex.config.Field` may need to
1225 implement a ``toDict`` method for *this* method to work.
1229 dict_[name] = field.toDict(self)
1233 """Get all the field names in the config, recursively.
1237 names : `list` of `str`
1244 with io.StringIO()
as strFd:
1246 contents = strFd.getvalue()
1252 for line
in contents.split(
"\n"):
1253 if re.search(
r"^((assert|import)\s+|\s*$|#)", line):
1256 mat = re.search(
r"^(?:config\.)?([^=]+)\s*=\s*.*", line)
1258 keys.append(mat.group(1))
1262 def _rename(self, name):
1263 """Rename this config object in its parent `~lsst.pex.config.Config`.
1268 New name for this config in its parent `~lsst.pex.config.Config`.
1272 This method uses the `~lsst.pex.config.Field.rename` method of
1273 individual `lsst.pex.config.Field` instances.
1274 `lsst.pex.config.Field` subclasses may need to implement a ``rename``
1275 method for *this* method to work.
1279 lsst.pex.config.Field.rename
1281 self.
_name_name = name
1286 """Validate the Config, raising an exception if invalid.
1290 lsst.pex.config.FieldValidationError
1291 Raised if verification fails.
1295 The base class implementation performs type checks on all fields by
1296 calling their `~lsst.pex.config.Field.validate` methods.
1298 Complex single-field validation can be defined by deriving new Field
1299 types. For convenience, some derived `lsst.pex.config.Field`-types
1300 (`~lsst.pex.config.ConfigField` and
1301 `~lsst.pex.config.ConfigChoiceField`) are defined in `lsst.pex.config`
1302 that handle recursing into subconfigs.
1304 Inter-field relationships should only be checked in derived
1305 `~lsst.pex.config.Config` classes after calling this method, and base
1306 validation is complete.
1309 field.validate(self)
1312 """Format a configuration field's history to a human-readable format.
1317 Name of a `~lsst.pex.config.Field` in this config.
1319 Keyword arguments passed to `lsst.pex.config.history.format`.
1324 A string containing the formatted history.
1328 lsst.pex.config.history.format
1331 return pexHist.format(self, name, **kwargs)
1333 history = property(
lambda x: x._history)
1334 """Read-only history.
1338 """Set an attribute (such as a field's value).
1342 Unlike normal Python objects, `~lsst.pex.config.Config` objects are
1343 locked such that no additional attributes nor properties may be added
1344 to them dynamically.
1346 Although this is not the standard Python behavior, it helps to protect
1347 users from accidentally mispelling a field name, or trying to set a
1350 if attr
in self.
_fields_fields:
1351 if self.
_fields_fields[attr].deprecated
is not None:
1352 fullname = _joinNamePath(self.
_name_name, self.
_fields_fields[attr].name)
1353 warnings.warn(f
"Config field {fullname} is deprecated: {self._fields[attr].deprecated}",
1354 FutureWarning, stacklevel=2)
1358 self.
_fields_fields[attr].__set__(self, value, at=at, label=label)
1359 elif hasattr(getattr(self.__class__, attr,
None),
'__set__'):
1361 return object.__setattr__(self, attr, value)
1362 elif attr
in self.__dict__
or attr
in (
"_name",
"_history",
"_storage",
"_frozen",
"_imports"):
1364 self.__dict__[attr] = value
1367 raise AttributeError(
"%s has no attribute %s" % (_typeStr(self), attr))
1370 if attr
in self.
_fields_fields:
1373 self.
_fields_fields[attr].__delete__(self, at=at, label=label)
1375 object.__delattr__(self, attr)
1379 for name
in self.
_fields_fields:
1380 thisValue = getattr(self, name)
1381 otherValue = getattr(other, name)
1382 if isinstance(thisValue, float)
and math.isnan(thisValue):
1383 if not math.isnan(otherValue):
1385 elif thisValue != otherValue:
1391 return not self.
__eq____eq__(other)
1394 return str(self.
toDicttoDict())
1399 ", ".join(
"%s=%r" % (k, v)
for k, v
in self.
toDicttoDict().
items()
if v
is not None)
1402 def compare(self, other, shortcut=True, rtol=1E-8, atol=1E-8, output=None):
1403 """Compare this configuration to another `~lsst.pex.config.Config` for
1408 other : `lsst.pex.config.Config`
1409 Other `~lsst.pex.config.Config` object to compare against this
1411 shortcut : `bool`, optional
1412 If `True`, return as soon as an inequality is found. Default is
1414 rtol : `float`, optional
1415 Relative tolerance for floating point comparisons.
1416 atol : `float`, optional
1417 Absolute tolerance for floating point comparisons.
1418 output : callable, optional
1419 A callable that takes a string, used (possibly repeatedly) to
1420 report inequalities.
1425 `True` when the two `lsst.pex.config.Config` instances are equal.
1426 `False` if there is an inequality.
1430 lsst.pex.config.compareConfigs
1434 Unselected targets of `~lsst.pex.config.RegistryField` fields and
1435 unselected choices of `~lsst.pex.config.ConfigChoiceField` fields
1436 are not considered by this method.
1438 Floating point comparisons are performed by `numpy.allclose`.
1440 name1 = self.
_name_name
if self.
_name_name
is not None else "config"
1441 name2 = other._name
if other._name
is not None else "config"
1444 rtol=rtol, atol=atol, output=output)
1448 """Run initialization for every subclass.
1450 Specifically registers the subclass with a YAML representer
1451 and YAML constructor (if pyyaml is available)
1458 yaml.add_representer(cls, _yaml_config_representer)
1461 def _fromPython(cls, config_py):
1462 """Instantiate a `Config`-subclass from serialized Python form.
1467 A serialized form of the Config as created by
1468 `Config.saveToStream`.
1473 Reconstructed `Config` instant.
1475 cls = _classFromPython(config_py)
1479 def _classFromPython(config_py):
1480 """Return the Config subclass required by this Config serialization.
1485 A serialized form of the Config as created by
1486 `Config.saveToStream`.
1491 The `Config` subclass associated with this config.
1500 matches = re.search(
r"^import ([\w.]+)\nassert .*==(.*?),", config_py)
1503 first_line, second_line, _ = config_py.split(
"\n", 2)
1504 raise ValueError(
"First two lines did not match expected form. Got:\n"
1505 f
" - {first_line}\n"
1506 f
" - {second_line}")
1508 module_name = matches.group(1)
1509 module = importlib.import_module(module_name)
1512 full_name = matches.group(2)
1515 if not full_name.startswith(module_name):
1516 raise ValueError(f
"Module name ({module_name}) inconsistent with full name ({full_name})")
1521 remainder = full_name[len(module_name)+1:]
1522 components = remainder.split(
".")
1524 for component
in components:
1525 pytype = getattr(pytype, component)
1530 """Create a `~lsst.pex.config.Config` from a stream.
1534 cls : `lsst.pex.config.Config`-type
1535 A `lsst.pex.config.Config` type (not an instance) that is instantiated
1536 with configurations in the ``stream``.
1537 stream : file-like object, `str`, or compiled string
1538 Stream containing configuration override code.
1542 config : `lsst.pex.config.Config`
1547 lsst.pex.config.Config.loadFromStream
1550 config.loadFromStream(stream)
def compare(self, other, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
def __init_subclass__(cls, **kwargs)
def __delattr__(self, attr, at=None, label="deletion")
def __new__(cls, *args, **kw)
def loadFromStream(self, stream, root="config", filename=None)
def saveToStream(self, outfile, root="config", skipImports=False)
def __contains__(self, name)
Return True if the specified field exists in this config.
def load(self, filename, root="config")
def __setattr__(self, attr, value, at=None, label="assignment")
def formatHistory(self, name, **kwargs)
def _collectImports(self)
def save(self, filename, root="config")
def __delete__(self, instance, at=None, label='deletion')
def _validateValue(self, value)
def rename(self, instance)
def __get__(self, instance, owner=None, at=None, label="default")
def freeze(self, instance)
def __set__(self, instance, value, at=None, label='assignment')
def validate(self, instance)
def save(self, outfile, instance)
def __init__(self, doc, dtype, default=None, check=None, optional=False, deprecated=None)
def _setup(self, doc, dtype, default, check, optional, source, deprecated)
def toDict(self, instance)
def __init__(self, field, config, msg)
def __exit__(self, *args)
def find_module(self, fullname, path=None)
daf::base::PropertyList * list
daf::base::PropertySet * set
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 unreduceConfig(cls, stream)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
pybind11::bytes encode(Region const &self)
Encode a Region as a pybind11 bytes object.