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# 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/>. 

21 

22from __future__ import annotations 

23 

24from dataclasses import dataclass, asdict 

25import copy 

26import gc 

27import unittest 

28import yaml 

29 

30import lsst.utils.tests 

31 

32from lsst.afw.typehandling import Storable, StorableHelperFactory 

33import testGenericMapLib as cppLib 

34from lsst.afw.image import ExposureF, ExposureFitsReader 

35 

36 

37class DemoStorable(Storable): 

38 """Test that we can inherit from Storable in Python. 

39 """ 

40 

41 def __init__(self, state): 

42 super().__init__() 

43 self._state = state 

44 

45 def __str__(self): 

46 return f"value = {self._state}" 

47 

48 def __repr__(self): 

49 return f"DemoStorable({self._state!r})" 

50 

51 def __hash__(self): 

52 return hash(self._state) 

53 

54 def __copy__(self): 

55 return DemoStorable(self._state) 

56 

57 def __deepcopy__(self, memo=None): 

58 return DemoStorable(copy.deepcopy(self._state, memo)) 

59 

60 def __eq__(self, other): 

61 return self._state == other._state 

62 

63 

64class SpecializedStorable(cppLib.CppStorable): 

65 """Test that we can inherit from C++ subclasses of Storable that 

66 are not Storable itself. 

67 """ 

68 

69 def __repr__(self): 

70 return "Pythonic " + super().__repr__() 

71 

72 

73class PythonStorableTestSuite(lsst.utils.tests.TestCase): 

74 

75 def setUp(self): 

76 self.aList = [42] 

77 self.testbed = DemoStorable(self.aList) 

78 

79 def testCopy(self): 

80 shallow = copy.copy(self.testbed) 

81 self.assertIsNot(shallow, self.testbed) 

82 self.assertEqual(shallow, self.testbed) 

83 

84 deep = copy.deepcopy(self.testbed) 

85 self.assertIsNot(deep, self.testbed) 

86 self.assertEqual(deep, self.testbed) 

87 

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) 

93 

94 self.aList.append(43) 

95 self.assertEqual(shallow, DemoStorable([42, 43])) 

96 self.assertEqual(deep, DemoStorable([42])) 

97 self.assertEqual(cpp, DemoStorable([42])) 

98 

99 def testStr(self): 

100 self.assertEqual(str(self.testbed), "value = [42]") 

101 

102 def testRepr(self): 

103 self.assertEqual(repr(self.testbed), "DemoStorable([42])") 

104 cppLib.assertPythonStorable(self.testbed, "DemoStorable([42])") 

105 

106 def testHash(self): 

107 with self.assertRaises(TypeError): 

108 hash(self.testbed) 

109 

110 def testEq(self): 

111 self.assertEqual(self.testbed, DemoStorable([42])) 

112 self.assertNotEqual(self.testbed, DemoStorable(0)) 

113 

114 def testGarbageCollection(self): 

115 cppLib.keepStaticStorable(DemoStorable(3)) 

116 

117 gc.collect() 

118 

119 retrieved = cppLib.keepStaticStorable() 

120 self.assertIsInstance(retrieved, Storable) 

121 self.assertIsInstance(retrieved, DemoStorable) 

122 self.assertEqual(retrieved, DemoStorable(3)) 

123 

124 def testInheritedGarbageCollection(self): 

125 cppLib.keepStaticStorable(SpecializedStorable("Foo")) 

126 

127 gc.collect() 

128 

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

135 

136 

137class CppStorableTestSuite(lsst.utils.tests.TestCase): 

138 

139 def setUp(self): 

140 self.initstr = "Just a string" 

141 self.testbed = cppLib.CppStorable(self.initstr) 

142 

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) 

148 

149 newstr = "Stringly typed" 

150 self.testbed.value = newstr 

151 

152 self.assertEqual(self.testbed.value, newstr) 

153 cppLib.assertCppValue(self.testbed, newstr) 

154 

155 

156@dataclass 

157class Blob(Storable): 

158 _factory = StorableHelperFactory(__name__, "Blob") 

159 

160 an_int: int 

161 a_float: float 

162 

163 def __post_init__(self): 

164 Storable.__init__(self) # required for trampoline 

165 

166 def isPersistable(self): 

167 return True 

168 

169 def _getPersistenceName(self): 

170 return "Blob" 

171 

172 def _getPythonModule(self): 

173 return __name__ 

174 

175 def _write(self): 

176 return yaml.dump(asdict(self), encoding='utf-8') 

177 

178 @staticmethod 

179 def _read(bytes): 

180 return Blob(**yaml.load(bytes, Loader=yaml.SafeLoader)) 

181 

182 

183class ExposureStorableBlobTestSuite(lsst.utils.tests.TestCase): 

184 def setUp(self): 

185 self.blob = Blob(1, 2.0) 

186 

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) 

193 

194 im2 = im.clone() 

195 im3 = copy.deepcopy(im) 

196 im4 = ExposureF(im, deep=False) 

197 im5 = ExposureF(im, deep=True) 

198 

199 for i in [im2, im3, im4, im5]: 

200 self.assertEqual(i.getInfo().getComponent("BLOB"), self.blob) 

201 

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) 

210 

211 newIm = ExposureF(tmpFile) 

212 self.assertEqual(newIm.getInfo().getComponent("BLOB"), self.blob) 

213 

214 reader = ExposureFitsReader(tmpFile) 

215 newBlob = reader.readComponent("BLOB") 

216 self.assertEqual(newBlob, self.blob) 

217 

218 

219class MemoryTester(lsst.utils.tests.MemoryTestCase): 

220 pass 

221 

222 

223def setup_module(module): 

224 lsst.utils.tests.init() 

225 

226 

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