Hide keyboard shortcuts

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 

25 

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 

31 

32 

33class AddConfig(pexConfig.Config): 

34 addend = pexConfig.Field(doc="amount to add", dtype=float, default=3.1) 

35 

36 

37class AddTask(pipeBase.Task): 

38 ConfigClass = AddConfig 

39 

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 ) 

46 

47 

48class MultConfig(pexConfig.Config): 

49 multiplicand = pexConfig.Field(doc="amount by which to multiply", dtype=float, default=2.5) 

50 

51 

52class MultTask(pipeBase.Task): 

53 ConfigClass = MultConfig 

54 

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 ) 

61 

62 

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) 

67 

68 

69class AddMultConfig(pexConfig.Config): 

70 add = AddTask.makeField("add task") 

71 mult = multRegistry.makeField("mult task", default="stdMult") 

72 

73 

74class AddMultTask(pipeBase.Task): 

75 ConfigClass = AddMultConfig 

76 _DefaultName = "addMult" 

77 

78 """First add, then multiply""" 

79 

80 def __init__(self, **keyArgs): 

81 pipeBase.Task.__init__(self, **keyArgs) 

82 self.makeSubtask("add") 

83 self.makeSubtask("mult") 

84 

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 ) 

94 

95 @pipeBase.timeMethod 

96 def failDec(self): 

97 """A method that fails with a decorator 

98 """ 

99 raise RuntimeError("failDec intentional error") 

100 

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") 

106 

107 

108class AddTwiceTask(AddTask): 

109 """Variant of AddTask that adds twice the addend""" 

110 

111 def run(self, val): 

112 addend = self.config.addend 

113 return pipeBase.Struct(val=val + (2 * addend)) 

114 

115 

116class TaskTestCase(unittest.TestCase): 

117 """A test case for Task 

118 """ 

119 

120 def setUp(self): 

121 self.valDict = dict() 

122 

123 def tearDown(self): 

124 self.valDict = None 

125 

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) 

141 

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") 

149 

150 self.assertEqual(addMultTask._name, "addMult") 

151 self.assertEqual(addMultTask.add._name, "add") 

152 self.assertEqual(addMultTask.mult._name, "mult") 

153 

154 self.assertEqual(addMultTask.getFullName(), "addMult") 

155 self.assertEqual(addMultTask.add.getFullName(), "addMult.add") 

156 self.assertEqual(addMultTask.mult.getFullName(), "addMult.mult") 

157 

158 self.assertEqual(addMultTask._fullName, "addMult") 

159 self.assertEqual(addMultTask.add._fullName, "addMult.add") 

160 self.assertEqual(addMultTask.mult._fullName, "addMult.mult") 

161 

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") 

168 

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") 

173 

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) 

182 

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) 

191 

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) 

205 

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")) 

220 

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) 

264 

265 

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

267 pass 

268 

269 

270def setup_module(module): 

271 lsst.utils.tests.init() 

272 

273 

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()