Coverage for tests/test_wrappers.py: 12%

348 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-06 03:35 -0700

1# This file is part of utils. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22import unittest 

23 

24import lsst.utils 

25import lsst.utils.tests 

26import numpy as np 

27 

28 

29class MockClass: # continued class needs to be at module scope 

30 """A test class that can be continued.""" 

31 

32 def method1(self): 

33 return self 

34 

35 @classmethod 

36 def method2(cls): 

37 return cls 

38 

39 @staticmethod 

40 def method3(): 

41 return True 

42 

43 @property 

44 def property1(self): 

45 return False 

46 

47 

48class DecoratorsTestCase(lsst.utils.tests.TestCase): 

49 """Test the decorators.""" 

50 

51 def setUp(self): 

52 @lsst.utils.continueClass 

53 class MockClass: 

54 def method1a(self): 

55 return self 

56 

57 @classmethod 

58 def method2a(cls): 

59 return cls 

60 

61 @staticmethod 

62 def method3a(): 

63 return True 

64 

65 @property 

66 def property1a(self): 

67 return False 

68 

69 @lsst.utils.inClass(MockClass) 

70 def method1b(self): 

71 return self 

72 

73 @lsst.utils.inClass(MockClass) 

74 @classmethod 

75 def method2b(cls): 

76 return cls 

77 

78 @lsst.utils.inClass(MockClass) 

79 @staticmethod 

80 def method3b(): 

81 return True 

82 

83 @lsst.utils.inClass(MockClass) 

84 @property 

85 def property1b(self): 

86 return False 

87 

88 def testAttributeCopying(self): 

89 x = MockClass() 

90 self.assertIs(x.method1(), x) 

91 self.assertIs(x.method1a(), x) 

92 self.assertIs(x.method1b(), x) 

93 self.assertIs(x.method2(), MockClass) 

94 self.assertIs(x.method2a(), MockClass) 

95 self.assertIs(x.method2b(), MockClass) 

96 self.assertIs(MockClass.method2(), MockClass) 

97 self.assertIs(MockClass.method2a(), MockClass) 

98 self.assertIs(MockClass.method2b(), MockClass) 

99 self.assertTrue(x.method3()) 

100 self.assertTrue(x.method3a()) 

101 self.assertTrue(x.method3b()) 

102 self.assertTrue(MockClass.method3()) 

103 self.assertTrue(MockClass.method3a()) 

104 self.assertTrue(MockClass.method3b()) 

105 self.assertFalse(x.property1) 

106 self.assertFalse(x.property1a) 

107 self.assertFalse(x.property1b) 

108 

109 

110class TemplateMetaSimpleTestCase(lsst.utils.tests.TestCase): 

111 """Test TemplateMeta on a mockup of a template with a single dtype 

112 template parameter. 

113 """ 

114 

115 def setUp(self): 

116 class Example(metaclass=lsst.utils.TemplateMeta): 

117 def method1(self): 

118 return self 

119 

120 @classmethod 

121 def method2(cls): 

122 return cls 

123 

124 @staticmethod 

125 def method3(): 

126 return True 

127 

128 @property 

129 def property1(self): 

130 return False 

131 

132 class ExampleF: 

133 pass 

134 

135 class ExampleD: 

136 pass 

137 

138 self.Example = Example 

139 self.ExampleF = ExampleF 

140 self.ExampleD = ExampleD 

141 

142 def register(self): 

143 self.Example.register(np.float32, self.ExampleF) 

144 self.Example.register(np.float64, self.ExampleD) 

145 

146 def alias(self): 

147 self.Example.alias("F", self.ExampleF) 

148 self.Example.alias("D", self.ExampleD) 

149 

150 def testCorrectRegistration(self): 

151 self.register() 

152 self.assertEqual(self.ExampleF.dtype, np.float32) 

153 self.assertEqual(self.ExampleD.dtype, np.float64) 

154 self.assertIn(np.float32, self.Example) 

155 self.assertIn(np.float64, self.Example) 

156 self.assertEqual(self.Example[np.float32], self.ExampleF) 

157 self.assertEqual(self.Example[np.float64], self.ExampleD) 

158 

159 def testAliases(self): 

160 self.register() 

161 self.alias() 

162 self.assertEqual(self.ExampleF.dtype, np.float32) 

163 self.assertEqual(self.ExampleD.dtype, np.float64) 

164 self.assertIn("F", self.Example) 

165 self.assertIn("D", self.Example) 

166 self.assertEqual(self.Example["F"], self.ExampleF) 

167 self.assertEqual(self.Example["D"], self.ExampleD) 

168 self.assertEqual(self.Example["F"], self.Example[np.float32]) 

169 self.assertEqual(self.Example["D"], self.Example[np.float64]) 

170 

171 def testInheritanceHooks(self): 

172 self.register() 

173 self.assertTrue(issubclass(self.ExampleF, self.Example)) 

174 self.assertTrue(issubclass(self.ExampleD, self.Example)) 

175 f = self.ExampleF() 

176 d = self.ExampleD() 

177 self.assertIsInstance(f, self.Example) 

178 self.assertIsInstance(d, self.Example) 

179 self.assertEqual(set(self.Example.__subclasses__()), {self.ExampleF, self.ExampleD}) 

180 

181 # To test fallback code path, ensure that there are multiple 

182 # examples to check. 

183 class ExampleSub(self.ExampleD): 

184 # A subclass that is not itself registered. 

185 pass 

186 

187 class Example2(metaclass=lsst.utils.TemplateMeta): 

188 # A new independent class. 

189 pass 

190 

191 class Example2I: 

192 # Something that will be registered in independent hierarchy. 

193 pass 

194 

195 Example2.register(np.int32, Example2I) 

196 

197 sub = ExampleSub() 

198 self.assertIsInstance(sub, self.Example) 

199 self.assertNotIsInstance(sub, Example2) 

200 self.assertTrue(issubclass(ExampleSub, self.Example)) 

201 self.assertFalse(issubclass(ExampleSub, Example2)) 

202 

203 def testConstruction(self): 

204 self.register() 

205 f1 = self.Example(dtype=np.float32) 

206 # Test that numpy dtype objects resolve to their underlying type 

207 f2 = self.Example(dtype=np.dtype(np.float32)) 

208 for f in (f1, f2): 

209 self.assertIsInstance(f, self.Example) 

210 self.assertIsInstance(f, self.ExampleF) 

211 self.assertNotIsInstance(f, self.ExampleD) 

212 

213 with self.assertRaises(TypeError): 

214 self.Example() 

215 with self.assertRaises(TypeError): 

216 self.Example(dtype=np.int32) 

217 

218 def testAttributeCopying(self): 

219 self.register() 

220 f = self.ExampleF() 

221 d = self.ExampleD() 

222 self.assertIs(f.method1(), f) 

223 self.assertIs(d.method1(), d) 

224 self.assertIs(f.method2(), self.ExampleF) 

225 self.assertIs(d.method2(), self.ExampleD) 

226 self.assertIs(self.ExampleF.method2(), self.ExampleF) 

227 self.assertIs(self.ExampleD.method2(), self.ExampleD) 

228 self.assertTrue(f.method3()) 

229 self.assertTrue(d.method3()) 

230 self.assertTrue(self.ExampleF.method3()) 

231 self.assertTrue(self.ExampleD.method3()) 

232 self.assertFalse(f.property1) 

233 self.assertFalse(d.property1) 

234 

235 def testDictBehavior(self): 

236 self.register() 

237 self.assertIn(np.float32, self.Example) 

238 self.assertEqual(self.Example[np.float32], self.ExampleF) 

239 self.assertEqual(set(self.Example.keys()), {np.float32, np.float64}) 

240 self.assertEqual(set(self.Example.values()), {self.ExampleF, self.ExampleD}) 

241 self.assertEqual( 

242 set(self.Example.items()), {(np.float32, self.ExampleF), (np.float64, self.ExampleD)} 

243 ) 

244 self.assertEqual(len(self.Example), 2) 

245 self.assertEqual(set(iter(self.Example)), {np.float32, np.float64}) 

246 self.assertEqual(self.Example.get(np.float64), self.ExampleD) 

247 self.assertEqual(self.Example.get(np.int32, False), False) 

248 

249 def testNoInheritedDictBehavior(self): 

250 self.register() 

251 f = self.ExampleF() 

252 with self.assertRaises(TypeError): 

253 len(f) 

254 with self.assertRaises(TypeError): 

255 f["F"] 

256 with self.assertRaises(TypeError): 

257 for _ in f: 

258 pass 

259 with self.assertRaises(TypeError): 

260 len(self.ExampleF) 

261 with self.assertRaises(TypeError): 

262 self.ExampleF["F"] 

263 with self.assertRaises(TypeError): 

264 for _ in self.ExampleF: 

265 pass 

266 

267 def testAliasUnregistered(self): 

268 with self.assertRaises(ValueError): 

269 self.Example.alias("F", self.ExampleF) 

270 self.assertEqual(len(self.Example), 0) 

271 self.assertEqual(len(self.Example), 0) 

272 

273 def testRegisterDTypeTwice(self): 

274 with self.assertRaises(KeyError): 

275 self.Example.register("F", self.ExampleF) 

276 self.Example.register("F", self.ExampleD) 

277 self.assertEqual(len(self.Example), 1) 

278 

279 def testRegisterTemplateTwice(self): 

280 with self.assertRaises(ValueError): 

281 self.Example.register("F", self.ExampleF) 

282 self.Example.register("D", self.ExampleF) 

283 self.assertEqual(len(self.Example), 1) 

284 

285 

286class TemplateMetaHardTestCase(lsst.utils.tests.TestCase): 

287 """Test TemplateMeta with a mockup of a template with multiple 

288 template parameters. 

289 """ 

290 

291 def setUp(self): 

292 class Example(metaclass=lsst.utils.TemplateMeta): 

293 TEMPLATE_PARAMS = ("d", "u") 

294 TEMPLATE_DEFAULTS = (2, None) 

295 

296 class Example2F: 

297 pass 

298 

299 class Example2D: 

300 pass 

301 

302 class Example3F: 

303 pass 

304 

305 class Example3D: 

306 pass 

307 

308 self.Example = Example 

309 self.Example2F = Example2F 

310 self.Example2D = Example2D 

311 self.Example3F = Example3F 

312 self.Example3D = Example3D 

313 

314 def register(self): 

315 self.Example.register((2, np.float32), self.Example2F) 

316 self.Example.register((2, np.float64), self.Example2D) 

317 self.Example.register((3, np.float32), self.Example3F) 

318 self.Example.register((3, np.float64), self.Example3D) 

319 

320 def alias(self): 

321 self.Example.alias("2F", self.Example2F) 

322 self.Example.alias("2D", self.Example2D) 

323 self.Example.alias("3F", self.Example3F) 

324 self.Example.alias("3D", self.Example3D) 

325 

326 def testCorrectRegistration(self): 

327 self.register() 

328 self.assertEqual(self.Example2F.d, 2) 

329 self.assertEqual(self.Example2F.u, np.float32) 

330 self.assertEqual(self.Example2D.d, 2) 

331 self.assertEqual(self.Example2D.u, np.float64) 

332 self.assertEqual(self.Example3F.d, 3) 

333 self.assertEqual(self.Example3F.u, np.float32) 

334 self.assertEqual(self.Example3D.d, 3) 

335 self.assertEqual(self.Example3D.u, np.float64) 

336 self.assertIn((2, np.float32), self.Example) 

337 self.assertIn((2, np.float64), self.Example) 

338 self.assertIn((3, np.float32), self.Example) 

339 self.assertIn((3, np.float64), self.Example) 

340 self.assertEqual(self.Example[2, np.float32], self.Example2F) 

341 self.assertEqual(self.Example[2, np.float64], self.Example2D) 

342 self.assertEqual(self.Example[3, np.float32], self.Example3F) 

343 self.assertEqual(self.Example[3, np.float64], self.Example3D) 

344 

345 def testAliases(self): 

346 self.register() 

347 self.alias() 

348 self.assertEqual(self.Example2F.d, 2) 

349 self.assertEqual(self.Example2F.u, np.float32) 

350 self.assertEqual(self.Example2D.d, 2) 

351 self.assertEqual(self.Example2D.u, np.float64) 

352 self.assertEqual(self.Example3F.d, 3) 

353 self.assertEqual(self.Example3F.u, np.float32) 

354 self.assertEqual(self.Example3D.d, 3) 

355 self.assertEqual(self.Example3D.u, np.float64) 

356 self.assertIn("2F", self.Example) 

357 self.assertIn("2D", self.Example) 

358 self.assertIn("3F", self.Example) 

359 self.assertIn("3D", self.Example) 

360 self.assertEqual(self.Example["2F"], self.Example2F) 

361 self.assertEqual(self.Example["2D"], self.Example2D) 

362 self.assertEqual(self.Example["3F"], self.Example3F) 

363 self.assertEqual(self.Example["3D"], self.Example3D) 

364 

365 def testInheritanceHooks(self): 

366 self.register() 

367 self.assertTrue(issubclass(self.Example2F, self.Example)) 

368 self.assertTrue(issubclass(self.Example3D, self.Example)) 

369 f = self.Example2F() 

370 d = self.Example3D() 

371 self.assertIsInstance(f, self.Example) 

372 self.assertIsInstance(d, self.Example) 

373 self.assertEqual( 

374 set(self.Example.__subclasses__()), 

375 {self.Example2F, self.Example2D, self.Example3F, self.Example3D}, 

376 ) 

377 

378 def testConstruction(self): 

379 self.register() 

380 f = self.Example(u=np.float32) 

381 self.assertIsInstance(f, self.Example) 

382 self.assertIsInstance(f, self.Example2F) 

383 with self.assertRaises(TypeError): 

384 self.Example() 

385 with self.assertRaises(TypeError): 

386 self.Example(u=np.int32, d=1) 

387 

388 def testDictBehavior(self): 

389 self.register() 

390 self.assertIn((2, np.float32), self.Example) 

391 self.assertEqual(self.Example[2, np.float32], self.Example2F) 

392 self.assertEqual( 

393 set(self.Example.keys()), 

394 {(2, np.float32), (2, np.float64), (3, np.float32), (3, np.float64)}, 

395 ) 

396 self.assertEqual( 

397 set(self.Example.values()), {self.Example2F, self.Example2D, self.Example3F, self.Example3D} 

398 ) 

399 self.assertEqual( 

400 set(self.Example.items()), 

401 { 

402 ((2, np.float32), self.Example2F), 

403 ((2, np.float64), self.Example2D), 

404 ((3, np.float32), self.Example3F), 

405 ((3, np.float64), self.Example3D), 

406 }, 

407 ) 

408 self.assertEqual(len(self.Example), 4) 

409 self.assertEqual( 

410 set(iter(self.Example)), {(2, np.float32), (2, np.float64), (3, np.float32), (3, np.float64)} 

411 ) 

412 self.assertEqual(self.Example.get((3, np.float64)), self.Example3D) 

413 self.assertEqual(self.Example.get((2, np.int32), False), False) 

414 

415 def testRegisterBadKey(self): 

416 with self.assertRaises(ValueError): 

417 self.Example.register("F", self.Example2F) 

418 

419 def testRegisterDTypeTwice(self): 

420 with self.assertRaises(KeyError): 

421 self.Example.register((2, "F"), self.Example2F) 

422 self.Example.register((2, "F"), self.Example2D) 

423 self.assertEqual(len(self.Example), 1) 

424 

425 def testRegisterTemplateTwice(self): 

426 with self.assertRaises(ValueError): 

427 self.Example.register((2, "F"), self.Example2F) 

428 self.Example.register((2, "D"), self.Example2F) 

429 self.assertEqual(len(self.Example), 1) 

430 

431 

432class TestDefaultMethodCopying(lsst.utils.tests.TestCase): 

433 """Test to determine if static and class methods from a class which is 

434 registered as a default type in a type ABC are properly copied. 

435 """ 

436 

437 def setUp(self): 

438 class Example(metaclass=lsst.utils.TemplateMeta): 

439 TEMPLATE_PARAMS = ("dtype",) 

440 TEMPLATE_DEFAULTS = (np.float32,) 

441 

442 class ExampleF: 

443 @staticmethod 

444 def staticCall(): 

445 return 6 

446 

447 @classmethod 

448 def classCall(cls): 

449 return cls 

450 

451 def regularCall(self): 

452 return self 

453 

454 class ExampleI: 

455 @staticmethod 

456 def notTransferedStaticCall(): 

457 return 8 

458 

459 @classmethod 

460 def notTransferedClassCall(cls): 

461 return cls 

462 

463 # Add in a built in function to ExampleF to mimic how pybind11 treats 

464 # static methods from c++. 

465 ExampleF.pow = pow 

466 

467 Example.register(np.float32, ExampleF) 

468 Example.register(np.int32, ExampleI) 

469 self.Example = Example 

470 self.ExampleF = ExampleF 

471 self.ExampleI = ExampleI 

472 

473 def testMethodCopyForDefaultType(self): 

474 # Check that the methods for the default type were transfered and that 

475 # the regular method was not 

476 self.assertTrue(hasattr(self.Example, "staticCall")) 

477 self.assertTrue(hasattr(self.Example, "pow")) 

478 self.assertTrue(hasattr(self.Example, "classCall")) 

479 self.assertFalse(hasattr(self.Example, "regularCall")) 

480 

481 # Verify the default static and class method defaults return the 

482 # correct values 

483 self.assertEqual(self.Example.staticCall(), 6) 

484 self.assertEqual(self.Example.pow(2, 2), 4) 

485 self.assertIs(self.Example.classCall(), self.ExampleF) 

486 

487 # Verify static and class methods for non default keys are not 

488 # transfered 

489 self.assertFalse(hasattr(self.Example, "notTransferedStaticCall")) 

490 self.assertFalse(hasattr(self.Example, "notTransferedClassCall")) 

491 

492 

493if __name__ == "__main__": 

494 unittest.main()