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