Coverage for tests/test_task.py: 31%
Shortcuts 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
Shortcuts 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 logging
23import time
24import unittest
25import numbers
27import lsst.utils.tests
28import lsst.daf.base as dafBase
29import lsst.pex.config as pexConfig
30import lsst.pipe.base as pipeBase
31from lsst.utils.timer import timeMethod
34class AddConfig(pexConfig.Config):
35 addend = pexConfig.Field(doc="amount to add", dtype=float, default=3.1)
38class AddTask(pipeBase.Task):
39 ConfigClass = AddConfig
41 @timeMethod
42 def run(self, val):
43 self.metadata.add("add", self.config.addend)
44 return pipeBase.Struct(
45 val=val + self.config.addend,
46 )
49class MultConfig(pexConfig.Config):
50 multiplicand = pexConfig.Field(doc="amount by which to multiply", dtype=float, default=2.5)
53class MultTask(pipeBase.Task):
54 ConfigClass = MultConfig
56 @timeMethod
57 def run(self, val):
58 self.metadata.add("mult", self.config.multiplicand)
59 return pipeBase.Struct(
60 val=val * self.config.multiplicand,
61 )
64# prove that registry fields can also be used to hold subtasks
65# by using a registry to hold MultTask
66multRegistry = pexConfig.makeRegistry("Registry for Mult-like tasks")
67multRegistry.register("stdMult", MultTask)
70class AddMultConfig(pexConfig.Config):
71 add = AddTask.makeField("add task")
72 mult = multRegistry.makeField("mult task", default="stdMult")
75class AddMultTask(pipeBase.Task):
76 ConfigClass = AddMultConfig
77 _DefaultName = "addMult"
79 """First add, then multiply"""
81 def __init__(self, **keyArgs):
82 pipeBase.Task.__init__(self, **keyArgs)
83 self.makeSubtask("add")
84 self.makeSubtask("mult")
86 @timeMethod
87 def run(self, val):
88 with self.timer("context"):
89 addRet = self.add.run(val)
90 multRet = self.mult.run(addRet.val)
91 self.metadata.add("addmult", multRet.val)
92 return pipeBase.Struct(
93 val=multRet.val,
94 )
96 @timeMethod
97 def failDec(self):
98 """A method that fails with a decorator
99 """
100 raise RuntimeError("failDec intentional error")
102 def failCtx(self):
103 """A method that fails inside a context manager
104 """
105 with self.timer("failCtx"):
106 raise RuntimeError("failCtx intentional error")
109class AddTwiceTask(AddTask):
110 """Variant of AddTask that adds twice the addend"""
112 def run(self, val):
113 addend = self.config.addend
114 return pipeBase.Struct(val=val + (2 * addend))
117class TaskTestCase(unittest.TestCase):
118 """A test case for Task
119 """
121 def setUp(self):
122 self.valDict = dict()
124 def tearDown(self):
125 self.valDict = None
127 def testBasics(self):
128 """Test basic construction and use of a task
129 """
130 for addend in (1.1, -3.5):
131 for multiplicand in (0.9, -45.0):
132 config = AddMultTask.ConfigClass()
133 config.add.addend = addend
134 config.mult["stdMult"].multiplicand = multiplicand
135 # make sure both ways of accessing the registry work and give
136 # the same result
137 self.assertEqual(config.mult.active.multiplicand, multiplicand)
138 addMultTask = AddMultTask(config=config)
139 for val in (-1.0, 0.0, 17.5):
140 ret = addMultTask.run(val=val)
141 self.assertAlmostEqual(ret.val, (val + addend) * multiplicand)
143 def testNames(self):
144 """Test getName() and getFullName()
145 """
146 addMultTask = AddMultTask()
147 self.assertEqual(addMultTask.getName(), "addMult")
148 self.assertEqual(addMultTask.add.getName(), "add")
149 self.assertEqual(addMultTask.mult.getName(), "mult")
151 self.assertEqual(addMultTask._name, "addMult")
152 self.assertEqual(addMultTask.add._name, "add")
153 self.assertEqual(addMultTask.mult._name, "mult")
155 self.assertEqual(addMultTask.getFullName(), "addMult")
156 self.assertEqual(addMultTask.add.getFullName(), "addMult.add")
157 self.assertEqual(addMultTask.mult.getFullName(), "addMult.mult")
159 self.assertEqual(addMultTask._fullName, "addMult")
160 self.assertEqual(addMultTask.add._fullName, "addMult.add")
161 self.assertEqual(addMultTask.mult._fullName, "addMult.mult")
163 def testLog(self):
164 """Test the Task's logger
165 """
166 addMultTask = AddMultTask()
167 self.assertEqual(addMultTask.log.name, "addMult")
168 self.assertEqual(addMultTask.add.log.name, "addMult.add")
170 log = logging.getLogger("tester")
171 addMultTask = AddMultTask(log=log)
172 self.assertEqual(addMultTask.log.name, "tester.addMult")
173 self.assertEqual(addMultTask.add.log.name, "tester.addMult.add")
175 def testGetFullMetadata(self):
176 """Test getFullMetadata()
177 """
178 addMultTask = AddMultTask()
179 fullMetadata = addMultTask.getFullMetadata()
180 self.assertIsInstance(fullMetadata.getPropertySet("addMult"), dafBase.PropertySet)
181 self.assertIsInstance(fullMetadata.getPropertySet("addMult:add"), dafBase.PropertySet)
182 self.assertIsInstance(fullMetadata.getPropertySet("addMult:mult"), dafBase.PropertySet)
184 def testEmptyMetadata(self):
185 task = AddMultTask()
186 task.run(val=1.2345)
187 task.emptyMetadata()
188 fullMetadata = task.getFullMetadata()
189 self.assertEqual(fullMetadata.getPropertySet("addMult").nameCount(), 0)
190 self.assertEqual(fullMetadata.getPropertySet("addMult:add").nameCount(), 0)
191 self.assertEqual(fullMetadata.getPropertySet("addMult:mult").nameCount(), 0)
193 def testReplace(self):
194 """Test replacing one subtask with another
195 """
196 for addend in (1.1, -3.5):
197 for multiplicand in (0.9, -45.0):
198 config = AddMultTask.ConfigClass()
199 config.add.retarget(AddTwiceTask)
200 config.add.addend = addend
201 config.mult["stdMult"].multiplicand = multiplicand
202 addMultTask = AddMultTask(config=config)
203 for val in (-1.0, 0.0, 17.5):
204 ret = addMultTask.run(val=val)
205 self.assertAlmostEqual(ret.val, (val + (2 * addend)) * multiplicand)
207 def testFail(self):
208 """Test timers when the code they are timing fails
209 """
210 addMultTask = AddMultTask()
211 try:
212 addMultTask.failDec()
213 self.fail("Expected RuntimeError")
214 except RuntimeError:
215 self.assertTrue(addMultTask.metadata.exists("failDecEndCpuTime"))
216 try:
217 addMultTask.failCtx()
218 self.fail("Expected RuntimeError")
219 except RuntimeError:
220 self.assertTrue(addMultTask.metadata.exists("failCtxEndCpuTime"))
222 def testTimeMethod(self):
223 """Test that the timer is adding the right metadata
224 """
225 addMultTask = AddMultTask()
226 addMultTask.run(val=1.1)
227 # Check existence and type
228 for key, keyType in (("Utc", str),
229 ("CpuTime", float),
230 ("UserTime", float),
231 ("SystemTime", float),
232 ("MaxResidentSetSize", numbers.Integral),
233 ("MinorPageFaults", numbers.Integral),
234 ("MajorPageFaults", numbers.Integral),
235 ("BlockInputs", numbers.Integral),
236 ("BlockOutputs", numbers.Integral),
237 ("VoluntaryContextSwitches", numbers.Integral),
238 ("InvoluntaryContextSwitches", numbers.Integral),
239 ):
240 for when in ("Start", "End"):
241 for method in ("run", "context"):
242 name = method + when + key
243 self.assertIn(name, addMultTask.metadata.names(),
244 name + " is missing from task metadata")
245 self.assertIsInstance(addMultTask.metadata.getScalar(name), keyType,
246 f"{name} is not of the right type "
247 f"({keyType} vs {type(addMultTask.metadata.getScalar(name))})")
248 # Some basic sanity checks
249 currCpuTime = time.process_time()
250 self.assertLessEqual(
251 addMultTask.metadata.getScalar("runStartCpuTime"),
252 addMultTask.metadata.getScalar("runEndCpuTime"),
253 )
254 self.assertLessEqual(addMultTask.metadata.getScalar("runEndCpuTime"), currCpuTime)
255 self.assertLessEqual(
256 addMultTask.metadata.getScalar("contextStartCpuTime"),
257 addMultTask.metadata.getScalar("contextEndCpuTime"),
258 )
259 self.assertLessEqual(addMultTask.metadata.getScalar("contextEndCpuTime"), currCpuTime)
260 self.assertLessEqual(
261 addMultTask.add.metadata.getScalar("runStartCpuTime"),
262 addMultTask.metadata.getScalar("runEndCpuTime"),
263 )
264 self.assertLessEqual(addMultTask.add.metadata.getScalar("runEndCpuTime"), currCpuTime)
267class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
268 pass
271def setup_module(module):
272 lsst.utils.tests.init()
275if __name__ == "__main__": 275 ↛ 276line 275 didn't jump to line 276, because the condition on line 275 was never true
276 lsst.utils.tests.init()
277 unittest.main()