Coverage for tests/test_configurableActions.py: 23%

147 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 03:25 -0700

1# This file is part of pipe_tasks. 

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.pipe.tasks.configurableActions import (ConfigurableActionStructField, ConfigurableAction, 

27 ConfigurableActionField) 

28from lsst.pex.config import Config, Field, FieldValidationError 

29from lsst.pipe.base import Struct 

30 

31 

32class ActionTest1(ConfigurableAction): 

33 var = Field(doc="test field", dtype=int, default=0) 

34 

35 def __call__(self): 

36 return self.var 

37 

38 def validate(self): 

39 assert(self.var is not None) 

40 

41 

42class ActionTest2(ConfigurableAction): 

43 var = Field(doc="test field", dtype=int, default=1) 

44 

45 def __call__(self): 

46 return self.var 

47 

48 def validate(self): 

49 assert(self.var is not None) 

50 

51 

52class ActionTest3(ConfigurableAction): 

53 var = Field(doc="test field", dtype=int, default=3) 

54 

55 def __call__(self): 

56 return self.var 

57 

58 def validate(self): 

59 assert(self.var is not None) 

60 

61 

62class ConfigurableActionsTestCase(unittest.TestCase): 

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

64 class TestConfig(Config): 

65 actions = ConfigurableActionStructField(doc="Actions to be tested", default=default) 

66 singleAction = ConfigurableActionField(doc="A configurable action", default=singleDefault) 

67 return TestConfig 

68 

69 def testConfigInstatiation(self): 

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

71 configClass = self._createConfig() 

72 config = configClass() 

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

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

75 

76 # test again with default values 

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

78 config = configClass() 

79 

80 # verify the defaults were created 

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

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

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

84 

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

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

87 

88 def testAssignment(self): 

89 # Struct actions 

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

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

92 config = configClass() 

93 config.actions.test2 = ActionTest2 

94 

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

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

97 

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

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

100 config = configClass() 

101 config.actions.test3 = ActionTest3() 

102 

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

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

105 

106 # The following is designed to support pipeline config setting 

107 # Test assignment using the update accessor 

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

109 config = configClass() 

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

111 

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

113 

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

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

116 config = configClass() 

117 config2 = configClass2() 

118 config.actions.update = config2.actions 

119 

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

121 

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

123 # identifiers 

124 configClass = self._createConfig() 

125 config = configClass() 

126 with self.assertRaises(ValueError): 

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

128 

129 with self.assertRaises(ValueError): 

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

131 

132 # Test remove "assignment" using the remove accessor 

133 configClass = self._createConfig(default={"test1": ActionTest1, "test2": ActionTest2, 

134 "test3": ActionTest3}) 

135 config = configClass() 

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

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

138 

139 configClass = self._createConfig(default={"test1": ActionTest1, "test2": ActionTest2, 

140 "test3": ActionTest3}) 

141 config = configClass() 

142 config.actions.remove = "test1" 

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

144 

145 # singleAction 

146 # Test that an action can be reassigned 

147 configClass = self._createConfig(singleDefault=ActionTest1) 

148 config = configClass() 

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

150 

151 config.singleAction = ActionTest2 

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

153 

154 config.singleAction = ActionTest3() 

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

156 

157 # Verify that ConfigurableActionStructField can be assigned to with 

158 # a ConfigurableActionStruct, Struct, and SimpleNamespace 

159 otherConfigClass = self._createConfig(default={"test1": ActionTest1(var=1), 

160 "test2": ActionTest2(var=2)}) 

161 assignSource1 = otherConfigClass().actions 

162 assignSource2 = Struct(test1=ActionTest1(var=1), test2=ActionTest2(var=2)) 

163 assignSource3 = SimpleNamespace(test1=ActionTest1(var=1), test2=ActionTest2(var=2)) 

164 

165 for source in (assignSource1, assignSource2, assignSource3): 

166 configClass = self._createConfig() 

167 config = configClass() 

168 config.actions = source 

169 

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

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

172 

173 # Fail if assigment is ConfigurableActionStructField 

174 with self.assertRaises(ValueError): 

175 configClass = self._createConfig() 

176 config = configClass() 

177 config.actions = otherConfigClass.actions 

178 

179 # Fail if assignment is some other type 

180 with self.assertRaises(ValueError): 

181 configClass = self._createConfig() 

182 config = configClass() 

183 config.actions = {} 

184 

185 def testValidate(self): 

186 configClass = self._createConfig(default={"test1": ActionTest1, "test2": ActionTest2, 

187 "test3": ActionTest3}, singleDefault=ActionTest1) 

188 config = configClass() 

189 config.validate() 

190 

191 def testFreeze(self): 

192 configClass = self._createConfig(default={"test1": ActionTest1, "test2": ActionTest2}, 

193 singleDefault=ActionTest1) 

194 config = configClass() 

195 config.freeze() 

196 

197 with self.assertRaises(FieldValidationError): 

198 config.actions.test3 = ActionTest3 

199 

200 with self.assertRaises(FieldValidationError): 

201 config.actions.test1.var = 2 

202 

203 with self.assertRaises(FieldValidationError): 

204 config.actions.test2.var = 0 

205 

206 with self.assertRaises(FieldValidationError): 

207 config.singleAction = ActionTest2 

208 

209 with self.assertRaises(FieldValidationError): 

210 config.singleAction.var = 3 

211 

212 def testCompare(self): 

213 configClass = self._createConfig(default={"test1": ActionTest1, "test2": ActionTest2}, 

214 singleDefault=ActionTest1) 

215 config = configClass() 

216 config2 = configClass() 

217 

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

219 

220 # Test equality fail for ConfigurableActionsStructField 

221 config3 = configClass() 

222 config3.actions.test1.var = 99 

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

224 

225 # Test equality fail for ConfigurableActionsField 

226 config4 = configClass() 

227 config4.singleAction.var = 99 

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

229 

230 def testSave(self): 

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

232 # implementation in pex_config 

233 ioObject = StringIO() 

234 configClass = self._createConfig(default={"test1": ActionTest1}, 

235 singleDefault=ActionTest1) 

236 config = configClass() 

237 

238 config.saveToStream(ioObject) 

239 loadedConfig = configClass() 

240 loadedConfig.loadFromStream(ioObject.read()) 

241 self.assertTrue(config.compare(loadedConfig)) 

242 # Be sure that the fields are actually there 

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

244 self.assertEqual(loadedConfig.singleAction.var, 0) 

245 

246 def testToDict(self): 

247 """Test the toDict interface""" 

248 configClass = self._createConfig(default={"test1": ActionTest1}, 

249 singleDefault=ActionTest1) 

250 config = configClass() 

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

252 

253 

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

255 unittest.main()