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
135 # the same result
136 self.assertEqual(config.mult.active.multiplicand, multiplicand)
137 addMultTask = AddMultTask(config=config)
138 for val in (-1.0, 0.0, 17.5):
139 ret = addMultTask.run(val=val)
140 self.assertAlmostEqual(ret.val, (val + addend) * multiplicand)
142 def testNames(self):
143 """Test getName() and getFullName()
144 """
145 addMultTask = AddMultTask()
146 self.assertEqual(addMultTask.getName(), "addMult")
147 self.assertEqual(addMultTask.add.getName(), "add")
148 self.assertEqual(addMultTask.mult.getName(), "mult")
150 self.assertEqual(addMultTask._name, "addMult")
151 self.assertEqual(addMultTask.add._name, "add")
152 self.assertEqual(addMultTask.mult._name, "mult")
154 self.assertEqual(addMultTask.getFullName(), "addMult")
155 self.assertEqual(addMultTask.add.getFullName(), "addMult.add")
156 self.assertEqual(addMultTask.mult.getFullName(), "addMult.mult")
158 self.assertEqual(addMultTask._fullName, "addMult")
159 self.assertEqual(addMultTask.add._fullName, "addMult.add")
160 self.assertEqual(addMultTask.mult._fullName, "addMult.mult")
162 def testLog(self):
163 """Test the Task's logger
164 """
165 addMultTask = AddMultTask()
166 self.assertEqual(addMultTask.log.getName(), "addMult")
167 self.assertEqual(addMultTask.add.log.getName(), "addMult.add")
169 log = Log.getLogger("tester")
170 addMultTask = AddMultTask(log=log)
171 self.assertEqual(addMultTask.log.getName(), "tester.addMult")
172 self.assertEqual(addMultTask.add.log.getName(), "tester.addMult.add")
174 def testGetFullMetadata(self):
175 """Test getFullMetadata()
176 """
177 addMultTask = AddMultTask()
178 fullMetadata = addMultTask.getFullMetadata()
179 self.assertIsInstance(fullMetadata.getPropertySet("addMult"), dafBase.PropertySet)
180 self.assertIsInstance(fullMetadata.getPropertySet("addMult:add"), dafBase.PropertySet)
181 self.assertIsInstance(fullMetadata.getPropertySet("addMult:mult"), dafBase.PropertySet)
183 def testEmptyMetadata(self):
184 task = AddMultTask()
185 task.run(val=1.2345)
186 task.emptyMetadata()
187 fullMetadata = task.getFullMetadata()
188 self.assertEqual(fullMetadata.getPropertySet("addMult").nameCount(), 0)
189 self.assertEqual(fullMetadata.getPropertySet("addMult:add").nameCount(), 0)
190 self.assertEqual(fullMetadata.getPropertySet("addMult:mult").nameCount(), 0)
192 def testReplace(self):
193 """Test replacing one subtask with another
194 """
195 for addend in (1.1, -3.5):
196 for multiplicand in (0.9, -45.0):
197 config = AddMultTask.ConfigClass()
198 config.add.retarget(AddTwiceTask)
199 config.add.addend = addend
200 config.mult["stdMult"].multiplicand = multiplicand
201 addMultTask = AddMultTask(config=config)
202 for val in (-1.0, 0.0, 17.5):
203 ret = addMultTask.run(val=val)
204 self.assertAlmostEqual(ret.val, (val + (2 * addend)) * multiplicand)
206 def testFail(self):
207 """Test timers when the code they are timing fails
208 """
209 addMultTask = AddMultTask()
210 try:
211 addMultTask.failDec()
212 self.fail("Expected RuntimeError")
213 except RuntimeError:
214 self.assertTrue(addMultTask.metadata.exists("failDecEndCpuTime"))
215 try:
216 addMultTask.failCtx()
217 self.fail("Expected RuntimeError")
218 except RuntimeError:
219 self.assertTrue(addMultTask.metadata.exists("failCtxEndCpuTime"))
221 def testTimeMethod(self):
222 """Test that the timer is adding the right metadata
223 """
224 addMultTask = AddMultTask()
225 addMultTask.run(val=1.1)
226 # Check existence and type
227 for key, keyType in (("Utc", str),
228 ("CpuTime", float),
229 ("UserTime", float),
230 ("SystemTime", float),
231 ("MaxResidentSetSize", numbers.Integral),
232 ("MinorPageFaults", numbers.Integral),
233 ("MajorPageFaults", numbers.Integral),
234 ("BlockInputs", numbers.Integral),
235 ("BlockOutputs", numbers.Integral),
236 ("VoluntaryContextSwitches", numbers.Integral),
237 ("InvoluntaryContextSwitches", numbers.Integral),
238 ):
239 for when in ("Start", "End"):
240 for method in ("run", "context"):
241 name = method + when + key
242 self.assertIn(name, addMultTask.metadata.names(),
243 name + " is missing from task metadata")
244 self.assertIsInstance(addMultTask.metadata.getScalar(name), keyType,
245 f"{name} is not of the right type "
246 f"({keyType} vs {type(addMultTask.metadata.getScalar(name))})")
247 # Some basic sanity checks
248 currCpuTime = time.process_time()
249 self.assertLessEqual(
250 addMultTask.metadata.getScalar("runStartCpuTime"),
251 addMultTask.metadata.getScalar("runEndCpuTime"),
252 )
253 self.assertLessEqual(addMultTask.metadata.getScalar("runEndCpuTime"), currCpuTime)
254 self.assertLessEqual(
255 addMultTask.metadata.getScalar("contextStartCpuTime"),
256 addMultTask.metadata.getScalar("contextEndCpuTime"),
257 )
258 self.assertLessEqual(addMultTask.metadata.getScalar("contextEndCpuTime"), currCpuTime)
259 self.assertLessEqual(
260 addMultTask.add.metadata.getScalar("runStartCpuTime"),
261 addMultTask.metadata.getScalar("runEndCpuTime"),
262 )
263 self.assertLessEqual(addMultTask.add.metadata.getScalar("runEndCpuTime"), currCpuTime)
266class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
267 pass
270def setup_module(module):
271 lsst.utils.tests.init()
274if __name__ == "__main__": 274 ↛ 275line 274 didn't jump to line 275, because the condition on line 274 was never true
275 lsst.utils.tests.init()
276 unittest.main()