Coverage for tests/test_dimensions.py : 13%

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 daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://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 unittest
23import copy
24import pickle
25import itertools
27from lsst.daf.butler.core.utils import NamedKeyDict
28from lsst.daf.butler.core.dimensions import DimensionUniverse, DimensionGraph, Dimension
29from lsst.daf.butler.core.dimensions.schema import makeElementTableSpec
32class DimensionTestCase(unittest.TestCase):
33 """Tests for dimensions.
35 All tests here rely on the content of ``config/dimensions.yaml``, either
36 to test that the definitions there are read in properly or just as generic
37 data for testing various operations.
38 """
40 def setUp(self):
41 self.universe = DimensionUniverse()
43 def checkGraphInvariants(self, graph):
44 elements = list(graph.elements)
45 for n, element in enumerate(elements):
46 # Ordered comparisons on graphs behave like sets.
47 self.assertLessEqual(element.graph, graph)
48 # Ordered comparisons on elements correspond to the ordering within
49 # a DimensionUniverse (topological, with deterministic
50 # tiebreakers).
51 for other in elements[:n]:
52 self.assertLess(other, element)
53 self.assertLessEqual(other, element)
54 for other in elements[n + 1:]:
55 self.assertGreater(other, element)
56 self.assertGreaterEqual(other, element)
57 self.assertEqual(DimensionGraph(self.universe, graph.required), graph)
58 self.assertCountEqual(graph.required,
59 [dimension for dimension in graph.dimensions
60 if not any(dimension in other.graph.implied for other in graph.elements)])
61 self.assertCountEqual(graph.implied, graph.dimensions - graph.required)
62 self.assertCountEqual(graph.dimensions,
63 [element for element in graph.elements
64 if isinstance(element, Dimension)])
65 self.assertCountEqual(graph.dimensions, itertools.chain(graph.required, graph.implied))
67 def testConfigRead(self):
68 self.assertEqual(self.universe.dimensions.names,
69 {"instrument", "visit", "exposure", "detector", "physical_filter",
70 "abstract_filter", "subfilter", "calibration_label",
71 "skymap", "tract", "patch", "htm7", "htm9"})
73 def testGraphs(self):
74 self.checkGraphInvariants(self.universe.empty)
75 self.checkGraphInvariants(self.universe)
76 for element in self.universe.elements:
77 self.checkGraphInvariants(element.graph)
79 def testInstrumentDimensions(self):
80 graph = DimensionGraph(self.universe, names=("exposure", "detector", "calibration_label"))
81 self.assertCountEqual(graph.dimensions.names,
82 ("instrument", "exposure", "detector", "calibration_label",
83 "visit", "physical_filter", "abstract_filter"))
84 self.assertCountEqual(graph.required.names, ("instrument", "exposure", "detector",
85 "calibration_label"))
86 self.assertCountEqual(graph.implied.names, ("visit", "physical_filter", "abstract_filter"))
87 self.assertCountEqual(graph.elements.names - graph.dimensions.names, ("visit_detector_region",))
89 def testCalibrationDimensions(self):
90 graph = DimensionGraph(self.universe, names=("calibration_label", "physical_filter", "detector"))
91 self.assertCountEqual(graph.dimensions.names,
92 ("instrument", "detector", "calibration_label",
93 "physical_filter", "abstract_filter"))
94 self.assertCountEqual(graph.required.names, ("instrument", "detector", "calibration_label",
95 "physical_filter"))
96 self.assertCountEqual(graph.implied.names, ("abstract_filter",))
97 self.assertCountEqual(graph.elements.names, graph.dimensions.names)
99 def testObservationDimensions(self):
100 graph = DimensionGraph(self.universe, names=("exposure", "detector"))
101 self.assertCountEqual(graph.dimensions.names, ("instrument", "detector", "visit", "exposure",
102 "physical_filter", "abstract_filter"))
103 self.assertCountEqual(graph.required.names, ("instrument", "detector", "exposure"))
104 self.assertCountEqual(graph.implied.names, ("physical_filter", "abstract_filter", "visit"))
105 self.assertCountEqual(graph.elements.names - graph.dimensions.names, ("visit_detector_region",))
106 self.assertCountEqual(graph.spatial.names, ("visit_detector_region",))
107 self.assertCountEqual(graph.getSpatial(independent=False).names,
108 ("visit", "visit_detector_region",))
109 self.assertCountEqual(graph.getSpatial(prefer=("visit",)).names, ("visit",))
110 self.assertCountEqual(graph.getTemporal(independent=False).names, ("visit", "exposure"))
111 self.assertCountEqual(graph.temporal.names, ("exposure",))
112 self.assertCountEqual(graph.getTemporal(prefer=("visit",)).names, ("visit",))
114 def testSkyMapDimensions(self):
115 graph = DimensionGraph(self.universe, names=("patch",))
116 self.assertCountEqual(graph.dimensions.names, ("skymap", "tract", "patch"))
117 self.assertCountEqual(graph.required.names, ("skymap", "tract", "patch"))
118 self.assertCountEqual(graph.implied.names, ())
119 self.assertCountEqual(graph.elements.names, graph.dimensions.names)
120 self.assertCountEqual(graph.spatial.names, ("patch",))
121 self.assertCountEqual(graph.getSpatial(independent=False).names, ("patch", "tract"))
122 self.assertCountEqual(graph.getSpatial(prefer=("tract",)).names, ("tract",))
124 def testSubsetCalculation(self):
125 """Test that independent spatial and temporal options are computed
126 correctly.
127 """
128 graph = DimensionGraph(self.universe, names=("visit", "detector", "tract", "patch", "htm7",
129 "exposure", "calibration_label"))
130 self.assertCountEqual(graph.spatial.names,
131 ("visit_detector_region", "patch", "htm7"))
132 self.assertCountEqual(graph.getSpatial(independent=False).names,
133 ("visit_detector_region", "patch", "htm7", "visit", "tract"))
134 self.assertCountEqual(graph.getSpatial(prefer=["tract"]).names,
135 ("visit_detector_region", "tract", "htm7"))
136 self.assertCountEqual(graph.temporal.names,
137 ("exposure", "calibration_label"))
138 self.assertCountEqual(graph.getTemporal(independent=False).names,
139 ("visit", "exposure", "calibration_label"))
140 self.assertCountEqual(graph.getTemporal(prefer=["visit"]).names,
141 ("visit", "calibration_label"))
143 def testSchemaGeneration(self):
144 tableSpecs = NamedKeyDict({})
145 for element in self.universe.elements:
146 if element.hasTable and element.viewOf is None:
147 tableSpecs[element] = makeElementTableSpec(element)
148 for element, tableSpec in tableSpecs.items():
149 for dep in element.graph.required:
150 with self.subTest(element=element.name, dep=dep.name):
151 if dep != element:
152 self.assertIn(dep.name, tableSpec.fields)
153 self.assertEqual(tableSpec.fields[dep.name].dtype, dep.primaryKey.dtype)
154 self.assertEqual(tableSpec.fields[dep.name].length, dep.primaryKey.length)
155 self.assertEqual(tableSpec.fields[dep.name].nbytes, dep.primaryKey.nbytes)
156 self.assertFalse(tableSpec.fields[dep.name].nullable)
157 self.assertTrue(tableSpec.fields[dep.name].primaryKey)
158 else:
159 self.assertIn(element.primaryKey.name, tableSpec.fields)
160 self.assertEqual(tableSpec.fields[element.primaryKey.name].dtype,
161 dep.primaryKey.dtype)
162 self.assertEqual(tableSpec.fields[element.primaryKey.name].length,
163 dep.primaryKey.length)
164 self.assertEqual(tableSpec.fields[element.primaryKey.name].nbytes,
165 dep.primaryKey.nbytes)
166 self.assertFalse(tableSpec.fields[element.primaryKey.name].nullable)
167 self.assertTrue(tableSpec.fields[element.primaryKey.name].primaryKey)
168 for dep in element.implied:
169 with self.subTest(element=element.name, dep=dep.name):
170 self.assertIn(dep.name, tableSpec.fields)
171 self.assertEqual(tableSpec.fields[dep.name].dtype, dep.primaryKey.dtype)
172 self.assertFalse(tableSpec.fields[dep.name].primaryKey)
173 for foreignKey in tableSpec.foreignKeys:
174 self.assertIn(foreignKey.table, tableSpecs)
175 self.assertIn(foreignKey.table, element.graph.dimensions.names)
176 self.assertEqual(len(foreignKey.source), len(foreignKey.target))
177 for source, target in zip(foreignKey.source, foreignKey.target):
178 self.assertIn(source, tableSpec.fields.names)
179 self.assertIn(target, tableSpecs[foreignKey.table].fields.names)
180 self.assertEqual(tableSpec.fields[source].dtype,
181 tableSpecs[foreignKey.table].fields[target].dtype)
182 self.assertEqual(tableSpec.fields[source].length,
183 tableSpecs[foreignKey.table].fields[target].length)
184 self.assertEqual(tableSpec.fields[source].nbytes,
185 tableSpecs[foreignKey.table].fields[target].nbytes)
186 self.assertEqual(tuple(tableSpec.fields.names), element.RecordClass.__slots__)
188 def testPickling(self):
189 # Pickling and copying should always yield the exact same object within
190 # a single process (cross-process is impossible to test here).
191 universe1 = DimensionUniverse()
192 universe2 = pickle.loads(pickle.dumps(universe1))
193 universe3 = copy.copy(universe1)
194 universe4 = copy.deepcopy(universe1)
195 self.assertIs(universe1, universe2)
196 self.assertIs(universe1, universe3)
197 self.assertIs(universe1, universe4)
198 for element1 in universe1.elements:
199 element2 = pickle.loads(pickle.dumps(element1))
200 self.assertIs(element1, element2)
201 graph1 = element1.graph
202 graph2 = pickle.loads(pickle.dumps(graph1))
203 self.assertIs(graph1, graph2)
206if __name__ == "__main__": 206 ↛ 207line 206 didn't jump to line 207, because the condition on line 206 was never true
207 unittest.main()