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

140 

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

148 

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

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

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

152 

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

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

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

156 

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

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

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

160 

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

167 

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

172 

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) 

181 

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) 

190 

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) 

204 

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

219 

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) 

263 

264 

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

266 pass 

267 

268 

269def setup_module(module): 

270 lsst.utils.tests.init() 

271 

272 

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