28 __all__ = [
"ConfigField"]
30 from .config
import Config, Field, FieldValidationError, _joinNamePath, _typeStr
31 from .comparison
import compareConfigs, getComparisonName
32 from .callStack
import getCallStack, getStackFrame
36 """A configuration field (`~lsst.pex.config.Field` subclass) that takes a 37 `~lsst.pex.config.Config`-type as a value. 42 A description of the configuration field. 43 dtype : `lsst.pex.config.Config`-type 44 The type of the field, which must be a subclass of 45 `lsst.pex.config.Config`. 46 default : `lsst.pex.config.Config`, optional 47 If default is `None`, the field will default to a default-constructed 48 instance of ``dtype``. Additionally, to allow for fewer deep-copies, 49 assigning an instance of ``ConfigField`` to ``dtype`` itself, is 50 considered equivalent to assigning a default-constructed sub-config. 51 This means that the argument default can be ``dtype``, as well as an 52 instance of ``dtype``. 53 check : callable, optional 54 A callback function that validates the field's value, returning `True` 55 if the value is valid, and `False` otherwise. 56 deprecated : None or `str`, optional 57 A description of why this Field is deprecated, including removal date. 58 If not None, the string is appended to the docstring for this Field. 74 The behavior of this type of field is much like that of the base `Field` 77 Assigning to ``ConfigField`` will update all of the fields in the 81 def __init__(self, doc, dtype, default=None, check=None, deprecated=None):
82 if not issubclass(dtype, Config):
83 raise ValueError(
"dtype=%s is not a subclass of Config" %
88 self.
_setup(doc=doc, dtype=dtype, default=default, check=check,
89 optional=
False, source=source, deprecated=deprecated)
92 if instance
is None or not isinstance(instance, Config):
95 value = instance._storage.get(self.name,
None)
102 def __set__(self, instance, value, at=None, label="assignment"):
105 "Cannot modify a frozen Config")
106 name = _joinNamePath(prefix=instance._name, name=self.name)
109 msg =
"Value %s is of incorrect type %s. Expected %s" % \
110 (value, _typeStr(value), _typeStr(self.
dtype))
116 oldValue = instance._storage.get(self.name,
None)
118 if value == self.
dtype:
119 instance._storage[self.name] = self.
dtype(__name=name, __at=at, __label=label)
121 instance._storage[self.name] = self.
dtype(__name=name, __at=at,
122 __label=label, **value._storage)
124 if value == self.
dtype:
126 oldValue.update(__at=at, __label=label, **value._storage)
127 history = instance._history.setdefault(self.name, [])
128 history.append((
"config value set", at, label))
131 """Rename the field in a `~lsst.pex.config.Config` (for internal use 136 instance : `lsst.pex.config.Config` 137 The config instance that contains this field. 141 This method is invoked by the `lsst.pex.config.Config` object that 142 contains this field and should not be called directly. 144 Renaming is only relevant for `~lsst.pex.config.Field` instances that 145 hold subconfigs. `~lsst.pex.config.Fields` that hold subconfigs should 146 rename each subconfig with the full field name as generated by 147 `lsst.pex.config.config._joinNamePath`. 150 value._rename(_joinNamePath(instance._name, self.name))
152 def _collectImports(self, instance, imports):
154 value._collectImports()
155 imports |= value._imports
157 def save(self, outfile, instance):
158 """Save this field to a file (for internal use only). 162 outfile : file-like object 163 A writeable field handle. 165 The `Config` instance that contains this field. 169 This method is invoked by the `~lsst.pex.config.Config` object that 170 contains this field and should not be called directly. 172 The output consists of the documentation string 173 (`lsst.pex.config.Field.doc`) formatted as a Python comment. The second 174 line is formatted as an assignment: ``{fullname}={value}``. 176 This output can be executed with Python. 182 """Make this field read-only. 186 instance : `lsst.pex.config.Config` 187 The config instance that contains this field. 191 Freezing is only relevant for fields that hold subconfigs. Fields which 192 hold subconfigs should freeze each subconfig. 194 **Subclasses should implement this method.** 200 """Convert the field value so that it can be set as the value of an 201 item in a `dict` (for internal use only). 206 The `Config` that contains this field. 211 The field's value. See *Notes*. 215 This method invoked by the owning `~lsst.pex.config.Config` object and 216 should not be called directly. 218 Simple values are passed through. Complex data structures must be 219 manipulated. For example, a `~lsst.pex.config.Field` holding a 220 subconfig should, instead of the subconfig object, return a `dict` 221 where the keys are the field names in the subconfig, and the values are 222 the field values in the subconfig. 225 return value.toDict()
228 """Validate the field (for internal use only). 232 instance : `lsst.pex.config.Config` 233 The config instance that contains this field. 237 lsst.pex.config.FieldValidationError 238 Raised if verification fails. 242 This method provides basic validation: 244 - Ensures that the value is not `None` if the field is not optional. 245 - Ensures type correctness. 246 - Ensures that the user-provided ``check`` function is valid. 248 Most `~lsst.pex.config.Field` subclasses should call 249 `lsst.pex.config.field.Field.validate` if they re-implement 250 `~lsst.pex.config.field.Field.validate`. 255 if self.
check is not None and not self.
check(value):
256 msg =
"%s is not a valid value" % str(value)
259 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
260 """Compare two fields for equality. 262 Used by `ConfigField.compare`. 266 instance1 : `lsst.pex.config.Config` 267 Left-hand side config instance to compare. 268 instance2 : `lsst.pex.config.Config` 269 Right-hand side config instance to compare. 271 If `True`, this function returns as soon as an inequality if found. 273 Relative tolerance for floating point comparisons. 275 Absolute tolerance for floating point comparisons. 277 A callable that takes a string, used (possibly repeatedly) to 283 `True` if the fields are equal, `False` otherwise. 287 Floating point comparisons are performed by `numpy.allclose`. 289 c1 = getattr(instance1, self.name)
290 c2 = getattr(instance2, self.name)
292 _joinNamePath(instance1._name, self.name),
293 _joinNamePath(instance2._name, self.name)
295 return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
def compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
def __get__(self, instance, owner=None)
def validate(self, instance)
def rename(self, instance)
def getStackFrame(relative=0)
def __get__(self, instance, owner=None, at=None, label="default")
def __set__(self, instance, value, at=None, label='assignment')
def save(self, outfile, instance)
def __init__(self, doc, dtype, default=None, check=None, deprecated=None)
def getComparisonName(name1, name2)
def __set__(self, instance, value, at=None, label="assignment")
def toDict(self, instance)
def freeze(self, instance)
def _setup(self, doc, dtype, default, check, optional, source, deprecated)