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

# 

# 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/>. 

# 

 

__all__ = ["ConfigField"] 

 

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

from .comparison import compareConfigs, getComparisonName 

from .callStack import getCallStack, getStackFrame 

 

 

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): 

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

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

_typeStr(dtype)) 

53 ↛ 55line 53 didn't jump to line 55, because the condition on line 53 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) 

64 ↛ 65line 64 didn't jump to line 65, because the condition on line 64 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"): 

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

raise FieldValidationError(self, instance, 

"Cannot modify a frozen Config") 

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

 

76 ↛ 77line 76 didn't jump to line 77, because the condition on line 76 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) 

 

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

at = getCallStack() 

 

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

if oldValue is None: 

86 ↛ 89line 86 didn't jump to line 89, because the condition on line 86 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() 

 

118 ↛ 119line 118 didn't jump to line 119, because the condition on line 118 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)