Coverage for tests/test_configOverrides.py: 17%

160 statements  

« prev     ^ index     » next       coverage.py v7.3.0, created at 2023-08-31 09:39 +0000

1# This file is part of pipe_base. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21 

22"""Simple unit test for configOverrides. 

23""" 

24 

25import tempfile 

26import unittest 

27 

28import lsst.pex.config as pexConfig 

29import lsst.utils.tests 

30from lsst.pipe.base.configOverrides import ConfigOverrides 

31from lsst.pipe.base.pipelineIR import ParametersIR 

32 

33# This is used in testSettingVar unit test 

34TEST_CHOICE_VALUE = 1 

35 

36 

37class ConfigTest(pexConfig.Config): 

38 """Configuration used for testing.""" 

39 

40 fStr = pexConfig.Field(dtype=str, default="default", doc="test") 

41 fBool = pexConfig.Field(dtype=bool, default=False, doc="test") 

42 fInt = pexConfig.Field(dtype=int, default=-1, doc="test") 

43 fFloat = pexConfig.Field(dtype=float, default=-1.0, doc="test") 

44 

45 fListStr = pexConfig.ListField(dtype=str, default=[], doc="test") 

46 fListBool = pexConfig.ListField(dtype=bool, default=[], doc="test") 

47 fListInt = pexConfig.ListField(dtype=int, default=[], doc="test") 

48 

49 fChoiceStr = pexConfig.ChoiceField(dtype=str, allowed=dict(A="a", B="b", C="c"), doc="test") 

50 fChoiceInt = pexConfig.ChoiceField(dtype=int, allowed={1: "a", 2: "b", 3: "c"}, doc="test") 

51 

52 fDictStrInt = pexConfig.DictField(keytype=str, itemtype=int, doc="test") 

53 

54 

55class ConfigOverridesTestCase(unittest.TestCase): 

56 """A test case for Task""" 

57 

58 def checkSingleFieldOverride(self, field, value, result=None): 

59 """Apply overrides of a single field. 

60 

61 Parameters 

62 ---------- 

63 field : `str` 

64 Field name. 

65 value : 

66 Field value to set, can be a string or anything else. 

67 result : optional 

68 Expected value of the field. 

69 """ 

70 config = ConfigTest() 

71 overrides = ConfigOverrides() 

72 overrides.addValueOverride(field, value) 

73 overrides.applyTo(config) 

74 self.assertEqual(getattr(config, field), result) 

75 

76 def testSimpleValueStr(self): 

77 """Test for applying value override to a string field""" 

78 field = "fStr" 

79 

80 # values of supported type 

81 self.checkSingleFieldOverride(field, "string", "string") 

82 

83 # invalid input 

84 with self.assertRaises(pexConfig.FieldValidationError): 

85 self.checkSingleFieldOverride(field, 1) 

86 

87 def testSimpleValueBool(self): 

88 """Test for applying value override to a boolean field""" 

89 field = "fBool" 

90 

91 # values of supported type 

92 self.checkSingleFieldOverride(field, True, True) 

93 self.checkSingleFieldOverride(field, False, False) 

94 

95 # supported string conversions 

96 self.checkSingleFieldOverride(field, "True", True) 

97 self.checkSingleFieldOverride(field, "False", False) 

98 

99 # parseable but invalid input 

100 with self.assertRaises(pexConfig.FieldValidationError): 

101 self.checkSingleFieldOverride(field, 1) 

102 with self.assertRaises(pexConfig.FieldValidationError): 

103 self.checkSingleFieldOverride(field, []) 

104 with self.assertRaises(pexConfig.FieldValidationError): 

105 self.checkSingleFieldOverride(field, "1") 

106 

107 def testSimpleValueInt(self): 

108 """Test for applying value override to a int field""" 

109 field = "fInt" 

110 

111 # values of supported type 

112 self.checkSingleFieldOverride(field, 0, 0) 

113 self.checkSingleFieldOverride(field, 100, 100) 

114 

115 # supported string conversions 

116 self.checkSingleFieldOverride(field, "0", 0) 

117 self.checkSingleFieldOverride(field, "100", 100) 

118 self.checkSingleFieldOverride(field, "-100", -100) 

119 self.checkSingleFieldOverride(field, "0x100", 0x100) 

120 

121 # parseable but invalid input 

122 with self.assertRaises(pexConfig.FieldValidationError): 

123 self.checkSingleFieldOverride(field, 1.0) 

124 with self.assertRaises(pexConfig.FieldValidationError): 

125 self.checkSingleFieldOverride(field, "1.0") 

126 with self.assertRaises(pexConfig.FieldValidationError): 

127 self.checkSingleFieldOverride(field, "[]") 

128 

129 def testSimpleValueFloat(self): 

130 """Test for applying value override to a float field""" 

131 field = "fFloat" 

132 

133 # values of supported type 

134 self.checkSingleFieldOverride(field, 0.0, 0.0) 

135 self.checkSingleFieldOverride(field, 100.0, 100.0) 

136 

137 # supported string conversions 

138 self.checkSingleFieldOverride(field, "0.", 0.0) 

139 self.checkSingleFieldOverride(field, "100.0", 100.0) 

140 self.checkSingleFieldOverride(field, "-1.2e10", -1.2e10) 

141 

142 # parseable but invalid input 

143 with self.assertRaises(pexConfig.FieldValidationError): 

144 self.checkSingleFieldOverride(field, []) 

145 with self.assertRaises(pexConfig.FieldValidationError): 

146 self.checkSingleFieldOverride(field, "(1, 1)") 

147 

148 def testListValueStr(self): 

149 """Test for applying value override to a list field""" 

150 field = "fListStr" 

151 

152 # values of supported type 

153 self.checkSingleFieldOverride(field, ["a", "b"], ["a", "b"]) 

154 self.checkSingleFieldOverride(field, ("a", "b"), ["a", "b"]) 

155 

156 # supported string conversions 

157 self.checkSingleFieldOverride(field, '["a", "b"]', ["a", "b"]) 

158 self.checkSingleFieldOverride(field, '("a", "b")', ["a", "b"]) 

159 

160 # parseable but invalid input 

161 with self.assertRaises(pexConfig.FieldValidationError): 

162 self.checkSingleFieldOverride(field, "['a', []]") 

163 

164 def testListValueBool(self): 

165 """Test for applying value override to a list field""" 

166 field = "fListBool" 

167 

168 # values of supported type 

169 self.checkSingleFieldOverride(field, [True, False], [True, False]) 

170 self.checkSingleFieldOverride(field, (True, False), [True, False]) 

171 

172 # supported string conversions 

173 self.checkSingleFieldOverride(field, "[True, False]", [True, False]) 

174 self.checkSingleFieldOverride(field, "(True, False)", [True, False]) 

175 self.checkSingleFieldOverride(field, "['True', 'False']", [True, False]) 

176 

177 with self.assertRaises(pexConfig.FieldValidationError): 

178 self.checkSingleFieldOverride(field, "[1, 2]") 

179 with self.assertRaises(pexConfig.FieldValidationError): 

180 self.checkSingleFieldOverride(field, [0, 1]) 

181 with self.assertRaises(pexConfig.FieldValidationError): 

182 self.checkSingleFieldOverride(field, "5") 

183 

184 def testListValueInt(self): 

185 """Test for applying value override to a list field""" 

186 field = "fListInt" 

187 

188 # values of supported type 

189 self.checkSingleFieldOverride(field, [1, 2], [1, 2]) 

190 self.checkSingleFieldOverride(field, (1, 2), [1, 2]) 

191 

192 # supported string conversions 

193 self.checkSingleFieldOverride(field, "[1, 2]", [1, 2]) 

194 self.checkSingleFieldOverride(field, "(1, 2)", [1, 2]) 

195 self.checkSingleFieldOverride(field, "['1', '2']", [1, 2]) 

196 

197 # parseable but invalid input 

198 with self.assertRaises(pexConfig.FieldValidationError): 

199 self.checkSingleFieldOverride(field, "[1.0, []]") 

200 with self.assertRaises(pexConfig.FieldValidationError): 

201 self.checkSingleFieldOverride(field, [[], []]) 

202 with self.assertRaises(pexConfig.FieldValidationError): 

203 self.checkSingleFieldOverride(field, "5") 

204 

205 def testChoiceValueStr(self): 

206 """Test for applying value override to a choice field""" 

207 field = "fChoiceStr" 

208 

209 # values of supported type 

210 self.checkSingleFieldOverride(field, "A", "A") 

211 self.checkSingleFieldOverride(field, "B", "B") 

212 

213 # non-allowed value 

214 with self.assertRaises(pexConfig.FieldValidationError): 

215 self.checkSingleFieldOverride(field, "X") 

216 

217 def testChoiceValueInt(self): 

218 """Test for applying value override to a choice field""" 

219 field = "fChoiceInt" 

220 

221 # values of supported type 

222 self.checkSingleFieldOverride(field, 1, 1) 

223 self.checkSingleFieldOverride(field, 3, 3) 

224 

225 # supported string conversions 

226 self.checkSingleFieldOverride(field, "1", 1) 

227 

228 # parseable but invalid input 

229 with self.assertRaises(pexConfig.FieldValidationError): 

230 self.checkSingleFieldOverride(field, "0") 

231 with self.assertRaises(pexConfig.FieldValidationError): 

232 self.checkSingleFieldOverride(field, "[1]") 

233 with self.assertRaises(pexConfig.FieldValidationError): 

234 self.checkSingleFieldOverride(field, [0, 1]) 

235 

236 def testSettingVar(self): 

237 """Test setting a field with a string that represents a variable.""" 

238 field = "fChoiceInt" 

239 

240 # verify loading variable 

241 self.checkSingleFieldOverride(field, "TEST_CHOICE_VALUE", 1) 

242 

243 # Verify That python importing a variable works 

244 config = ConfigTest() 

245 overrides = ConfigOverrides() 

246 overrides.addPythonOverride("from math import pi") 

247 overrides.addValueOverride("fFloat", "pi") 

248 overrides.applyTo(config) 

249 from math import pi 

250 

251 self.assertEqual(config.fFloat, pi) 

252 

253 def testDictValueInt(self): 

254 """Test for applying value override to a dict field""" 

255 field = "fDictStrInt" 

256 

257 # values of supported type 

258 self.checkSingleFieldOverride(field, dict(a=1, b=2), dict(a=1, b=2)) 

259 

260 # supported string conversions 

261 self.checkSingleFieldOverride(field, "{'a': 1, 'b': 2}", dict(a=1, b=2)) 

262 

263 # parseable but invalid input 

264 with self.assertRaises(pexConfig.FieldValidationError): 

265 self.checkSingleFieldOverride(field, "{1: 2}") 

266 with self.assertRaises(pexConfig.FieldValidationError): 

267 self.checkSingleFieldOverride(field, "{'a': 'b'}") 

268 with self.assertRaises(pexConfig.FieldValidationError): 

269 self.checkSingleFieldOverride(field, {"a": "b"}) 

270 

271 def testConfigParameters(self): 

272 """Test that passing parameters works""" 

273 config = ConfigTest() 

274 parameters = ParametersIR(mapping={"number": 6, "text": "hello world"}) 

275 overrides = ConfigOverrides() 

276 overrides.addParameters(parameters) 

277 overrides.addPythonOverride("config.fStr = parameters.text") 

278 with tempfile.NamedTemporaryFile(mode="w") as fileOverride: 

279 fileOverride.write("config.fInt = parameters.number") 

280 fileOverride.seek(0) 

281 overrides.addFileOverride(fileOverride.name) 

282 overrides.applyTo(config) 

283 self.assertEqual(config.fStr, parameters.mapping["text"]) 

284 self.assertEqual(config.fInt, parameters.mapping["number"]) 

285 

286 overrides = ConfigOverrides() 

287 overrides.addParameters(parameters) 

288 overrides.addPythonOverride("parameters.fail = 9") 

289 with self.assertRaises(ValueError): 

290 overrides.applyTo(config) 

291 

292 

293class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase): 

294 """Check for memory leaks.""" 

295 

296 

297def setup_module(module): 

298 """Configure pytest.""" 

299 lsst.utils.tests.init() 

300 

301 

302if __name__ == "__main__": 

303 lsst.utils.tests.init() 

304 unittest.main()