lsst.pex.config  15.0-1-gae1598d+12
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 from builtins import str
23 
24 from .config import Config, Field, FieldValidationError, _joinNamePath, _typeStr
25 from .comparison import compareConfigs, getComparisonName
26 from .callStack import getCallStack, getStackFrame
27 
28 __all__ = ["ConfigField"]
29 
30 
32  """
33  Defines a field which is itself a Config.
34 
35  The behavior of this type of field is much like that of the base Field type.
36 
37  Note that dtype must be a subclass of Config.
38 
39  If default=None, the field will default to a default-constructed
40  instance of dtype.
41 
42  Additionally, to allow for fewer deep-copies, assigning an instance of
43  ConfigField to dtype itself, is considered equivalent to assigning a
44  default-constructed sub-config. This means that the argument default can be
45  dtype, as well as an instance of dtype.
46 
47  Assigning to ConfigField will update all of the fields in the config.
48  """
49 
50  def __init__(self, doc, dtype, default=None, check=None):
51  if not issubclass(dtype, Config):
52  raise ValueError("dtype=%s is not a subclass of Config" %
53  _typeStr(dtype))
54  if default is None:
55  default = dtype
56  source = getStackFrame()
57  self._setup(doc=doc, dtype=dtype, default=default, check=check,
58  optional=False, source=source)
59 
60  def __get__(self, instance, owner=None):
61  if instance is None or not isinstance(instance, Config):
62  return self
63  else:
64  value = instance._storage.get(self.name, None)
65  if value is None:
66  at = getCallStack()
67  at.insert(0, self.source)
68  self.__set__(instance, self.default, at=at, label="default")
69  return value
70 
71  def __set__(self, instance, value, at=None, label="assignment"):
72  if instance._frozen:
73  raise FieldValidationError(self, instance,
74  "Cannot modify a frozen Config")
75  name = _joinNamePath(prefix=instance._name, name=self.name)
76 
77  if value != self.dtype and type(value) != self.dtype:
78  msg = "Value %s is of incorrect type %s. Expected %s" % \
79  (value, _typeStr(value), _typeStr(self.dtype))
80  raise FieldValidationError(self, instance, msg)
81 
82  if at is None:
83  at = getCallStack()
84 
85  oldValue = instance._storage.get(self.name, None)
86  if oldValue is None:
87  if value == self.dtype:
88  instance._storage[self.name] = self.dtype(__name=name, __at=at, __label=label)
89  else:
90  instance._storage[self.name] = self.dtype(__name=name, __at=at,
91  __label=label, **value._storage)
92  else:
93  if value == self.dtype:
94  value = value()
95  oldValue.update(__at=at, __label=label, **value._storage)
96  history = instance._history.setdefault(self.name, [])
97  history.append(("config value set", at, label))
98 
99  def rename(self, instance):
100  value = self.__get__(instance)
101  value._rename(_joinNamePath(instance._name, self.name))
102 
103  def save(self, outfile, instance):
104  value = self.__get__(instance)
105  value._save(outfile)
106 
107  def freeze(self, instance):
108  value = self.__get__(instance)
109  value.freeze()
110 
111  def toDict(self, instance):
112  value = self.__get__(instance)
113  return value.toDict()
114 
115  def validate(self, instance):
116  value = self.__get__(instance)
117  value.validate()
118 
119  if self.check is not None and not self.check(value):
120  msg = "%s is not a valid value" % str(value)
121  raise FieldValidationError(self, instance, msg)
122 
123  def _compare(self, instance1, instance2, shortcut, rtol, atol, output):
124  """Helper function for Config.compare; used to compare two fields for equality.
125 
126  @param[in] instance1 LHS Config instance to compare.
127  @param[in] instance2 RHS Config instance to compare.
128  @param[in] shortcut If True, return as soon as an inequality is found.
129  @param[in] rtol Relative tolerance for floating point comparisons.
130  @param[in] atol Absolute tolerance for floating point comparisons.
131  @param[in] output If not None, a callable that takes a string, used (possibly repeatedly)
132  to report inequalities.
133 
134  Floating point comparisons are performed by numpy.allclose; refer to that for details.
135  """
136  c1 = getattr(instance1, self.name)
137  c2 = getattr(instance2, self.name)
138  name = getComparisonName(
139  _joinNamePath(instance1._name, self.name),
140  _joinNamePath(instance2._name, self.name)
141  )
142  return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)
def __get__(self, instance, owner=None)
Definition: configField.py:60
def __set__(self, instance, value, at=None, label="assignment")
Definition: configField.py:71
def compareConfigs(name, c1, c2, shortcut=True, rtol=1E-8, atol=1E-8, output=None)
Definition: comparison.py:67
def getCallStack(skip=0)
Definition: callStack.py:157
def __init__(self, doc, dtype, default=None, check=None)
Definition: configField.py:50
def __get__(self, instance, owner=None, at=None, label="default")
Definition: config.py:287
def _setup(self, doc, dtype, default, check, optional, source)
Definition: config.py:188
def getStackFrame(relative=0)
Definition: callStack.py:54
def save(self, outfile, instance)
Definition: configField.py:103
def __set__(self, instance, value, at=None, label='assignment')
Definition: config.py:306
def getComparisonName(name1, name2)
Definition: comparison.py:35