Coverage for tests/test_packages.py: 13%

93 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-02-14 01:59 -0800

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# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11# 

12 

13import os 

14import unittest 

15from collections.abc import Mapping 

16 

17import lsst.utils.packages 

18import lsst.utils.tests 

19 

20TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

21 

22 

23class PackagesTestCase(unittest.TestCase): 

24 """Tests for package version collection 

25 

26 Unfortunately, we're somewhat limited in what we can test because 

27 we only get the versions of things being used at runtime, and this 

28 package sits rather low in the dependency chain so there's not 

29 usually a lot of other packages available when this test gets run. 

30 Therefore some of the tests are only checking that things don't 

31 explode, since they are incapable of testing much more than that. 

32 """ 

33 

34 def testPython(self): 

35 """Test that we get the right version for this python package""" 

36 versions = lsst.utils.packages.getPythonPackages() 

37 expected = lsst.utils.version.__version__ 

38 self.assertEqual(versions["utils"], expected) 

39 

40 def testEnvironment(self): 

41 """Test getting versions from the environment 

42 

43 Unfortunately, none of the products that need their versions divined 

44 from the environment are dependencies of this package, and so all we 

45 can do is test that this doesn't fall over. 

46 """ 

47 lsst.utils.packages.getEnvironmentPackages() 

48 

49 def testConda(self): 

50 """Test getting versions from conda environement 

51 

52 We do not rely on being run in a conda environment so all we can do is 

53 test that this doesn't fall over. 

54 """ 

55 lsst.utils.packages.getCondaPackages() 

56 

57 def _writeTempFile(self, packages, suffix): 

58 """Write packages to a temp file using the supplied suffix and read 

59 back. 

60 """ 

61 with lsst.utils.tests.getTempFilePath(suffix) as tempName: 

62 packages.write(tempName) 

63 new = lsst.utils.packages.Packages.read(tempName) 

64 return new 

65 

66 def testPackages(self): 

67 """Test the Packages class""" 

68 packages = lsst.utils.packages.Packages.fromSystem() 

69 self.assertIsInstance(packages, Mapping) 

70 

71 # Check that stringification is not crashing. 

72 self.assertTrue(str(packages).startswith("Packages({")) 

73 self.assertTrue(repr(packages).startswith("Packages({")) 

74 

75 # Test pickling and YAML 

76 new = self._writeTempFile(packages, ".pickle") 

77 new_pkl = self._writeTempFile(packages, ".pkl") 

78 new_yaml = self._writeTempFile(packages, ".yaml") 

79 new_json = self._writeTempFile(packages, ".json") 

80 

81 self.assertIsInstance(new, lsst.utils.packages.Packages, f"Checking type ({type(new)}) from pickle") 

82 self.assertIsInstance( 

83 new_yaml, lsst.utils.packages.Packages, f"Checking type ({type(new_yaml)}) from YAML" 

84 ) 

85 self.assertEqual(new, packages) 

86 self.assertEqual(new_pkl, new) 

87 self.assertEqual(new, new_yaml) 

88 self.assertEqual(new, new_json) 

89 

90 # Dict compatibility. 

91 for k, v in new.items(): 

92 self.assertEqual(new[k], v) 

93 

94 with self.assertRaises(ValueError): 

95 self._writeTempFile(packages, ".txt") 

96 

97 with self.assertRaises(ValueError): 

98 # .txt extension is not recognized 

99 lsst.utils.packages.Packages.read("something.txt") 

100 

101 # 'packages' and 'new' should have identical content 

102 self.assertDictEqual(packages.difference(new), {}) 

103 self.assertDictEqual(packages.missing(new), {}) 

104 self.assertDictEqual(packages.extra(new), {}) 

105 self.assertEqual(len(packages), len(new)) 

106 

107 # Check inverted comparisons 

108 self.assertDictEqual(new.difference(packages), {}) 

109 self.assertDictEqual(new.missing(packages), {}) 

110 self.assertDictEqual(new.extra(packages), {}) 

111 

112 # Now load an obscure python package and the list of packages should 

113 # change 

114 # Shouldn't be used by anything we've previously imported 

115 import smtpd # noqa: F401 

116 

117 new = lsst.utils.packages.Packages.fromSystem() 

118 self.assertDictEqual(packages.difference(new), {}) # No inconsistencies 

119 self.assertDictEqual(packages.extra(new), {}) # Nothing in 'packages' that's not in 'new' 

120 missing = packages.missing(new) 

121 self.assertGreater(len(missing), 0) # 'packages' should be missing some stuff in 'new' 

122 self.assertIn("smtpd", missing) 

123 

124 # Inverted comparisons 

125 self.assertDictEqual(new.difference(packages), {}) 

126 self.assertDictEqual(new.missing(packages), {}) # Nothing in 'new' that's not in 'packages' 

127 extra = new.extra(packages) 

128 self.assertGreater(len(extra), 0) # 'new' has extra stuff compared to 'packages' 

129 self.assertIn("smtpd", extra) 

130 self.assertIn("smtpd", new) 

131 

132 # Run with both a Packages and a dict 

133 for new_pkg in (new, dict(new)): 

134 packages.update(new_pkg) # Should now be identical 

135 self.assertDictEqual(packages.difference(new_pkg), {}) 

136 self.assertDictEqual(packages.missing(new_pkg), {}) 

137 self.assertDictEqual(packages.extra(new_pkg), {}) 

138 self.assertEqual(len(packages), len(new_pkg)) 

139 

140 # Loop over keys to check iterator. 

141 keys = {k for k in new} 

142 self.assertEqual(keys, set(dict(new).keys())) 

143 

144 # Loop over values to check that we do get them all. 

145 values = {v for v in new.values()} 

146 self.assertEqual(values, set(dict(new).values())) 

147 

148 # Serialize via bytes 

149 for format in ("pickle", "yaml", "json"): 

150 asbytes = new.toBytes(format) 

151 from_bytes = lsst.utils.packages.Packages.fromBytes(asbytes, format) 

152 self.assertEqual(from_bytes, new) 

153 

154 with self.assertRaises(ValueError): 

155 new.toBytes("unknown_format") 

156 

157 with self.assertRaises(ValueError): 

158 lsst.utils.packages.Packages.fromBytes(from_bytes, "unknown_format") 

159 

160 with self.assertRaises(TypeError): 

161 some_yaml = b"list: [1, 2]" 

162 lsst.utils.packages.Packages.fromBytes(some_yaml, "yaml") 

163 

164 def testBackwardsCompatibility(self): 

165 """Test if we can read old data files.""" 

166 

167 # Pickle contents changed when moving to dict base class. 

168 packages_p = lsst.utils.packages.Packages.read(os.path.join(TESTDIR, "data", "v1.pickle")) 

169 self.assertIsInstance(packages_p, lsst.utils.packages.Packages) 

170 

171 # YAML format is unchanged when moving from special class to dict 

172 # but test anyway. 

173 packages_y = lsst.utils.packages.Packages.read(os.path.join(TESTDIR, "data", "v1.yaml")) 

174 

175 self.assertEqual(packages_p, packages_y) 

176 

177 # Now check that we can read the version 2 files that were 

178 # written with Packages inheriting from dict but still in `base`. 

179 packages_p2 = lsst.utils.packages.Packages.read(os.path.join(TESTDIR, "data", "v2.pickle")) 

180 packages_y2 = lsst.utils.packages.Packages.read(os.path.join(TESTDIR, "data", "v2.yaml")) 

181 self.assertEqual(packages_p2, packages_y2) 

182 self.assertIsInstance(packages_p2, lsst.utils.packages.Packages) 

183 

184 

185if __name__ == "__main__": 185 ↛ 186line 185 didn't jump to line 186, because the condition on line 185 was never true

186 unittest.main()