Coverage for tests/test_defineVisits.py: 28%
77 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-27 09:12 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-27 09:12 +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/>.
22import os
23import pickle
24import shutil
25import tempfile
26import unittest
27from collections import defaultdict
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
35TESTDIR = os.path.dirname(__file__)
36DATADIR = os.path.join(TESTDIR, "data", "visits")
39class DefineVisitsTestCase(unittest.TestCase):
40 """Test visit definition."""
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)
50 self.config = DefineVisitsTask.ConfigClass()
51 self.task = DefineVisitsTask(config=self.config, butler=self.butler)
53 # Need to register the instrument.
54 DummyCam().register(self.butler.registry)
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)
62 def tearDown(self):
63 if self.root is not None:
64 shutil.rmtree(self.root, ignore_errors=True)
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 )
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)
80 self.assertEqual(
81 dict(defmap),
82 {
83 92022040500348: {2022040500348},
84 2022040500347: {2022040500347},
85 2022040500348: {2022040500348, 2022040500349},
86 2022040500349: {2022040500349},
87 },
88 )
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)
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()
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()
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()
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)
126 def test_incremental(self):
127 for record in self.records.values():
128 self.define_visits_incrementally(record)
129 self.assertVisits()
131 def test_incremental_reverse(self):
132 for record in reversed(self.records.values()):
133 self.define_visits_incrementally(record)
134 self.assertVisits()
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)
148if __name__ == "__main__": 148 ↛ 149line 148 didn't jump to line 149, because the condition on line 148 was never true
149 unittest.main()