Coverage for tests/test_configOverrides.py: 17%

160 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-10 03:25 -0700

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 software is dual licensed under the GNU General Public License and also 

10# under a 3-clause BSD license. Recipients may choose which of these licenses 

11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt, 

12# respectively. If you choose the GPL option then the following text applies 

13# (but note that there is still no warranty even if you opt for BSD instead): 

14# 

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

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

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

18# (at your option) any later version. 

19# 

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

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

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

23# GNU General Public License for more details. 

24# 

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

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

27 

28"""Simple unit test for configOverrides. 

29""" 

30 

31import tempfile 

32import unittest 

33 

34import lsst.pex.config as pexConfig 

35import lsst.utils.tests 

36from lsst.pipe.base.configOverrides import ConfigOverrides 

37from lsst.pipe.base.pipelineIR import ParametersIR 

38 

39# This is used in testSettingVar unit test 

40TEST_CHOICE_VALUE = 1 

41 

42 

43class ConfigTest(pexConfig.Config): 

44 """Configuration used for testing.""" 

45 

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

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

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

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

50 

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

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

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

54 

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

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

57 

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

59 

60 

61class ConfigOverridesTestCase(unittest.TestCase): 

62 """A test case for Task.""" 

63 

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

65 """Apply overrides of a single field. 

66 

67 Parameters 

68 ---------- 

69 field : `str` 

70 Field name. 

71 value : `typing.Any` 

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

73 result : optional 

74 Expected value of the field. 

75 """ 

76 config = ConfigTest() 

77 overrides = ConfigOverrides() 

78 overrides.addValueOverride(field, value) 

79 overrides.applyTo(config) 

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

81 

82 def testSimpleValueStr(self): 

83 """Test for applying value override to a string field.""" 

84 field = "fStr" 

85 

86 # values of supported type 

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

88 

89 # invalid input 

90 with self.assertRaises(pexConfig.FieldValidationError): 

91 self.checkSingleFieldOverride(field, 1) 

92 

93 def testSimpleValueBool(self): 

94 """Test for applying value override to a boolean field.""" 

95 field = "fBool" 

96 

97 # values of supported type 

98 self.checkSingleFieldOverride(field, True, True) 

99 self.checkSingleFieldOverride(field, False, False) 

100 

101 # supported string conversions 

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

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

104 

105 # parseable but invalid input 

106 with self.assertRaises(pexConfig.FieldValidationError): 

107 self.checkSingleFieldOverride(field, 1) 

108 with self.assertRaises(pexConfig.FieldValidationError): 

109 self.checkSingleFieldOverride(field, []) 

110 with self.assertRaises(pexConfig.FieldValidationError): 

111 self.checkSingleFieldOverride(field, "1") 

112 

113 def testSimpleValueInt(self): 

114 """Test for applying value override to a int field.""" 

115 field = "fInt" 

116 

117 # values of supported type 

118 self.checkSingleFieldOverride(field, 0, 0) 

119 self.checkSingleFieldOverride(field, 100, 100) 

120 

121 # supported string conversions 

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

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

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

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

126 

127 # parseable but invalid input 

128 with self.assertRaises(pexConfig.FieldValidationError): 

129 self.checkSingleFieldOverride(field, 1.0) 

130 with self.assertRaises(pexConfig.FieldValidationError): 

131 self.checkSingleFieldOverride(field, "1.0") 

132 with self.assertRaises(pexConfig.FieldValidationError): 

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

134 

135 def testSimpleValueFloat(self): 

136 """Test for applying value override to a float field.""" 

137 field = "fFloat" 

138 

139 # values of supported type 

140 self.checkSingleFieldOverride(field, 0.0, 0.0) 

141 self.checkSingleFieldOverride(field, 100.0, 100.0) 

142 

143 # supported string conversions 

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

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

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

147 

148 # parseable but invalid input 

149 with self.assertRaises(pexConfig.FieldValidationError): 

150 self.checkSingleFieldOverride(field, []) 

151 with self.assertRaises(pexConfig.FieldValidationError): 

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

153 

154 def testListValueStr(self): 

155 """Test for applying value override to a list field.""" 

156 field = "fListStr" 

157 

158 # values of supported type 

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

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

161 

162 # supported string conversions 

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

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

165 

166 # parseable but invalid input 

167 with self.assertRaises(pexConfig.FieldValidationError): 

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

169 

170 def testListValueBool(self): 

171 """Test for applying value override to a list field.""" 

172 field = "fListBool" 

173 

174 # values of supported type 

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

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

177 

178 # supported string conversions 

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

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

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

182 

183 with self.assertRaises(pexConfig.FieldValidationError): 

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

185 with self.assertRaises(pexConfig.FieldValidationError): 

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

187 with self.assertRaises(pexConfig.FieldValidationError): 

188 self.checkSingleFieldOverride(field, "5") 

189 

190 def testListValueInt(self): 

191 """Test for applying value override to a list field.""" 

192 field = "fListInt" 

193 

194 # values of supported type 

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

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

197 

198 # supported string conversions 

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

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

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

202 

203 # parseable but invalid input 

204 with self.assertRaises(pexConfig.FieldValidationError): 

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

206 with self.assertRaises(pexConfig.FieldValidationError): 

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

208 with self.assertRaises(pexConfig.FieldValidationError): 

209 self.checkSingleFieldOverride(field, "5") 

210 

211 def testChoiceValueStr(self): 

212 """Test for applying value override to a choice field.""" 

213 field = "fChoiceStr" 

214 

215 # values of supported type 

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

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

218 

219 # non-allowed value 

220 with self.assertRaises(pexConfig.FieldValidationError): 

221 self.checkSingleFieldOverride(field, "X") 

222 

223 def testChoiceValueInt(self): 

224 """Test for applying value override to a choice field.""" 

225 field = "fChoiceInt" 

226 

227 # values of supported type 

228 self.checkSingleFieldOverride(field, 1, 1) 

229 self.checkSingleFieldOverride(field, 3, 3) 

230 

231 # supported string conversions 

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

233 

234 # parseable but invalid input 

235 with self.assertRaises(pexConfig.FieldValidationError): 

236 self.checkSingleFieldOverride(field, "0") 

237 with self.assertRaises(pexConfig.FieldValidationError): 

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

239 with self.assertRaises(pexConfig.FieldValidationError): 

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

241 

242 def testSettingVar(self): 

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

244 field = "fChoiceInt" 

245 

246 # verify loading variable 

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

248 

249 # Verify That python importing a variable works 

250 config = ConfigTest() 

251 overrides = ConfigOverrides() 

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

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

254 overrides.applyTo(config) 

255 from math import pi 

256 

257 self.assertEqual(config.fFloat, pi) 

258 

259 def testDictValueInt(self): 

260 """Test for applying value override to a dict field.""" 

261 field = "fDictStrInt" 

262 

263 # values of supported type 

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

265 

266 # supported string conversions 

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

268 

269 # parseable but invalid input 

270 with self.assertRaises(pexConfig.FieldValidationError): 

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

272 with self.assertRaises(pexConfig.FieldValidationError): 

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

274 with self.assertRaises(pexConfig.FieldValidationError): 

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

276 

277 def testConfigParameters(self): 

278 """Test that passing parameters works.""" 

279 config = ConfigTest() 

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

281 overrides = ConfigOverrides() 

282 overrides.addParameters(parameters) 

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

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

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

286 fileOverride.seek(0) 

287 overrides.addFileOverride(fileOverride.name) 

288 overrides.applyTo(config) 

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

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

291 

292 overrides = ConfigOverrides() 

293 overrides.addParameters(parameters) 

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

295 with self.assertRaises(ValueError): 

296 overrides.applyTo(config) 

297 

298 

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

300 """Check for memory leaks.""" 

301 

302 

303def setup_module(module): 

304 """Configure pytest.""" 

305 lsst.utils.tests.init() 

306 

307 

308if __name__ == "__main__": 

309 lsst.utils.tests.init() 

310 unittest.main()