Coverage for tests/test_configurableActions.py: 10%

145 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-10 09:56 +0000

1# This file is part of pex_config. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

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

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

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

12# (at your option) any later version. 

13# 

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

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

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22import unittest 

23from io import StringIO 

24from types import SimpleNamespace 

25 

26import lsst.pex.config.configurableActions.tests as actionTests 

27from lsst.pex.config import FieldValidationError 

28from lsst.pex.config.configurableActions.tests import ActionTest1, ActionTest2, ActionTest3 

29 

30 

31class ConfigurableActionsTestCase(unittest.TestCase): 

32 """Test fo ConfigurableActions.""" 

33 

34 def _createConfig(self, default=None, singleDefault=None): 

35 class NewTestConfig(actionTests.TestConfig): 

36 def setDefaults(self): 

37 super().setDefaults() 

38 if default is not None: 

39 for k, v in default.items(): 

40 setattr(self.actions, k, v) 

41 if singleDefault is not None: 

42 self.singleAction = singleDefault 

43 

44 return NewTestConfig 

45 

46 def testConfigInstantiation(self): 

47 # This will raise if there is an issue instantiating something 

48 configClass = self._createConfig() 

49 config = configClass() 

50 self.assertTrue(hasattr(config, "actions")) 

51 self.assertTrue(hasattr(config, "singleAction")) 

52 

53 # test again with default values 

54 configClass = self._createConfig(default={"test1": ActionTest1}, singleDefault=ActionTest1) 

55 config = configClass() 

56 

57 # verify the defaults were created 

58 self.assertTrue(hasattr(config.actions, "test1")) 

59 self.assertTrue(hasattr(config.actions.test1, "var")) 

60 self.assertEqual(config.actions.test1.var, 0) 

61 

62 self.assertTrue(hasattr(config.singleAction, "var")) 

63 self.assertEqual(config.singleAction.var, 0) 

64 

65 def testAssignment(self): 

66 # Struct actions 

67 # Test that a new action can be added with assignment 

68 configClass = self._createConfig(default={"test1": ActionTest1}) 

69 config = configClass() 

70 config.actions.test2 = ActionTest2 

71 

72 self.assertEqual(tuple(config.actions.fieldNames), ("test1", "test2")) 

73 self.assertEqual(config.actions.test2.var, 1) 

74 

75 # verify the same as above, but assigning with instances 

76 configClass = self._createConfig(default={"test1": ActionTest1}) 

77 config = configClass() 

78 config.actions.test3 = ActionTest3() 

79 

80 self.assertEqual(tuple(config.actions.fieldNames), ("test1", "test3")) 

81 self.assertEqual(config.actions.test3.var, 3) 

82 

83 # The following is designed to support pipeline config setting 

84 # Test assignment using the update accessor 

85 configClass = self._createConfig(default={"test1": ActionTest1}) 

86 config = configClass() 

87 config.actions.update = {"test2": ActionTest2, "test3": ActionTest3} 

88 

89 self.assertEqual(tuple(config.actions.fieldNames), ("test1", "test2", "test3")) 

90 

91 configClass = self._createConfig(default={"test1": ActionTest1}) 

92 configClass2 = self._createConfig(default={"test2": ActionTest2, "test3": ActionTest3}) 

93 config = configClass() 

94 config2 = configClass2() 

95 config.actions.update = config2.actions 

96 

97 self.assertEqual(tuple(config.actions.fieldNames), ("test1", "test2", "test3")) 

98 

99 # verify tha the update interface cannot be used to assign invalid 

100 # identifiers 

101 configClass = self._createConfig() 

102 config = configClass() 

103 with self.assertRaises(ValueError): 

104 config.actions.update = {"name with space": ActionTest2} 

105 

106 with self.assertRaises(ValueError): 

107 config.actions.update = {"9leading_number": ActionTest2} 

108 

109 # Test remove "assignment" using the remove accessor 

110 configClass = self._createConfig( 

111 default={"test1": ActionTest1, "test2": ActionTest2, "test3": ActionTest3} 

112 ) 

113 config = configClass() 

114 config.actions.remove = ("test1", "test2") 

115 self.assertEqual(tuple(config.actions.fieldNames), ("test3",)) 

116 

117 configClass = self._createConfig( 

118 default={"test1": ActionTest1, "test2": ActionTest2, "test3": ActionTest3} 

119 ) 

120 config = configClass() 

121 config.actions.remove = "test1" 

122 self.assertEqual(tuple(config.actions.fieldNames), ("test2", "test3")) 

123 

124 # singleAction 

125 # Test that an action can be reassigned 

126 configClass = self._createConfig(singleDefault=ActionTest1) 

127 config = configClass() 

128 self.assertEqual(config.singleAction(), 0) 

129 

130 config.singleAction = ActionTest2 

131 self.assertEqual(config.singleAction(), 1) 

132 

133 config.singleAction = ActionTest3() 

134 self.assertEqual(config.singleAction(), 3) 

135 

136 # Verify that ConfigurableActionStructField can be assigned to with 

137 # a ConfigurableActionStruct, SimpleNamespace 

138 otherConfigClass = self._createConfig( 

139 default={"test1": ActionTest1(var=1), "test2": ActionTest2(var=2)} 

140 ) 

141 assignSource1 = otherConfigClass().actions 

142 assignSource2 = SimpleNamespace(test1=ActionTest1(var=1), test2=ActionTest2(var=2)) 

143 

144 for source in (assignSource1, assignSource2): 

145 configClass = self._createConfig() 

146 config = configClass() 

147 config.actions = source 

148 

149 self.assertEqual(tuple(config.actions.fieldNames), ("test1", "test2")) 

150 self.assertEqual((config.actions.test1.var, config.actions.test2.var), (1, 2)) 

151 

152 # Fail if assigment is ConfigurableActionStructField 

153 with self.assertRaises(ValueError): 

154 configClass = self._createConfig() 

155 config = configClass() 

156 config.actions = otherConfigClass.actions 

157 

158 # Fail if assignment is some other type 

159 with self.assertRaises(ValueError): 

160 configClass = self._createConfig() 

161 config = configClass() 

162 config.actions = {} 

163 

164 def testValidate(self): 

165 configClass = self._createConfig( 

166 default={"test1": ActionTest1, "test2": ActionTest2, "test3": ActionTest3}, 

167 singleDefault=ActionTest1, 

168 ) 

169 config = configClass() 

170 config.validate() 

171 

172 def testFreeze(self): 

173 configClass = self._createConfig( 

174 default={"test1": ActionTest1, "test2": ActionTest2}, singleDefault=ActionTest1 

175 ) 

176 config = configClass() 

177 config.freeze() 

178 

179 with self.assertRaises(FieldValidationError): 

180 config.actions.test3 = ActionTest3 

181 

182 with self.assertRaises(FieldValidationError): 

183 config.actions.test1.var = 2 

184 

185 with self.assertRaises(FieldValidationError): 

186 config.actions.test2.var = 0 

187 

188 with self.assertRaises(FieldValidationError): 

189 config.singleAction = ActionTest2 

190 

191 with self.assertRaises(FieldValidationError): 

192 config.singleAction.var = 3 

193 

194 def testCompare(self): 

195 configClass = self._createConfig( 

196 default={"test1": ActionTest1, "test2": ActionTest2}, singleDefault=ActionTest1 

197 ) 

198 config = configClass() 

199 config2 = configClass() 

200 

201 self.assertTrue(config.compare(config2)) 

202 

203 # Test equality fail for ConfigurableActionsStructField 

204 config3 = configClass() 

205 config3.actions.test1.var = 99 

206 self.assertFalse(config.compare(config3)) 

207 

208 # Test equality fail for ConfigurableActionsField 

209 config4 = configClass() 

210 config4.singleAction.var = 99 

211 self.assertFalse(config.compare(config4)) 

212 

213 def testSave(self): 

214 # This method will also test rename, as it is part of the 

215 # implementation in pex_config 

216 ioObject = StringIO() 

217 config = actionTests.TestConfig() 

218 config.actions.test1 = ActionTest1 

219 config.actions.test2 = ActionTest2 

220 config.singleAction = actionTests.TestDivideAction( 

221 colA=actionTests.TestSingleColumnAction(column="a"), 

222 colB=actionTests.TestSingleColumnAction(column="b"), 

223 ) 

224 

225 config.saveToStream(ioObject) 

226 string1 = ioObject.getvalue() 

227 loadedConfig = actionTests.TestConfig() 

228 loadedConfig.loadFromStream(string1) 

229 self.assertTrue(config.compare(loadedConfig), msg=f"{config} != {loadedConfig}") 

230 # Be sure that the fields are actually there 

231 self.assertEqual(loadedConfig.actions.test1.var, 0) 

232 self.assertEqual(loadedConfig.singleAction.colA.column, "a") 

233 self.assertEqual(loadedConfig.singleAction.colB.column, "b") 

234 # Save an equivalent struct with fields originally ordered differently, 

235 # check that the saved form is the same (via deterministic sorting). 

236 config2 = actionTests.TestConfig() 

237 config2.actions.test2 = ActionTest2 

238 config2.actions.test1 = ActionTest1 

239 config2.singleAction = actionTests.TestDivideAction( 

240 colB=actionTests.TestSingleColumnAction(column="b"), 

241 colA=actionTests.TestSingleColumnAction(column="a"), 

242 ) 

243 ioObject2 = StringIO() 

244 config2.saveToStream(ioObject2) 

245 self.maxDiff = None 

246 self.assertEqual(string1, ioObject2.getvalue()) 

247 

248 def testToDict(self): 

249 """Test the toDict interface.""" 

250 configClass = self._createConfig(default={"test1": ActionTest1}, singleDefault=ActionTest1) 

251 config = configClass() 

252 self.assertEqual(config.toDict(), {"actions": {"test1": {"var": 0}}, "singleAction": {"var": 0}}) 

253 

254 

255if __name__ == "__main__": 255 ↛ 256line 255 didn't jump to line 256, because the condition on line 255 was never true

256 unittest.main()