23 __all__ = [
"ConfigField"]
25 from .config
import Config, Field, FieldValidationError, _joinNamePath, _typeStr
26 from .comparison
import compareConfigs, getComparisonName
27 from .callStack
import getCallStack, getStackFrame
31 """A configuration field (`~lsst.pex.config.Field` subclass) that takes a 32 `~lsst.pex.config.Config`-type as a value. 37 A description of the configuration field. 38 dtype : `lsst.pex.config.Config`-type 39 The type of the field, which must be a subclass of 40 `lsst.pex.config.Config`. 41 default : `lsst.pex.config.Config`, optional 42 If default is `None`, the field will default to a default-constructed 43 instance of ``dtype``. Additionally, to allow for fewer deep-copies, 44 assigning an instance of ``ConfigField`` to ``dtype`` itself, is 45 considered equivalent to assigning a default-constructed sub-config. 46 This means that the argument default can be ``dtype``, as well as an 47 instance of ``dtype``. 48 check : callable, optional 49 A callback function that validates the field's value, returning `True` 50 if the value is valid, and `False` otherwise. 66 The behavior of this type of field is much like that of the base `Field` 69 Assigning to ``ConfigField`` will update all of the fields in the 73 def __init__(self, doc, dtype, default=None, check=None):
74 if not issubclass(dtype, Config):
75 raise ValueError(
"dtype=%s is not a subclass of Config" %
80 self.
_setup(doc=doc, dtype=dtype, default=default, check=check,
81 optional=
False, source=source)
84 if instance
is None or not isinstance(instance, Config):
87 value = instance._storage.get(self.name,
None)
94 def __set__(self, instance, value, at=None, label="assignment"):
97 "Cannot modify a frozen Config")
98 name = _joinNamePath(prefix=instance._name, name=self.name)
101 msg =
"Value %s is of incorrect type %s. Expected %s" % \
102 (value, _typeStr(value), _typeStr(self.
dtype))
108 oldValue = instance._storage.get(self.name,
None)
110 if value == self.
dtype:
111 instance._storage[self.name] = self.
dtype(__name=name, __at=at, __label=label)
113 instance._storage[self.name] = self.
dtype(__name=name, __at=at,
114 __label=label, **value._storage)
116 if value == self.
dtype:
118 oldValue.update(__at=at, __label=label, **value._storage)
119 history = instance._history.setdefault(self.name, [])
120 history.append((
"config value set", at, label))
123 """Rename the field in a `~lsst.pex.config.Config` (for internal use 128 instance : `lsst.pex.config.Config` 129 The config instance that contains this field. 133 This method is invoked by the `lsst.pex.config.Config` object that 134 contains this field and should not be called directly. 136 Renaming is only relevant for `~lsst.pex.config.Field` instances that 137 hold subconfigs. `~lsst.pex.config.Fields` that hold subconfigs should 138 rename each subconfig with the full field name as generated by 139 `lsst.pex.config.config._joinNamePath`. 142 value._rename(_joinNamePath(instance._name, self.name))
144 def save(self, outfile, instance):
145 """Save this field to a file (for internal use only). 149 outfile : file-like object 150 A writeable field handle. 152 The `Config` instance that contains this field. 156 This method is invoked by the `~lsst.pex.config.Config` object that 157 contains this field and should not be called directly. 159 The output consists of the documentation string 160 (`lsst.pex.config.Field.doc`) formatted as a Python comment. The second 161 line is formatted as an assignment: ``{fullname}={value}``. 163 This output can be executed with Python. 169 """Make this field read-only. 173 instance : `lsst.pex.config.Config` 174 The config instance that contains this field. 178 Freezing is only relevant for fields that hold subconfigs. Fields which 179 hold subconfigs should freeze each subconfig. 181 **Subclasses should implement this method.** 187 """Convert the field value so that it can be set as the value of an 188 item in a `dict` (for internal use only). 193 The `Config` that contains this field. 198 The field's value. See *Notes*. 202 This method invoked by the owning `~lsst.pex.config.Config` object and 203 should not be called directly. 205 Simple values are passed through. Complex data structures must be 206 manipulated. For example, a `~lsst.pex.config.Field` holding a 207 subconfig should, instead of the subconfig object, return a `dict` 208 where the keys are the field names in the subconfig, and the values are 209 the field values in the subconfig. 212 return value.toDict()
215 """Validate the field (for internal use only). 219 instance : `lsst.pex.config.Config` 220 The config instance that contains this field. 224 lsst.pex.config.FieldValidationError 225 Raised if verification fails. 229 This method provides basic validation: 231 - Ensures that the value is not `None` if the field is not optional. 232 - Ensures type correctness. 233 - Ensures that the user-provided ``check`` function is valid. 235 Most `~lsst.pex.config.Field` subclasses should call 236 `lsst.pex.config.field.Field.validate` if they re-implement 237 `~lsst.pex.config.field.Field.validate`. 242 if self.
check is not None and not self.
check(value):
243 msg =
"%s is not a valid value" %
str(value)
246 def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
247 """Compare two fields for equality. 249 Used by `ConfigField.compare`. 253 instance1 : `lsst.pex.config.Config` 254 Left-hand side config instance to compare. 255 instance2 : `lsst.pex.config.Config` 256 Right-hand side config instance to compare. 258 If `True`, this function returns as soon as an inequality if found. 260 Relative tolerance for floating point comparisons. 262 Absolute tolerance for floating point comparisons. 264 A callable that takes a string, used (possibly repeatedly) to report inequalities. 269 `True` if the fields are equal, `False` otherwise. 273 Floating point comparisons are performed by `numpy.allclose`. 275 c1 = getattr(instance1, self.name)
276 c2 = getattr(instance2, self.name)
278 _joinNamePath(instance1._name, self.name),
279 _joinNamePath(instance2._name, self.name)
281 return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
def __get__(self, instance, owner=None)
def __set__(self, instance, value, at=None, label="assignment")
def compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
def __init__(self, doc, dtype, default=None, check=None)
def __get__(self, instance, owner=None, at=None, label="default")
def _setup(self, doc, dtype, default, check, optional, source)
def freeze(self, instance)
def getStackFrame(relative=0)
def toDict(self, instance)
def rename(self, instance)
def save(self, outfile, instance)
def __set__(self, instance, value, at=None, label='assignment')
def validate(self, instance)
def getComparisonName(name1, name2)