Coverage for tests/test_task.py : 29%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22import time
23import unittest
24import numbers
26import lsst.utils.tests
27import lsst.daf.base as dafBase
28from lsst.log import Log
29import lsst.pex.config as pexConfig
30import lsst.pipe.base as pipeBase
33class AddConfig(pexConfig.Config):
34 addend = pexConfig.Field(doc="amount to add", dtype=float, default=3.1)
37class AddTask(pipeBase.Task):
38 ConfigClass = AddConfig
40 @pipeBase.timeMethod
41 def run(self, val):
42 self.metadata.add("add", self.config.addend)
43 return pipeBase.Struct(
44 val=val + self.config.addend,
45 )
48class MultConfig(pexConfig.Config):
49 multiplicand = pexConfig.Field(doc="amount by which to multiply", dtype=float, default=2.5)
52class MultTask(pipeBase.Task):
53 ConfigClass = MultConfig
55 @pipeBase.timeMethod
56 def run(self, val):
57 self.metadata.add("mult", self.config.multiplicand)
58 return pipeBase.Struct(
59 val=val * self.config.multiplicand,
60 )
63# prove that registry fields can also be used to hold subtasks
64# by using a registry to hold MultTask
65multRegistry = pexConfig.makeRegistry("Registry for Mult-like tasks")
66multRegistry.register("stdMult", MultTask)
69class AddMultConfig(pexConfig.Config):
70 add = AddTask.makeField("add task")
71 mult = multRegistry.makeField("mult task", default="stdMult")
74class AddMultTask(pipeBase.Task):
75 ConfigClass = AddMultConfig
76 _DefaultName = "addMult"
78 """First add, then multiply"""
80 def __init__(self, **keyArgs):
81 pipeBase.Task.__init__(self, **keyArgs)
82 self.makeSubtask("add")
83 self.makeSubtask("mult")
85 @pipeBase.timeMethod
86 def run(self, val):
87 with self.timer("context"):
88 addRet = self.add.run(val)
89 multRet = self.mult.run(addRet.val)
90 self.metadata.add("addmult", multRet.val)
91 return pipeBase.Struct(
92 val=multRet.val,
93 )
95 @pipeBase.timeMethod
96 def failDec(self):
97 """A method that fails with a decorator
98 """
99 raise RuntimeError("failDec intentional error")
101 def failCtx(self):
102 """A method that fails inside a context manager
103 """
104 with self.timer("failCtx"):
105 raise RuntimeError("failCtx intentional error")
108class AddTwiceTask(AddTask):
109 """Variant of AddTask that adds twice the addend"""
111 def run(self, val):
112 addend = self.config.addend
113 return pipeBase.Struct(val=val + (2 * addend))
116class TaskTestCase(unittest.TestCase):
117 """A test case for Task
118 """
120 def setUp(self):
121 self.valDict = dict()
123 def tearDown(self):
124 self.valDict = None
126 def testBasics(self):
127 """Test basic construction and use of a task
128 """
129 for addend in (1.1, -3.5):
130 for multiplicand in (0.9, -45.0):
131 config = AddMultTask.ConfigClass()
132 config.add.addend = addend
133 config.mult["stdMult"].multiplicand = multiplicand
134 # make sure both ways of accessing the registry work and give the same result
135 self.assertEqual(config.mult.active.multiplicand, multiplicand)
136 addMultTask = AddMultTask(config=config)
137 for val in (-1.0, 0.0, 17.5):
138 ret = addMultTask.run(val=val)
139 self.assertAlmostEqual(ret.val, (val + addend) * multiplicand)
141 def testNames(self):
142 """Test getName() and getFullName()
143 """
144 addMultTask = AddMultTask()
145 self.assertEqual(addMultTask.getName(), "addMult")
146 self.assertEqual(addMultTask.add.getName(), "add")
147 self.assertEqual(addMultTask.mult.getName(), "mult")
149 self.assertEqual(addMultTask._name, "addMult")
150 self.assertEqual(addMultTask.add._name, "add")
151 self.assertEqual(addMultTask.mult._name, "mult")
153 self.assertEqual(addMultTask.getFullName(), "addMult")
154 self.assertEqual(addMultTask.add.getFullName(), "addMult.add")
155 self.assertEqual(addMultTask.mult.getFullName(), "addMult.mult")
157 self.assertEqual(addMultTask._fullName, "addMult")
158 self.assertEqual(addMultTask.add._fullName, "addMult.add")
159 self.assertEqual(addMultTask.mult._fullName, "addMult.mult")
161 def testLog(self):
162 """Test the Task's logger
163 """
164 addMultTask = AddMultTask()
165 self.assertEqual(addMultTask.log.getName(), "addMult")
166 self.assertEqual(addMultTask.add.log.getName(), "addMult.add")
168 log = Log.getLogger("tester")
169 addMultTask = AddMultTask(log=log)
170 self.assertEqual(addMultTask.log.getName(), "tester.addMult")
171 self.assertEqual(addMultTask.add.log.getName(), "tester.addMult.add")
173 def testGetFullMetadata(self):
174 """Test getFullMetadata()
175 """
176 addMultTask = AddMultTask()
177 fullMetadata = addMultTask.getFullMetadata()
178 self.assertIsInstance(fullMetadata.getPropertySet("addMult"), dafBase.PropertySet)
179 self.assertIsInstance(fullMetadata.getPropertySet("addMult:add"), dafBase.PropertySet)
180 self.assertIsInstance(fullMetadata.getPropertySet("addMult:mult"), dafBase.PropertySet)
182 def testEmptyMetadata(self):
183 task = AddMultTask()
184 task.run(val=1.2345)
185 task.emptyMetadata()
186 fullMetadata = task.getFullMetadata()
187 self.assertEqual(fullMetadata.getPropertySet("addMult").nameCount(), 0)
188 self.assertEqual(fullMetadata.getPropertySet("addMult:add").nameCount(), 0)
189 self.assertEqual(fullMetadata.getPropertySet("addMult:mult").nameCount(), 0)
191 def testReplace(self):
192 """Test replacing one subtask with another
193 """
194 for addend in (1.1, -3.5):
195 for multiplicand in (0.9, -45.0):
196 config = AddMultTask.ConfigClass()
197 config.add.retarget(AddTwiceTask)
198 config.add.addend = addend
199 config.mult["stdMult"].multiplicand = multiplicand
200 addMultTask = AddMultTask(config=config)
201 for val in (-1.0, 0.0, 17.5):
202 ret = addMultTask.run(val=val)
203 self.assertAlmostEqual(ret.val, (val + (2 * addend)) * multiplicand)
205 def testFail(self):
206 """Test timers when the code they are timing fails
207 """
208 addMultTask = AddMultTask()
209 try:
210 addMultTask.failDec()
211 self.fail("Expected RuntimeError")
212 except RuntimeError:
213 self.assertTrue(addMultTask.metadata.exists("failDecEndCpuTime"))
214 try:
215 addMultTask.failCtx()
216 self.fail("Expected RuntimeError")
217 except RuntimeError:
218 self.assertTrue(addMultTask.metadata.exists("failCtxEndCpuTime"))
220 def testTimeMethod(self):
221 """Test that the timer is adding the right metadata
222 """
223 addMultTask = AddMultTask()
224 addMultTask.run(val=1.1)
225 # Check existence and type
226 for key, keyType in (("Utc", str),
227 ("CpuTime", float),
228 ("UserTime", float),
229 ("SystemTime", float),
230 ("MaxResidentSetSize", numbers.Integral),
231 ("MinorPageFaults", numbers.Integral),
232 ("MajorPageFaults", numbers.Integral),
233 ("BlockInputs", numbers.Integral),
234 ("BlockOutputs", numbers.Integral),
235 ("VoluntaryContextSwitches", numbers.Integral),
236 ("InvoluntaryContextSwitches", numbers.Integral),
237 ):
238 for when in ("Start", "End"):
239 for method in ("run", "context"):
240 name = method + when + key
241 self.assertIn(name, addMultTask.metadata.names(),
242 name + " is missing from task metadata")
243 self.assertIsInstance(addMultTask.metadata.getScalar(name), keyType,
244 f"{name} is not of the right type "
245 f"({keyType} vs {type(addMultTask.metadata.getScalar(name))})")
246 # Some basic sanity checks
247 currCpuTime = time.process_time()
248 self.assertLessEqual(
249 addMultTask.metadata.getScalar("runStartCpuTime"),
250 addMultTask.metadata.getScalar("runEndCpuTime"),
251 )
252 self.assertLessEqual(addMultTask.metadata.getScalar("runEndCpuTime"), currCpuTime)
253 self.assertLessEqual(
254 addMultTask.metadata.getScalar("contextStartCpuTime"),
255 addMultTask.metadata.getScalar("contextEndCpuTime"),
256 )
257 self.assertLessEqual(addMultTask.metadata.getScalar("contextEndCpuTime"), currCpuTime)
258 self.assertLessEqual(
259 addMultTask.add.metadata.getScalar("runStartCpuTime"),
260 addMultTask.metadata.getScalar("runEndCpuTime"),
261 )
262 self.assertLessEqual(addMultTask.add.metadata.getScalar("runEndCpuTime"), currCpuTime)
265class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
266 pass
269def setup_module(module):
270 lsst.utils.tests.init()
273if __name__ == "__main__": 273 ↛ 274line 273 didn't jump to line 274, because the condition on line 273 was never true
274 lsst.utils.tests.init()
275 unittest.main()