Coverage for tests/test_configurableActions.py: 9%

144 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-28 09:11 +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 

26from lsst.pex.config import FieldValidationError 

27from lsst.pex.config.configurableActions.tests import ( 

28 ActionTest1, 

29 ActionTest2, 

30 ActionTest3, 

31 TestConfig, 

32 TestDivideAction, 

33 TestSingleColumnAction, 

34) 

35 

36 

37class ConfigurableActionsTestCase(unittest.TestCase): 

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

39 class NewTestConfig(TestConfig): 

40 def setDefaults(self): 

41 super().setDefaults() 

42 if default is not None: 

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

44 setattr(self.actions, k, v) 

45 if singleDefault is not None: 

46 self.singleAction = singleDefault 

47 

48 return NewTestConfig 

49 

50 def testConfigInstantiation(self): 

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

52 configClass = self._createConfig() 

53 config = configClass() 

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

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

56 

57 # test again with default values 

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

59 config = configClass() 

60 

61 # verify the defaults were created 

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

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

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

65 

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

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

68 

69 def testAssignment(self): 

70 # Struct actions 

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

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

73 config = configClass() 

74 config.actions.test2 = ActionTest2 

75 

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

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

78 

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

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

81 config = configClass() 

82 config.actions.test3 = ActionTest3() 

83 

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

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

86 

87 # The following is designed to support pipeline config setting 

88 # Test assignment using the update accessor 

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

90 config = configClass() 

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

92 

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

94 

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

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

97 config = configClass() 

98 config2 = configClass2() 

99 config.actions.update = config2.actions 

100 

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

102 

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

104 # identifiers 

105 configClass = self._createConfig() 

106 config = configClass() 

107 with self.assertRaises(ValueError): 

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

109 

110 with self.assertRaises(ValueError): 

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

112 

113 # Test remove "assignment" using the remove accessor 

114 configClass = self._createConfig( 

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

116 ) 

117 config = configClass() 

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

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

120 

121 configClass = self._createConfig( 

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

123 ) 

124 config = configClass() 

125 config.actions.remove = "test1" 

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

127 

128 # singleAction 

129 # Test that an action can be reassigned 

130 configClass = self._createConfig(singleDefault=ActionTest1) 

131 config = configClass() 

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

133 

134 config.singleAction = ActionTest2 

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

136 

137 config.singleAction = ActionTest3() 

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

139 

140 # Verify that ConfigurableActionStructField can be assigned to with 

141 # a ConfigurableActionStruct, SimpleNamespace 

142 otherConfigClass = self._createConfig( 

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

144 ) 

145 assignSource1 = otherConfigClass().actions 

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

147 

148 for source in (assignSource1, assignSource2): 

149 configClass = self._createConfig() 

150 config = configClass() 

151 config.actions = source 

152 

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

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

155 

156 # Fail if assigment is ConfigurableActionStructField 

157 with self.assertRaises(ValueError): 

158 configClass = self._createConfig() 

159 config = configClass() 

160 config.actions = otherConfigClass.actions 

161 

162 # Fail if assignment is some other type 

163 with self.assertRaises(ValueError): 

164 configClass = self._createConfig() 

165 config = configClass() 

166 config.actions = {} 

167 

168 def testValidate(self): 

169 configClass = self._createConfig( 

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

171 singleDefault=ActionTest1, 

172 ) 

173 config = configClass() 

174 config.validate() 

175 

176 def testFreeze(self): 

177 configClass = self._createConfig( 

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

179 ) 

180 config = configClass() 

181 config.freeze() 

182 

183 with self.assertRaises(FieldValidationError): 

184 config.actions.test3 = ActionTest3 

185 

186 with self.assertRaises(FieldValidationError): 

187 config.actions.test1.var = 2 

188 

189 with self.assertRaises(FieldValidationError): 

190 config.actions.test2.var = 0 

191 

192 with self.assertRaises(FieldValidationError): 

193 config.singleAction = ActionTest2 

194 

195 with self.assertRaises(FieldValidationError): 

196 config.singleAction.var = 3 

197 

198 def testCompare(self): 

199 configClass = self._createConfig( 

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

201 ) 

202 config = configClass() 

203 config2 = configClass() 

204 

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

206 

207 # Test equality fail for ConfigurableActionsStructField 

208 config3 = configClass() 

209 config3.actions.test1.var = 99 

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

211 

212 # Test equality fail for ConfigurableActionsField 

213 config4 = configClass() 

214 config4.singleAction.var = 99 

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

216 

217 def testSave(self): 

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

219 # implementation in pex_config 

220 ioObject = StringIO() 

221 config = TestConfig() 

222 config.actions.test1 = ActionTest1 

223 config.actions.test2 = ActionTest2 

224 config.singleAction = TestDivideAction( 

225 colA=TestSingleColumnAction(column="a"), 

226 colB=TestSingleColumnAction(column="b"), 

227 ) 

228 

229 config.saveToStream(ioObject) 

230 string1 = ioObject.getvalue() 

231 loadedConfig = TestConfig() 

232 loadedConfig.loadFromStream(string1) 

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

234 # Be sure that the fields are actually there 

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

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

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

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

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

240 config2 = TestConfig() 

241 config2.actions.test2 = ActionTest2 

242 config2.actions.test1 = ActionTest1 

243 config2.singleAction = TestDivideAction( 

244 colB=TestSingleColumnAction(column="b"), 

245 colA=TestSingleColumnAction(column="a"), 

246 ) 

247 ioObject2 = StringIO() 

248 config2.saveToStream(ioObject2) 

249 self.maxDiff = None 

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

251 

252 def testToDict(self): 

253 """Test the toDict interface""" 

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

255 config = configClass() 

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

257 

258 

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

260 unittest.main()