LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
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 save(self, outfile, instance):
145  """Save this field to a file (for internal use only).
146 
147  Parameters
148  ----------
149  outfile : file-like object
150  A writeable field handle.
151  instance : `Config`
152  The `Config` instance that contains this field.
153 
154  Notes
155  -----
156  This method is invoked by the `~lsst.pex.config.Config` object that
157  contains this field and should not be called directly.
158 
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}``.
162 
163  This output can be executed with Python.
164  """
165  value = self.__get__(instance)
166  value._save(outfile)
167 
168  def freeze(self, instance):
169  """Make this field read-only.
170 
171  Parameters
172  ----------
173  instance : `lsst.pex.config.Config`
174  The config instance that contains this field.
175 
176  Notes
177  -----
178  Freezing is only relevant for fields that hold subconfigs. Fields which
179  hold subconfigs should freeze each subconfig.
180 
181  **Subclasses should implement this method.**
182  """
183  value = self.__get__(instance)
184  value.freeze()
185 
186  def toDict(self, instance):
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).
189 
190  Parameters
191  ----------
192  instance : `Config`
193  The `Config` that contains this field.
194 
195  Returns
196  -------
197  value : object
198  The field's value. See *Notes*.
199 
200  Notes
201  -----
202  This method invoked by the owning `~lsst.pex.config.Config` object and
203  should not be called directly.
204 
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.
210  """
211  value = self.__get__(instance)
212  return value.toDict()
213 
214  def validate(self, instance):
215  """Validate the field (for internal use only).
216 
217  Parameters
218  ----------
219  instance : `lsst.pex.config.Config`
220  The config instance that contains this field.
221 
222  Raises
223  ------
224  lsst.pex.config.FieldValidationError
225  Raised if verification fails.
226 
227  Notes
228  -----
229  This method provides basic validation:
230 
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.
234 
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`.
238  """
239  value = self.__get__(instance)
240  value.validate()
241 
242  if self.check is not None and not self.check(value):
243  msg = "%s is not a valid value" % str(value)
244  raise FieldValidationError(self, instance, msg)
245 
246  def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
247  """Compare two fields for equality.
248 
249  Used by `ConfigField.compare`.
250 
251  Parameters
252  ----------
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.
257  shortcut : `bool`
258  If `True`, this function returns as soon as an inequality if found.
259  rtol : `float`
260  Relative tolerance for floating point comparisons.
261  atol : `float`
262  Absolute tolerance for floating point comparisons.
263  output : callable
264  A callable that takes a string, used (possibly repeatedly) to report inequalities.
265 
266  Returns
267  -------
268  isEqual : bool
269  `True` if the fields are equal, `False` otherwise.
270 
271  Notes
272  -----
273  Floating point comparisons are performed by `numpy.allclose`.
274  """
275  c1 = getattr(instance1, self.name)
276  c2 = getattr(instance2, self.name)
277  name = getComparisonName(
278  _joinNamePath(instance1._name, self.name),
279  _joinNamePath(instance2._name, self.name)
280  )
281  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:453
def _setup(self, doc, dtype, default, check, optional, source)
Definition: config.py:264
def getStackFrame(relative=0)
Definition: callStack.py:52
table::Key< int > type
Definition: Detector.cc:164
def save(self, outfile, instance)
Definition: configField.py:144
def __set__(self, instance, value, at=None, label='assignment')
Definition: config.py:471
def getComparisonName(name1, name2)
Definition: comparison.py:34