Coverage for tests/test_wrappers.py: 12%
348 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-05-01 15:14 -0700
« prev ^ index » next coverage.py v7.5.0, created at 2024-05-01 15:14 -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/>.
22import unittest
24import lsst.utils
25import lsst.utils.tests
26import numpy as np
29class MockClass: # continued class needs to be at module scope
30 """A test class that can be continued."""
32 def method1(self):
33 return self
35 @classmethod
36 def method2(cls):
37 return cls
39 @staticmethod
40 def method3():
41 return True
43 @property
44 def property1(self):
45 return False
48class DecoratorsTestCase(lsst.utils.tests.TestCase):
49 """Test the decorators."""
51 def setUp(self):
52 @lsst.utils.continueClass
53 class MockClass:
54 def method1a(self):
55 return self
57 @classmethod
58 def method2a(cls):
59 return cls
61 @staticmethod
62 def method3a():
63 return True
65 @property
66 def property1a(self):
67 return False
69 @lsst.utils.inClass(MockClass)
70 def method1b(self):
71 return self
73 @lsst.utils.inClass(MockClass)
74 @classmethod
75 def method2b(cls):
76 return cls
78 @lsst.utils.inClass(MockClass)
79 @staticmethod
80 def method3b():
81 return True
83 @lsst.utils.inClass(MockClass)
84 @property
85 def property1b(self):
86 return False
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)
110class TemplateMetaSimpleTestCase(lsst.utils.tests.TestCase):
111 """Test TemplateMeta on a mockup of a template with a single dtype
112 template parameter.
113 """
115 def setUp(self):
116 class Example(metaclass=lsst.utils.TemplateMeta):
117 def method1(self):
118 return self
120 @classmethod
121 def method2(cls):
122 return cls
124 @staticmethod
125 def method3():
126 return True
128 @property
129 def property1(self):
130 return False
132 class ExampleF:
133 pass
135 class ExampleD:
136 pass
138 self.Example = Example
139 self.ExampleF = ExampleF
140 self.ExampleD = ExampleD
142 def register(self):
143 self.Example.register(np.float32, self.ExampleF)
144 self.Example.register(np.float64, self.ExampleD)
146 def alias(self):
147 self.Example.alias("F", self.ExampleF)
148 self.Example.alias("D", self.ExampleD)
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)
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])
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})
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
187 class Example2(metaclass=lsst.utils.TemplateMeta):
188 # A new independent class.
189 pass
191 class Example2I:
192 # Something that will be registered in independent hierarchy.
193 pass
195 Example2.register(np.int32, Example2I)
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))
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)
213 with self.assertRaises(TypeError):
214 self.Example()
215 with self.assertRaises(TypeError):
216 self.Example(dtype=np.int32)
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)
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)
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
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)
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)
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)
286class TemplateMetaHardTestCase(lsst.utils.tests.TestCase):
287 """Test TemplateMeta with a mockup of a template with multiple
288 template parameters.
289 """
291 def setUp(self):
292 class Example(metaclass=lsst.utils.TemplateMeta):
293 TEMPLATE_PARAMS = ("d", "u")
294 TEMPLATE_DEFAULTS = (2, None)
296 class Example2F:
297 pass
299 class Example2D:
300 pass
302 class Example3F:
303 pass
305 class Example3D:
306 pass
308 self.Example = Example
309 self.Example2F = Example2F
310 self.Example2D = Example2D
311 self.Example3F = Example3F
312 self.Example3D = Example3D
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)
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)
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)
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)
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 )
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)
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)
415 def testRegisterBadKey(self):
416 with self.assertRaises(ValueError):
417 self.Example.register("F", self.Example2F)
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)
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)
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 """
437 def setUp(self):
438 class Example(metaclass=lsst.utils.TemplateMeta):
439 TEMPLATE_PARAMS = ("dtype",)
440 TEMPLATE_DEFAULTS = (np.float32,)
442 class ExampleF:
443 @staticmethod
444 def staticCall():
445 return 6
447 @classmethod
448 def classCall(cls):
449 return cls
451 def regularCall(self):
452 return self
454 class ExampleI:
455 @staticmethod
456 def notTransferedStaticCall():
457 return 8
459 @classmethod
460 def notTransferedClassCall(cls):
461 return cls
463 # Add in a built in function to ExampleF to mimic how pybind11 treats
464 # static methods from c++.
465 ExampleF.pow = pow
467 Example.register(np.float32, ExampleF)
468 Example.register(np.int32, ExampleI)
469 self.Example = Example
470 self.ExampleF = ExampleF
471 self.ExampleI = ExampleI
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"))
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)
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"))
493if __name__ == "__main__":
494 unittest.main()