Coverage for tests/test_defineVisits.py: 27%
77 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-06 02:49 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-06 02:49 -0700
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 def setUp(self):
41 """Create a new butler for each test since we are changing dimension
42 records."""
43 self.root = tempfile.mkdtemp(dir=TESTDIR)
44 self.creatorButler = butlerTests.makeTestRepo(self.root, [])
45 self.butler = butlerTests.makeTestCollection(self.creatorButler)
47 self.config = DefineVisitsTask.ConfigClass()
48 self.task = DefineVisitsTask(config=self.config, butler=self.butler)
50 # Need to register the instrument.
51 DummyCam().register(self.butler.registry)
53 # Read the exposure records.
54 self.records: dict[int, DimensionRecord] = {}
55 for i in (347, 348, 349):
56 simple = SerializedDimensionRecord.parse_file(os.path.join(DATADIR, f"exp_{i}.json"))
57 self.records[i] = DimensionRecord.from_simple(simple, registry=self.butler.registry)
59 def tearDown(self):
60 if self.root is not None:
61 shutil.rmtree(self.root, ignore_errors=True)
63 def assertVisits(self):
64 """Check that the visits were registered as expected."""
65 visits = list(self.butler.registry.queryDimensionRecords("visit"))
66 self.assertEqual(len(visits), 4)
67 self.assertEqual(
68 {visit.id for visit in visits}, {2022040500347, 2022040500348, 2022040500349, 92022040500348}
69 )
71 # Ensure that the definitions are correct (ignoring order).
72 defmap = defaultdict(set)
73 definitions = list(self.butler.registry.queryDimensionRecords("visit_definition"))
74 for defn in definitions:
75 defmap[defn.visit].add(defn.exposure)
77 self.assertEqual(
78 dict(defmap),
79 {
80 92022040500348: {2022040500348},
81 2022040500347: {2022040500347},
82 2022040500348: {2022040500348, 2022040500349},
83 2022040500349: {2022040500349},
84 },
85 )
87 def define_visits(
88 self, exposures: list[DimensionRecord | list[DimensionRecord]], incremental: bool
89 ) -> None:
90 for records in exposures:
91 self.butler.registry.insertDimensionData("exposure", *ensure_iterable(records))
92 # Include all records so far in definition.
93 dataIds = [d for d in self.butler.registry.queryDataIds("exposure", instrument="DummyCam")]
94 self.task.run(dataIds, incremental=incremental)
96 def test_defineVisits(self):
97 # Test visit definition with all the records.
98 self.define_visits([[r for r in self.records.values()]], incremental=False) # list inside a list
99 self.assertVisits()
101 def test_incremental_cumulative(self):
102 # Define the visits after each exposure.
103 self.define_visits([exp for exp in self.records.values()], incremental=True)
104 self.assertVisits()
106 def test_incremental_cumulative_reverse(self):
107 # In reverse order we should still eventually end up with the right
108 # answer.
109 with self.assertLogs("lsst.defineVisits.groupExposures", level="WARNING") as cm:
110 self.define_visits(list(reversed(self.records.values())), incremental=True)
111 self.assertIn("Skipping the multi-snap definition", "\n".join(cm.output))
112 self.assertVisits()
114 def define_visits_incrementally(self, exposure: DimensionRecord) -> None:
115 self.butler.registry.insertDimensionData("exposure", exposure)
116 dataIds = [
117 DataCoordinate.standardize(
118 instrument="DummyCam", exposure=exposure.id, universe=self.butler.registry.dimensions
119 )
120 ]
121 self.task.run(dataIds, incremental=True)
123 def test_incremental(self):
124 for record in self.records.values():
125 self.define_visits_incrementally(record)
126 self.assertVisits()
128 def test_incremental_reverse(self):
129 for record in reversed(self.records.values()):
130 self.define_visits_incrementally(record)
131 self.assertVisits()
133 def testPickleTask(self):
134 stream = pickle.dumps(self.task)
135 copy = pickle.loads(stream)
136 self.assertEqual(self.task.getFullName(), copy.getFullName())
137 self.assertEqual(self.task.log.name, copy.log.name)
138 self.assertEqual(self.task.config, copy.config)
139 self.assertEqual(self.task.butler._config, copy.butler._config)
140 self.assertEqual(self.task.butler.collections, copy.butler.collections)
141 self.assertEqual(self.task.butler.run, copy.butler.run)
142 self.assertEqual(self.task.universe, copy.universe)
145if __name__ == "__main__": 145 ↛ 146line 145 didn't jump to line 146, because the condition on line 145 was never true
146 unittest.main()