Coverage for tests/test_defineVisits.py: 28%

77 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-30 12:18 +0000

1# This file is part of obs_base. 

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 <http://www.gnu.org/licenses/>. 

21 

22import os 

23import pickle 

24import shutil 

25import tempfile 

26import unittest 

27from collections import defaultdict 

28 

29import lsst.daf.butler.tests as butlerTests 

30from lsst.daf.butler import DataCoordinate, DimensionRecord, SerializedDimensionRecord 

31from lsst.obs.base import DefineVisitsTask 

32from lsst.obs.base.instrument_tests import DummyCam 

33from lsst.utils.iteration import ensure_iterable 

34 

35TESTDIR = os.path.dirname(__file__) 

36DATADIR = os.path.join(TESTDIR, "data", "visits") 

37 

38 

39class DefineVisitsTestCase(unittest.TestCase): 

40 """Test visit definition.""" 

41 

42 def setUp(self): 

43 """Create a new butler for each test since we are changing dimension 

44 records. 

45 """ 

46 self.root = tempfile.mkdtemp(dir=TESTDIR) 

47 self.creatorButler = butlerTests.makeTestRepo(self.root, []) 

48 self.butler = butlerTests.makeTestCollection(self.creatorButler, uniqueId=self.id()) 

49 

50 self.config = DefineVisitsTask.ConfigClass() 

51 self.task = DefineVisitsTask(config=self.config, butler=self.butler) 

52 

53 # Need to register the instrument. 

54 DummyCam().register(self.butler.registry) 

55 

56 # Read the exposure records. 

57 self.records: dict[int, DimensionRecord] = {} 

58 for i in (347, 348, 349): 

59 simple = SerializedDimensionRecord.parse_file(os.path.join(DATADIR, f"exp_{i}.json")) 

60 self.records[i] = DimensionRecord.from_simple(simple, registry=self.butler.registry) 

61 

62 def tearDown(self): 

63 if self.root is not None: 

64 shutil.rmtree(self.root, ignore_errors=True) 

65 

66 def assertVisits(self): 

67 """Check that the visits were registered as expected.""" 

68 visits = list(self.butler.registry.queryDimensionRecords("visit")) 

69 self.assertEqual(len(visits), 4) 

70 self.assertEqual( 

71 {visit.id for visit in visits}, {2022040500347, 2022040500348, 2022040500349, 92022040500348} 

72 ) 

73 

74 # Ensure that the definitions are correct (ignoring order). 

75 defmap = defaultdict(set) 

76 definitions = list(self.butler.registry.queryDimensionRecords("visit_definition")) 

77 for defn in definitions: 

78 defmap[defn.visit].add(defn.exposure) 

79 

80 self.assertEqual( 

81 dict(defmap), 

82 { 

83 92022040500348: {2022040500348}, 

84 2022040500347: {2022040500347}, 

85 2022040500348: {2022040500348, 2022040500349}, 

86 2022040500349: {2022040500349}, 

87 }, 

88 ) 

89 

90 def define_visits( 

91 self, exposures: list[DimensionRecord | list[DimensionRecord]], incremental: bool 

92 ) -> None: 

93 for records in exposures: 

94 self.butler.registry.insertDimensionData("exposure", *ensure_iterable(records)) 

95 # Include all records so far in definition. 

96 dataIds = list(self.butler.registry.queryDataIds("exposure", instrument="DummyCam")) 

97 self.task.run(dataIds, incremental=incremental) 

98 

99 def test_defineVisits(self): 

100 # Test visit definition with all the records. 

101 self.define_visits([list(self.records.values())], incremental=False) # list inside a list 

102 self.assertVisits() 

103 

104 def test_incremental_cumulative(self): 

105 # Define the visits after each exposure. 

106 self.define_visits(list(self.records.values()), incremental=True) 

107 self.assertVisits() 

108 

109 def test_incremental_cumulative_reverse(self): 

110 # In reverse order we should still eventually end up with the right 

111 # answer. 

112 with self.assertLogs("lsst.defineVisits.groupExposures", level="WARNING") as cm: 

113 self.define_visits(list(reversed(self.records.values())), incremental=True) 

114 self.assertIn("Skipping the multi-snap definition", "\n".join(cm.output)) 

115 self.assertVisits() 

116 

117 def define_visits_incrementally(self, exposure: DimensionRecord) -> None: 

118 self.butler.registry.insertDimensionData("exposure", exposure) 

119 dataIds = [ 

120 DataCoordinate.standardize( 

121 instrument="DummyCam", exposure=exposure.id, universe=self.butler.dimensions 

122 ) 

123 ] 

124 self.task.run(dataIds, incremental=True) 

125 

126 def test_incremental(self): 

127 for record in self.records.values(): 

128 self.define_visits_incrementally(record) 

129 self.assertVisits() 

130 

131 def test_incremental_reverse(self): 

132 for record in reversed(self.records.values()): 

133 self.define_visits_incrementally(record) 

134 self.assertVisits() 

135 

136 def testPickleTask(self): 

137 stream = pickle.dumps(self.task) 

138 copy = pickle.loads(stream) 

139 self.assertEqual(self.task.getFullName(), copy.getFullName()) 

140 self.assertEqual(self.task.log.name, copy.log.name) 

141 self.assertEqual(self.task.config, copy.config) 

142 self.assertEqual(self.task.butler._config, copy.butler._config) 

143 self.assertEqual(self.task.butler.collections, copy.butler.collections) 

144 self.assertEqual(self.task.butler.run, copy.butler.run) 

145 self.assertEqual(self.task.universe, copy.universe) 

146 

147 

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

149 unittest.main()