Coverage for tests / test_configOverrides.py: 21%
159 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 08:57 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 08:57 +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 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/>.
28"""Simple unit test for configOverrides."""
30import tempfile
31import unittest
33import lsst.pex.config as pexConfig
34import lsst.utils.tests
35from lsst.pipe.base.configOverrides import ConfigOverrides
36from lsst.pipe.base.pipelineIR import ParametersIR
38# This is used in testSettingVar unit test
39TEST_CHOICE_VALUE = 1
42class ConfigTest(pexConfig.Config):
43 """Configuration used for testing."""
45 fStr = pexConfig.Field(dtype=str, default="default", doc="test")
46 fBool = pexConfig.Field(dtype=bool, default=False, doc="test")
47 fInt = pexConfig.Field(dtype=int, default=-1, doc="test")
48 fFloat = pexConfig.Field(dtype=float, default=-1.0, doc="test")
50 fListStr = pexConfig.ListField(dtype=str, default=[], doc="test")
51 fListBool = pexConfig.ListField(dtype=bool, default=[], doc="test")
52 fListInt = pexConfig.ListField(dtype=int, default=[], doc="test")
54 fChoiceStr = pexConfig.ChoiceField(dtype=str, allowed=dict(A="a", B="b", C="c"), doc="test")
55 fChoiceInt = pexConfig.ChoiceField(dtype=int, allowed={1: "a", 2: "b", 3: "c"}, doc="test")
57 fDictStrInt = pexConfig.DictField(keytype=str, itemtype=int, doc="test")
60class ConfigOverridesTestCase(unittest.TestCase):
61 """A test case for Task."""
63 def checkSingleFieldOverride(self, field, value, result=None):
64 """Apply overrides of a single field.
66 Parameters
67 ----------
68 field : `str`
69 Field name.
70 value : `typing.Any`
71 Field value to set, can be a string or anything else.
72 result : `typing.Any`, optional
73 Expected value of the field.
74 """
75 config = ConfigTest()
76 overrides = ConfigOverrides()
77 overrides.addValueOverride(field, value)
78 overrides.applyTo(config)
79 self.assertEqual(getattr(config, field), result)
81 def testSimpleValueStr(self):
82 """Test for applying value override to a string field."""
83 field = "fStr"
85 # values of supported type
86 self.checkSingleFieldOverride(field, "string", "string")
88 # invalid input
89 with self.assertRaises(pexConfig.FieldValidationError):
90 self.checkSingleFieldOverride(field, 1)
92 def testSimpleValueBool(self):
93 """Test for applying value override to a boolean field."""
94 field = "fBool"
96 # values of supported type
97 self.checkSingleFieldOverride(field, True, True)
98 self.checkSingleFieldOverride(field, False, False)
100 # supported string conversions
101 self.checkSingleFieldOverride(field, "True", True)
102 self.checkSingleFieldOverride(field, "False", False)
104 # parseable but invalid input
105 with self.assertRaises(pexConfig.FieldValidationError):
106 self.checkSingleFieldOverride(field, 1)
107 with self.assertRaises(pexConfig.FieldValidationError):
108 self.checkSingleFieldOverride(field, [])
109 with self.assertRaises(pexConfig.FieldValidationError):
110 self.checkSingleFieldOverride(field, "1")
112 def testSimpleValueInt(self):
113 """Test for applying value override to a int field."""
114 field = "fInt"
116 # values of supported type
117 self.checkSingleFieldOverride(field, 0, 0)
118 self.checkSingleFieldOverride(field, 100, 100)
120 # supported string conversions
121 self.checkSingleFieldOverride(field, "0", 0)
122 self.checkSingleFieldOverride(field, "100", 100)
123 self.checkSingleFieldOverride(field, "-100", -100)
124 self.checkSingleFieldOverride(field, "0x100", 0x100)
126 # parseable but invalid input
127 with self.assertRaises(pexConfig.FieldValidationError):
128 self.checkSingleFieldOverride(field, 1.0)
129 with self.assertRaises(pexConfig.FieldValidationError):
130 self.checkSingleFieldOverride(field, "1.0")
131 with self.assertRaises(pexConfig.FieldValidationError):
132 self.checkSingleFieldOverride(field, "[]")
134 def testSimpleValueFloat(self):
135 """Test for applying value override to a float field."""
136 field = "fFloat"
138 # values of supported type
139 self.checkSingleFieldOverride(field, 0.0, 0.0)
140 self.checkSingleFieldOverride(field, 100.0, 100.0)
142 # supported string conversions
143 self.checkSingleFieldOverride(field, "0.", 0.0)
144 self.checkSingleFieldOverride(field, "100.0", 100.0)
145 self.checkSingleFieldOverride(field, "-1.2e10", -1.2e10)
147 # parseable but invalid input
148 with self.assertRaises(pexConfig.FieldValidationError):
149 self.checkSingleFieldOverride(field, [])
150 with self.assertRaises(pexConfig.FieldValidationError):
151 self.checkSingleFieldOverride(field, "(1, 1)")
153 def testListValueStr(self):
154 """Test for applying value override to a list field."""
155 field = "fListStr"
157 # values of supported type
158 self.checkSingleFieldOverride(field, ["a", "b"], ["a", "b"])
159 self.checkSingleFieldOverride(field, ("a", "b"), ["a", "b"])
161 # supported string conversions
162 self.checkSingleFieldOverride(field, '["a", "b"]', ["a", "b"])
163 self.checkSingleFieldOverride(field, '("a", "b")', ["a", "b"])
165 # parseable but invalid input
166 with self.assertRaises(pexConfig.FieldValidationError):
167 self.checkSingleFieldOverride(field, "['a', []]")
169 def testListValueBool(self):
170 """Test for applying value override to a list field."""
171 field = "fListBool"
173 # values of supported type
174 self.checkSingleFieldOverride(field, [True, False], [True, False])
175 self.checkSingleFieldOverride(field, (True, False), [True, False])
177 # supported string conversions
178 self.checkSingleFieldOverride(field, "[True, False]", [True, False])
179 self.checkSingleFieldOverride(field, "(True, False)", [True, False])
180 self.checkSingleFieldOverride(field, "['True', 'False']", [True, False])
182 with self.assertRaises(pexConfig.FieldValidationError):
183 self.checkSingleFieldOverride(field, "[1, 2]")
184 with self.assertRaises(pexConfig.FieldValidationError):
185 self.checkSingleFieldOverride(field, [0, 1])
186 with self.assertRaises(pexConfig.FieldValidationError):
187 self.checkSingleFieldOverride(field, "5")
189 def testListValueInt(self):
190 """Test for applying value override to a list field."""
191 field = "fListInt"
193 # values of supported type
194 self.checkSingleFieldOverride(field, [1, 2], [1, 2])
195 self.checkSingleFieldOverride(field, (1, 2), [1, 2])
197 # supported string conversions
198 self.checkSingleFieldOverride(field, "[1, 2]", [1, 2])
199 self.checkSingleFieldOverride(field, "(1, 2)", [1, 2])
200 self.checkSingleFieldOverride(field, "['1', '2']", [1, 2])
202 # parseable but invalid input
203 with self.assertRaises(pexConfig.FieldValidationError):
204 self.checkSingleFieldOverride(field, "[1.0, []]")
205 with self.assertRaises(pexConfig.FieldValidationError):
206 self.checkSingleFieldOverride(field, [[], []])
207 with self.assertRaises(pexConfig.FieldValidationError):
208 self.checkSingleFieldOverride(field, "5")
210 def testChoiceValueStr(self):
211 """Test for applying value override to a choice field."""
212 field = "fChoiceStr"
214 # values of supported type
215 self.checkSingleFieldOverride(field, "A", "A")
216 self.checkSingleFieldOverride(field, "B", "B")
218 # non-allowed value
219 with self.assertRaises(pexConfig.FieldValidationError):
220 self.checkSingleFieldOverride(field, "X")
222 def testChoiceValueInt(self):
223 """Test for applying value override to a choice field."""
224 field = "fChoiceInt"
226 # values of supported type
227 self.checkSingleFieldOverride(field, 1, 1)
228 self.checkSingleFieldOverride(field, 3, 3)
230 # supported string conversions
231 self.checkSingleFieldOverride(field, "1", 1)
233 # parseable but invalid input
234 with self.assertRaises(pexConfig.FieldValidationError):
235 self.checkSingleFieldOverride(field, "0")
236 with self.assertRaises(pexConfig.FieldValidationError):
237 self.checkSingleFieldOverride(field, "[1]")
238 with self.assertRaises(pexConfig.FieldValidationError):
239 self.checkSingleFieldOverride(field, [0, 1])
241 def testSettingVar(self):
242 """Test setting a field with a string that represents a variable."""
243 field = "fChoiceInt"
245 # verify loading variable
246 self.checkSingleFieldOverride(field, "TEST_CHOICE_VALUE", 1)
248 # Verify That python importing a variable works
249 config = ConfigTest()
250 overrides = ConfigOverrides()
251 overrides.addPythonOverride("from math import pi")
252 overrides.addValueOverride("fFloat", "pi")
253 overrides.applyTo(config)
254 from math import pi
256 self.assertEqual(config.fFloat, pi)
258 def testDictValueInt(self):
259 """Test for applying value override to a dict field."""
260 field = "fDictStrInt"
262 # values of supported type
263 self.checkSingleFieldOverride(field, dict(a=1, b=2), dict(a=1, b=2))
265 # supported string conversions
266 self.checkSingleFieldOverride(field, "{'a': 1, 'b': 2}", dict(a=1, b=2))
268 # parseable but invalid input
269 with self.assertRaises(pexConfig.FieldValidationError):
270 self.checkSingleFieldOverride(field, "{1: 2}")
271 with self.assertRaises(pexConfig.FieldValidationError):
272 self.checkSingleFieldOverride(field, "{'a': 'b'}")
273 with self.assertRaises(pexConfig.FieldValidationError):
274 self.checkSingleFieldOverride(field, {"a": "b"})
276 def testConfigParameters(self):
277 """Test that passing parameters works."""
278 config = ConfigTest()
279 parameters = ParametersIR(mapping={"number": 6, "text": "hello world"})
280 overrides = ConfigOverrides()
281 overrides.addParameters(parameters)
282 overrides.addPythonOverride("config.fStr = parameters.text")
283 with tempfile.NamedTemporaryFile(mode="w") as fileOverride:
284 fileOverride.write("config.fInt = parameters.number")
285 fileOverride.seek(0)
286 overrides.addFileOverride(fileOverride.name)
287 overrides.applyTo(config)
288 self.assertEqual(config.fStr, parameters.mapping["text"])
289 self.assertEqual(config.fInt, parameters.mapping["number"])
291 overrides = ConfigOverrides()
292 overrides.addParameters(parameters)
293 overrides.addPythonOverride("parameters.fail = 9")
294 with self.assertRaises(ValueError):
295 overrides.applyTo(config)
298class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
299 """Check for memory leaks."""
302def setup_module(module):
303 """Configure pytest."""
304 lsst.utils.tests.init()
307if __name__ == "__main__":
308 lsst.utils.tests.init()
309 unittest.main()