LSSTApplications  17.0+11,17.0+34,17.0+56,17.0+57,17.0+59,17.0+7,17.0-1-g377950a+33,17.0.1-1-g114240f+2,17.0.1-1-g4d4fbc4+28,17.0.1-1-g55520dc+49,17.0.1-1-g5f4ed7e+52,17.0.1-1-g6dd7d69+17,17.0.1-1-g8de6c91+11,17.0.1-1-gb9095d2+7,17.0.1-1-ge9fec5e+5,17.0.1-1-gf4e0155+55,17.0.1-1-gfc65f5f+50,17.0.1-1-gfc6fb1f+20,17.0.1-10-g87f9f3f+1,17.0.1-11-ge9de802+16,17.0.1-16-ga14f7d5c+4,17.0.1-17-gc79d625+1,17.0.1-17-gdae4c4a+8,17.0.1-2-g26618f5+29,17.0.1-2-g54f2ebc+9,17.0.1-2-gf403422+1,17.0.1-20-g2ca2f74+6,17.0.1-23-gf3eadeb7+1,17.0.1-3-g7e86b59+39,17.0.1-3-gb5ca14a,17.0.1-3-gd08d533+40,17.0.1-30-g596af8797,17.0.1-4-g59d126d+4,17.0.1-4-gc69c472+5,17.0.1-6-g5afd9b9+4,17.0.1-7-g35889ee+1,17.0.1-7-gc7c8782+18,17.0.1-9-gc4bbfb2+3,w.2019.22
LSSTDataManagementBasePackage
configField.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2013 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 __all__ = ["ConfigField"]
24 
25 from .config import Config, Field, FieldValidationError, _joinNamePath, _typeStr
26 from .comparison import compareConfigs, getComparisonName
27 from .callStack import getCallStack, getStackFrame
28 
29 
31  """A configuration field (`~lsst.pex.config.Field` subclass) that takes a
32  `~lsst.pex.config.Config`-type as a value.
33 
34  Parameters
35  ----------
36  doc : `str`
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.
51 
52  See also
53  --------
54  ChoiceField
55  ConfigChoiceField
56  ConfigDictField
57  ConfigurableField
58  DictField
59  Field
60  ListField
61  RangeField
62  RegistryField
63 
64  Notes
65  -----
66  The behavior of this type of field is much like that of the base `Field`
67  type.
68 
69  Assigning to ``ConfigField`` will update all of the fields in the
70  configuration.
71  """
72 
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" %
76  _typeStr(dtype))
77  if default is None:
78  default = dtype
79  source = getStackFrame()
80  self._setup(doc=doc, dtype=dtype, default=default, check=check,
81  optional=False, source=source)
82 
83  def __get__(self, instance, owner=None):
84  if instance is None or not isinstance(instance, Config):
85  return self
86  else:
87  value = instance._storage.get(self.name, None)
88  if value is None:
89  at = getCallStack()
90  at.insert(0, self.source)
91  self.__set__(instance, self.default, at=at, label="default")
92  return value
93 
94  def __set__(self, instance, value, at=None, label="assignment"):
95  if instance._frozen:
96  raise FieldValidationError(self, instance,
97  "Cannot modify a frozen Config")
98  name = _joinNamePath(prefix=instance._name, name=self.name)
99 
100  if value != self.dtype and type(value) != self.dtype:
101  msg = "Value %s is of incorrect type %s. Expected %s" % \
102  (value, _typeStr(value), _typeStr(self.dtype))
103  raise FieldValidationError(self, instance, msg)
104 
105  if at is None:
106  at = getCallStack()
107 
108  oldValue = instance._storage.get(self.name, None)
109  if oldValue is None:
110  if value == self.dtype:
111  instance._storage[self.name] = self.dtype(__name=name, __at=at, __label=label)
112  else:
113  instance._storage[self.name] = self.dtype(__name=name, __at=at,
114  __label=label, **value._storage)
115  else:
116  if value == self.dtype:
117  value = value()
118  oldValue.update(__at=at, __label=label, **value._storage)
119  history = instance._history.setdefault(self.name, [])
120  history.append(("config value set", at, label))
121 
122  def rename(self, instance):
123  """Rename the field in a `~lsst.pex.config.Config` (for internal use
124  only).
125 
126  Parameters
127  ----------
128  instance : `lsst.pex.config.Config`
129  The config instance that contains this field.
130 
131  Notes
132  -----
133  This method is invoked by the `lsst.pex.config.Config` object that
134  contains this field and should not be called directly.
135 
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`.
140  """
141  value = self.__get__(instance)
142  value._rename(_joinNamePath(instance._name, self.name))
143 
144  def _collectImports(self, instance, imports):
145  value = self.__get__(instance)
146  value._collectImports()
147  imports |= value._imports
148 
149  def save(self, outfile, instance):
150  """Save this field to a file (for internal use only).
151 
152  Parameters
153  ----------
154  outfile : file-like object
155  A writeable field handle.
156  instance : `Config`
157  The `Config` instance that contains this field.
158 
159  Notes
160  -----
161  This method is invoked by the `~lsst.pex.config.Config` object that
162  contains this field and should not be called directly.
163 
164  The output consists of the documentation string
165  (`lsst.pex.config.Field.doc`) formatted as a Python comment. The second
166  line is formatted as an assignment: ``{fullname}={value}``.
167 
168  This output can be executed with Python.
169  """
170  value = self.__get__(instance)
171  value._save(outfile)
172 
173  def freeze(self, instance):
174  """Make this field read-only.
175 
176  Parameters
177  ----------
178  instance : `lsst.pex.config.Config`
179  The config instance that contains this field.
180 
181  Notes
182  -----
183  Freezing is only relevant for fields that hold subconfigs. Fields which
184  hold subconfigs should freeze each subconfig.
185 
186  **Subclasses should implement this method.**
187  """
188  value = self.__get__(instance)
189  value.freeze()
190 
191  def toDict(self, instance):
192  """Convert the field value so that it can be set as the value of an
193  item in a `dict` (for internal use only).
194 
195  Parameters
196  ----------
197  instance : `Config`
198  The `Config` that contains this field.
199 
200  Returns
201  -------
202  value : object
203  The field's value. See *Notes*.
204 
205  Notes
206  -----
207  This method invoked by the owning `~lsst.pex.config.Config` object and
208  should not be called directly.
209 
210  Simple values are passed through. Complex data structures must be
211  manipulated. For example, a `~lsst.pex.config.Field` holding a
212  subconfig should, instead of the subconfig object, return a `dict`
213  where the keys are the field names in the subconfig, and the values are
214  the field values in the subconfig.
215  """
216  value = self.__get__(instance)
217  return value.toDict()
218 
219  def validate(self, instance):
220  """Validate the field (for internal use only).
221 
222  Parameters
223  ----------
224  instance : `lsst.pex.config.Config`
225  The config instance that contains this field.
226 
227  Raises
228  ------
229  lsst.pex.config.FieldValidationError
230  Raised if verification fails.
231 
232  Notes
233  -----
234  This method provides basic validation:
235 
236  - Ensures that the value is not `None` if the field is not optional.
237  - Ensures type correctness.
238  - Ensures that the user-provided ``check`` function is valid.
239 
240  Most `~lsst.pex.config.Field` subclasses should call
241  `lsst.pex.config.field.Field.validate` if they re-implement
242  `~lsst.pex.config.field.Field.validate`.
243  """
244  value = self.__get__(instance)
245  value.validate()
246 
247  if self.check is not None and not self.check(value):
248  msg = "%s is not a valid value" % str(value)
249  raise FieldValidationError(self, instance, msg)
250 
251  def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
252  """Compare two fields for equality.
253 
254  Used by `ConfigField.compare`.
255 
256  Parameters
257  ----------
258  instance1 : `lsst.pex.config.Config`
259  Left-hand side config instance to compare.
260  instance2 : `lsst.pex.config.Config`
261  Right-hand side config instance to compare.
262  shortcut : `bool`
263  If `True`, this function returns as soon as an inequality if found.
264  rtol : `float`
265  Relative tolerance for floating point comparisons.
266  atol : `float`
267  Absolute tolerance for floating point comparisons.
268  output : callable
269  A callable that takes a string, used (possibly repeatedly) to report inequalities.
270 
271  Returns
272  -------
273  isEqual : bool
274  `True` if the fields are equal, `False` otherwise.
275 
276  Notes
277  -----
278  Floating point comparisons are performed by `numpy.allclose`.
279  """
280  c1 = getattr(instance1, self.name)
281  c2 = getattr(instance2, self.name)
282  name = getComparisonName(
283  _joinNamePath(instance1._name, self.name),
284  _joinNamePath(instance2._name, self.name)
285  )
286  return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
def __get__(self, instance, owner=None)
Definition: configField.py:83
def __set__(self, instance, value, at=None, label="assignment")
Definition: configField.py:94
def compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
Definition: comparison.py:105
def getCallStack(skip=0)
Definition: callStack.py:169
def __init__(self, doc, dtype, default=None, check=None)
Definition: configField.py:73
def __get__(self, instance, owner=None, at=None, label="default")
Definition: config.py:476
def _setup(self, doc, dtype, default, check, optional, source)
Definition: config.py:273
def getStackFrame(relative=0)
Definition: callStack.py:52
table::Key< int > type
Definition: Detector.cc:167
def save(self, outfile, instance)
Definition: configField.py:149
def __set__(self, instance, value, at=None, label='assignment')
Definition: config.py:494
def getComparisonName(name1, name2)
Definition: comparison.py:34