Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

# 

# LSST Data Management System 

# Copyright 2008-2013 LSST Corporation. 

# 

# This product includes software developed by the 

# LSST Project (http://www.lsst.org/). 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# This program is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

# GNU General Public License for more details. 

# 

# You should have received a copy of the LSST License Statement and 

# the GNU General Public License along with this program. If not, 

# see <http://www.lsstcorp.org/LegalNotices/>. 

# 

from builtins import str 

 

from .config import Config, Field, FieldValidationError, _joinNamePath, _typeStr 

from .comparison import compareConfigs, getComparisonName 

from .callStack import getCallStack, getStackFrame 

 

__all__ = ["ConfigField"] 

 

 

class ConfigField(Field): 

""" 

Defines a field which is itself a Config. 

 

The behavior of this type of field is much like that of the base Field type. 

 

Note that dtype must be a subclass of Config. 

 

If default=None, the field will default to a default-constructed 

instance of dtype. 

 

Additionally, to allow for fewer deep-copies, assigning an instance of 

ConfigField to dtype itself, is considered equivalent to assigning a 

default-constructed sub-config. This means that the argument default can be 

dtype, as well as an instance of dtype. 

 

Assigning to ConfigField will update all of the fields in the config. 

""" 

 

def __init__(self, doc, dtype, default=None, check=None): 

51 ↛ 52line 51 didn't jump to line 52, because the condition on line 51 was never true if not issubclass(dtype, Config): 

raise ValueError("dtype=%s is not a subclass of Config" % 

_typeStr(dtype)) 

54 ↛ 56line 54 didn't jump to line 56, because the condition on line 54 was never false if default is None: 

default = dtype 

source = getStackFrame() 

self._setup(doc=doc, dtype=dtype, default=default, check=check, 

optional=False, source=source) 

 

def __get__(self, instance, owner=None): 

if instance is None or not isinstance(instance, Config): 

return self 

else: 

value = instance._storage.get(self.name, None) 

65 ↛ 66line 65 didn't jump to line 66, because the condition on line 65 was never true if value is None: 

at = getCallStack() 

at.insert(0, self.source) 

self.__set__(instance, self.default, at=at, label="default") 

return value 

 

def __set__(self, instance, value, at=None, label="assignment"): 

72 ↛ 73line 72 didn't jump to line 73, because the condition on line 72 was never true if instance._frozen: 

raise FieldValidationError(self, instance, 

"Cannot modify a frozen Config") 

name = _joinNamePath(prefix=instance._name, name=self.name) 

 

77 ↛ 78line 77 didn't jump to line 78, because the condition on line 77 was never true if value != self.dtype and type(value) != self.dtype: 

msg = "Value %s is of incorrect type %s. Expected %s" % \ 

(value, _typeStr(value), _typeStr(self.dtype)) 

raise FieldValidationError(self, instance, msg) 

 

82 ↛ 83line 82 didn't jump to line 83, because the condition on line 82 was never true if at is None: 

at = getCallStack() 

 

oldValue = instance._storage.get(self.name, None) 

if oldValue is None: 

87 ↛ 90line 87 didn't jump to line 90, because the condition on line 87 was never false if value == self.dtype: 

instance._storage[self.name] = self.dtype(__name=name, __at=at, __label=label) 

else: 

instance._storage[self.name] = self.dtype(__name=name, __at=at, 

__label=label, **value._storage) 

else: 

if value == self.dtype: 

value = value() 

oldValue.update(__at=at, __label=label, **value._storage) 

history = instance._history.setdefault(self.name, []) 

history.append(("config value set", at, label)) 

 

def rename(self, instance): 

value = self.__get__(instance) 

value._rename(_joinNamePath(instance._name, self.name)) 

 

def save(self, outfile, instance): 

value = self.__get__(instance) 

value._save(outfile) 

 

def freeze(self, instance): 

value = self.__get__(instance) 

value.freeze() 

 

def toDict(self, instance): 

value = self.__get__(instance) 

return value.toDict() 

 

def validate(self, instance): 

value = self.__get__(instance) 

value.validate() 

 

119 ↛ 120line 119 didn't jump to line 120, because the condition on line 119 was never true if self.check is not None and not self.check(value): 

msg = "%s is not a valid value" % str(value) 

raise FieldValidationError(self, instance, msg) 

 

def _compare(self, instance1, instance2, shortcut, rtol, atol, output): 

"""Helper function for Config.compare; used to compare two fields for equality. 

 

@param[in] instance1 LHS Config instance to compare. 

@param[in] instance2 RHS Config instance to compare. 

@param[in] shortcut If True, return as soon as an inequality is found. 

@param[in] rtol Relative tolerance for floating point comparisons. 

@param[in] atol Absolute tolerance for floating point comparisons. 

@param[in] output If not None, a callable that takes a string, used (possibly repeatedly) 

to report inequalities. 

 

Floating point comparisons are performed by numpy.allclose; refer to that for details. 

""" 

c1 = getattr(instance1, self.name) 

c2 = getattr(instance2, self.name) 

name = getComparisonName( 

_joinNamePath(instance1._name, self.name), 

_joinNamePath(instance2._name, self.name) 

) 

return compareConfigs(name, c1, c2, shortcut=shortcut, rtol=rtol, atol=atol, output=output)