Coverage for tests/test_Storable.py : 39%

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# This file is part of afw.
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/>.
22from __future__ import annotations
24from dataclasses import dataclass, asdict
25import copy
26import gc
27import unittest
28import yaml
30import lsst.utils.tests
32from lsst.afw.typehandling import Storable, StorableHelperFactory
33import testGenericMapLib as cppLib
34from lsst.afw.image import ExposureF, ExposureFitsReader
37class DemoStorable(Storable):
38 """Test that we can inherit from Storable in Python.
39 """
41 def __init__(self, state):
42 super().__init__()
43 self._state = state
45 def __str__(self):
46 return f"value = {self._state}"
48 def __repr__(self):
49 return f"DemoStorable({self._state!r})"
51 def __hash__(self):
52 return hash(self._state)
54 def __copy__(self):
55 return DemoStorable(self._state)
57 def __deepcopy__(self, memo=None):
58 return DemoStorable(copy.deepcopy(self._state, memo))
60 def __eq__(self, other):
61 return self._state == other._state
64class SpecializedStorable(cppLib.CppStorable):
65 """Test that we can inherit from C++ subclasses of Storable that
66 are not Storable itself.
67 """
69 def __repr__(self):
70 return "Pythonic " + super().__repr__()
73class PythonStorableTestSuite(lsst.utils.tests.TestCase):
75 def setUp(self):
76 self.aList = [42]
77 self.testbed = DemoStorable(self.aList)
79 def testCopy(self):
80 shallow = copy.copy(self.testbed)
81 self.assertIsNot(shallow, self.testbed)
82 self.assertEqual(shallow, self.testbed)
84 deep = copy.deepcopy(self.testbed)
85 self.assertIsNot(deep, self.testbed)
86 self.assertEqual(deep, self.testbed)
88 cpp = cppLib.duplicate(self.testbed)
89 self.assertIsInstance(cpp, Storable)
90 self.assertIsInstance(cpp, DemoStorable)
91 self.assertIsNot(cpp, self.testbed)
92 self.assertEqual(cpp, self.testbed)
94 self.aList.append(43)
95 self.assertEqual(shallow, DemoStorable([42, 43]))
96 self.assertEqual(deep, DemoStorable([42]))
97 self.assertEqual(cpp, DemoStorable([42]))
99 def testStr(self):
100 self.assertEqual(str(self.testbed), "value = [42]")
102 def testRepr(self):
103 self.assertEqual(repr(self.testbed), "DemoStorable([42])")
104 cppLib.assertPythonStorable(self.testbed, "DemoStorable([42])")
106 def testHash(self):
107 with self.assertRaises(TypeError):
108 hash(self.testbed)
110 def testEq(self):
111 self.assertEqual(self.testbed, DemoStorable([42]))
112 self.assertNotEqual(self.testbed, DemoStorable(0))
114 def testGarbageCollection(self):
115 cppLib.keepStaticStorable(DemoStorable(3))
117 gc.collect()
119 retrieved = cppLib.keepStaticStorable()
120 self.assertIsInstance(retrieved, Storable)
121 self.assertIsInstance(retrieved, DemoStorable)
122 self.assertEqual(retrieved, DemoStorable(3))
124 def testInheritedGarbageCollection(self):
125 cppLib.keepStaticStorable(SpecializedStorable("Foo"))
127 gc.collect()
129 retrieved = cppLib.keepStaticStorable()
130 self.assertIsInstance(retrieved, Storable)
131 self.assertIsInstance(retrieved, cppLib.CppStorable)
132 self.assertIsInstance(retrieved, SpecializedStorable)
133 self.assertEqual(repr(retrieved), "Pythonic Foo")
134 cppLib.assertPythonStorable(retrieved, "Pythonic Foo")
137class CppStorableTestSuite(lsst.utils.tests.TestCase):
139 def setUp(self):
140 self.initstr = "Just a string"
141 self.testbed = cppLib.CppStorable(self.initstr)
143 def testNewValue(self):
144 """Test a Python-side state change in both C++ and Python.
145 """
146 self.assertEqual(self.testbed.value, self.initstr)
147 cppLib.assertCppValue(self.testbed, self.initstr)
149 newstr = "Stringly typed"
150 self.testbed.value = newstr
152 self.assertEqual(self.testbed.value, newstr)
153 cppLib.assertCppValue(self.testbed, newstr)
156@dataclass
157class Blob(Storable):
158 _factory = StorableHelperFactory(__name__, "Blob")
160 an_int: int
161 a_float: float
163 def __post_init__(self):
164 Storable.__init__(self) # required for trampoline
166 def isPersistable(self):
167 return True
169 def _getPersistenceName(self):
170 return "Blob"
172 def _getPythonModule(self):
173 return __name__
175 def _write(self):
176 return yaml.dump(asdict(self), encoding='utf-8')
178 @staticmethod
179 def _read(bytes):
180 return Blob(**yaml.load(bytes, Loader=yaml.SafeLoader))
183class ExposureStorableBlobTestSuite(lsst.utils.tests.TestCase):
184 def setUp(self):
185 self.blob = Blob(1, 2.0)
187 def testClone(self):
188 """Test copying an exposure with an attached Blob.
189 """
190 im = ExposureF(10, 10)
191 # Extra components must be ALL CAPS for fits storage.
192 im.getInfo().setComponent("BLOB", self.blob)
194 im2 = im.clone()
195 im3 = copy.deepcopy(im)
196 im4 = ExposureF(im, deep=False)
197 im5 = ExposureF(im, deep=True)
199 for i in [im2, im3, im4, im5]:
200 self.assertEqual(i.getInfo().getComponent("BLOB"), self.blob)
202 def testPersistence(self):
203 """Test persisting an exposure with an attached Blob.
204 """
205 im = ExposureF(10, 10)
206 # Extra components must be ALL CAPS for fits storage.
207 im.getInfo().setComponent("BLOB", self.blob)
208 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
209 im.writeFits(tmpFile)
211 newIm = ExposureF(tmpFile)
212 self.assertEqual(newIm.getInfo().getComponent("BLOB"), self.blob)
214 reader = ExposureFitsReader(tmpFile)
215 newBlob = reader.readComponent("BLOB")
216 self.assertEqual(newBlob, self.blob)
219class MemoryTester(lsst.utils.tests.MemoryTestCase):
220 pass
223def setup_module(module):
224 lsst.utils.tests.init()
227if __name__ == "__main__": 227 ↛ 228line 227 didn't jump to line 228, because the condition on line 227 was never true
228 lsst.utils.tests.init()
229 unittest.main()