Coverage for python/lsst/daf/butler/core/dimensions/construction.py: 43%
Shortcuts 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
Shortcuts 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/>.
22from __future__ import annotations
24from abc import ABC, abstractmethod
25from typing import TYPE_CHECKING, AbstractSet, Dict, Iterable
27from .._topology import TopologicalFamily, TopologicalSpace
28from ..named import NamedValueSet
30if TYPE_CHECKING: 30 ↛ 31line 30 didn't jump to line 31, because the condition on line 30 was never true
31 from ._config import DimensionConfig
32 from ._elements import Dimension, DimensionElement
33 from ._packer import DimensionPackerFactory
36class DimensionConstructionVisitor(ABC):
37 """For adding entities to a builder class.
39 An abstract base class for adding one or more entities to a
40 `DimensionConstructionBuilder`.
42 Parameters
43 ----------
44 name : `str`
45 Name of an entity being added. This must be unique across all
46 entities, which include `DimensionElement`, `TopologicalFamily`, and
47 `DimensionPackerFactory` objects. The visitor may add other entities
48 as well, as long as only the named entity is referenced by other
49 entities in the universe.
50 """
52 def __init__(self, name: str):
53 self.name = name
55 def __str__(self) -> str:
56 return self.name
58 @abstractmethod
59 def hasDependenciesIn(self, others: AbstractSet[str]) -> bool:
60 """Test if dependencies have already been constructed.
62 Tests whether other entities this visitor depends on have already
63 been constructed.
65 Parameters
66 ----------
67 others : `AbstractSet` [ `str` ]
68 The names of other visitors that have not yet been invoked.
70 Returns
71 -------
72 blocked : `bool`
73 If `True`, this visitor has dependencies on other visitors that
74 must be invoked before this one can be. If `False`, `visit` may
75 be called.
76 """
77 raise NotImplementedError()
79 @abstractmethod
80 def visit(self, builder: DimensionConstructionBuilder) -> None:
81 """Modify the given builder object to include responsible entities.
83 Parameters
84 ----------
85 builder : `DimensionConstructionBuilder`
86 Builder to modify in-place and from which dependencies can be
87 obtained.
89 Notes
90 -----
91 Subclasses may assume (and callers must guarantee) that
92 `hasDependenciesIn` would return `False` prior to `visit` being
93 called.
94 """
95 raise NotImplementedError()
98class DimensionConstructionBuilder:
99 """A builder object for constructing `DimensionUniverse` instances.
101 `DimensionConstructionVisitor` objects can be added to a
102 `DimensionConstructionBuilder` object in any order, and are invoked
103 in a deterministic order consistent with their dependency relationships
104 by a single call (by the `DimensionUniverse`) to the `finish` method.
106 Parameters
107 ----------
108 version : `int`
109 Version for the `DimensionUniverse`.
110 commonSkyPixName : `str`
111 Name of the "common" skypix dimension that is used to relate all other
112 spatial `TopologicalRelationshipEndpoint` objects.
113 visitors : `Iterable` [ `DimensionConstructionVisitor` ]
114 Visitor instances to include from the start.
115 """
117 def __init__(
118 self,
119 version: int,
120 commonSkyPixName: str,
121 config: DimensionConfig,
122 *,
123 visitors: Iterable[DimensionConstructionVisitor] = (),
124 ) -> None:
125 self.dimensions = NamedValueSet()
126 self.elements = NamedValueSet()
127 self.topology = {space: NamedValueSet() for space in TopologicalSpace.__members__.values()}
128 self.packers = {}
129 self.version = version
130 self.config = config
131 self.commonSkyPixName = commonSkyPixName
132 self._todo: Dict[str, DimensionConstructionVisitor] = {v.name: v for v in visitors}
134 def add(self, visitor: DimensionConstructionVisitor) -> None:
135 """Add a single visitor to the builder.
137 Parameters
138 ----------
139 visitor : `DimensionConstructionVisitor`
140 Visitor instance to add.
141 """
142 self._todo[visitor.name] = visitor
144 def update(self, visitors: Iterable[DimensionConstructionVisitor]) -> None:
145 """Add multiple visitors to the builder.
147 Parameters
148 ----------
149 visitors : `Iterable` [ `DimensionConstructionVisitor` ]
150 Visitor instances to add.
151 """
152 self._todo.update((v.name, v) for v in visitors)
154 def finish(self) -> None:
155 """Complete construction of the builder.
157 This method invokes all visitors in an order consistent with their
158 dependencies, fully populating all public attributes. It should be
159 called only once, by `DimensionUniverse` itself.
160 """
161 while self._todo:
162 unblocked = [
163 name
164 for name, visitor in self._todo.items()
165 if not visitor.hasDependenciesIn(self._todo.keys())
166 ]
167 unblocked.sort() # Break ties lexicographically.
168 if not unblocked:
169 raise RuntimeError(f"Cycle or unmet dependency in dimension elements: {self._todo.keys()}.")
170 for name in unblocked:
171 self._todo.pop(name).visit(self)
173 version: int
174 """Version number for the `DimensionUniverse` (`int`).
176 Populated at builder construction.
177 """
179 commonSkyPixName: str
180 """Name of the common skypix dimension used to connect other spatial
181 `TopologicalRelationshipEndpoint` objects (`str`).
183 Populated at builder construction.
184 """
186 dimensions: NamedValueSet[Dimension]
187 """Set of all `Dimension` objects (`NamedValueSet` [ `Dimension` ]).
189 Populated by `finish`.
190 """
192 elements: NamedValueSet[DimensionElement]
193 """Set of all `DimensionElement` objects
194 (`NamedValueSet` [ `DimensionElement` ]).
196 Populated by `finish`. `DimensionConstructionVisitor` classes that
197 construct `Dimension` objects are responsible for adding them to this
198 set as well as `dimensions`.
199 """
201 topology: Dict[TopologicalSpace, NamedValueSet[TopologicalFamily]]
202 """Dictionary containing all `TopologicalFamily` objects
203 (`dict` [ `TopologicalSpace`, `NamedValueSet` [ `TopologicalFamily` ] ] ).
204 """
206 packers: Dict[str, DimensionPackerFactory]
207 """Dictionary containing all `DimensionPackerFactory` objects
208 (`dict` [ `str`, `DimensionPackerFactory` ] ).
209 """