Hide keyboard shortcuts

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/>. 

21 

22from __future__ import annotations 

23 

24from abc import ABC, abstractmethod 

25from typing import ( 

26 AbstractSet, 

27 Dict, 

28 Iterable, 

29 TYPE_CHECKING, 

30) 

31 

32from ..named import NamedValueSet 

33from .._topology import TopologicalFamily, TopologicalSpace 

34 

35if TYPE_CHECKING: 35 ↛ 36line 35 didn't jump to line 36, because the condition on line 35 was never true

36 from ._elements import Dimension, DimensionElement 

37 from ._packer import DimensionPackerFactory 

38 

39 

40class DimensionConstructionVisitor(ABC): 

41 """An abstract base class for adding one or more entities to a 

42 `DimensionConstructionBuilder`. 

43 

44 Parameters 

45 ---------- 

46 name : `str` 

47 Name of an entity being added. This must be unique across all 

48 entities, which include `DimensionElement`, `TopologicalFamily`, and 

49 `DimensionPackerFactory` objects. The visitor may add other entities 

50 as well, as long as only the named entity is referenced by other 

51 entities in the universe. 

52 """ 

53 

54 def __init__(self, name: str): 

55 self.name = name 

56 

57 def __str__(self) -> str: 

58 return self.name 

59 

60 @abstractmethod 

61 def hasDependenciesIn(self, others: AbstractSet[str]) -> bool: 

62 """Test whether other entities this visitor depends on have already 

63 been constructed. 

64 

65 Parameters 

66 ---------- 

67 others : `AbstractSet` [ `str` ] 

68 The names of other visitors that have not yet been invoked. 

69 

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() 

78 

79 @abstractmethod 

80 def visit(self, builder: DimensionConstructionBuilder) -> None: 

81 """Modify the given builder object to include the entities this object 

82 is responsible for constructing. 

83 

84 Parameters 

85 ---------- 

86 builder : `DimensionConstructionBuilder` 

87 Builder to modify in-place and from which dependencies can be 

88 obtained. 

89 

90 Notes 

91 ----- 

92 Subclasses may assume (and callers must guarantee) that 

93 `hasDependenciesIn` would return `False` prior to `visit` being 

94 called. 

95 """ 

96 raise NotImplementedError() 

97 

98 

99class DimensionConstructionBuilder: 

100 """A builder object for constructing `DimensionUniverse` instances. 

101 

102 `DimensionConstructionVisitor` objects can be added to a 

103 `DimensionConstructionBuilder` object in any order, and are invoked 

104 in a deterministic order consistent with their dependency relationships 

105 by a single call (by the `DimensionUnvierse`) to the `finish` method. 

106 

107 Parameters 

108 ---------- 

109 version : `int` 

110 Version for the `DimensionUniverse`. 

111 commonSkyPixName : `str` 

112 Name of the "common" skypix dimension that is used to relate all other 

113 spatial `TopologicalRelationshipEndpoint` objects. 

114 visitors : `Iterable` [ `DimensionConstructionVisitor` ] 

115 Visitor instances to include from the start. 

116 """ 

117 

118 def __init__( 

119 self, 

120 version: int, 

121 commonSkyPixName: str, *, 

122 visitors: Iterable[DimensionConstructionVisitor] = () 

123 ) -> None: 

124 self.dimensions = NamedValueSet() 

125 self.elements = NamedValueSet() 

126 self.topology = {space: NamedValueSet() for space in TopologicalSpace.__members__.values()} 

127 self.packers = {} 

128 self.version = version 

129 self.commonSkyPixName = commonSkyPixName 

130 self._todo: Dict[str, DimensionConstructionVisitor] = {v.name: v for v in visitors} 

131 

132 def add(self, visitor: DimensionConstructionVisitor) -> None: 

133 """Add a single visitor to the builder. 

134 

135 Parameters 

136 ---------- 

137 visitor : `DimensionConstructionVisitor` 

138 Visitor instance to add. 

139 """ 

140 self._todo[visitor.name] = visitor 

141 

142 def update(self, visitors: Iterable[DimensionConstructionVisitor]) -> None: 

143 """Add multiple visitors to the builder. 

144 

145 Parameters 

146 ---------- 

147 visitors : `Iterable` [ `DimensionConstructionVisitor` ] 

148 Visitor instances to add. 

149 """ 

150 self._todo.update((v.name, v) for v in visitors) 

151 

152 def finish(self) -> None: 

153 """Complete construction of the builder. 

154 

155 This method invokes all visitors in an order consistent with their 

156 dependencies, fully populating all public attributes. It should be 

157 called only once, by `DimensionUniverse` itself. 

158 """ 

159 while self._todo: 

160 unblocked = [name for name, visitor in self._todo.items() 

161 if not visitor.hasDependenciesIn(self._todo.keys())] 

162 unblocked.sort() # Break ties lexicographically. 

163 if not unblocked: 

164 raise RuntimeError(f"Cycle or unmet dependency in dimension elements: {self._todo.keys()}.") 

165 for name in unblocked: 

166 self._todo.pop(name).visit(self) 

167 

168 version: int 

169 """Version number for the `DimensionUniverse` (`int`). 

170 

171 Populated at builder construction. 

172 """ 

173 

174 commonSkyPixName: str 

175 """Name of the common skypix dimension used to connect other spatial 

176 `TopologicalRelationshipEndpoint` objects (`str`). 

177 

178 Populated at builder construction. 

179 """ 

180 

181 dimensions: NamedValueSet[Dimension] 

182 """Set of all `Dimension` objects (`NamedValueSet` [ `Dimension` ]). 

183 

184 Populated by `finish`. 

185 """ 

186 

187 elements: NamedValueSet[DimensionElement] 

188 """Set of all `DimensionElement` objects 

189 (`NamedValueSet` [ `DimensionElement` ]). 

190 

191 Populated by `finish`. `DimensionConstructionVisitor` classes that 

192 construct `Dimension` objects are responsible for adding them to this 

193 set as well as `dimensions`. 

194 """ 

195 

196 topology: Dict[TopologicalSpace, NamedValueSet[TopologicalFamily]] 

197 """Dictionary containing all `TopologicalFamily` objects 

198 (`dict` [ `TopologicalSpace`, `NamedValueSet` [ `TopologicalFamily` ] ] ). 

199 """ 

200 

201 packers: Dict[str, DimensionPackerFactory] 

202 """Dictionary containing all `DimensionPackerFactory` objects 

203 (`dict` [ `str`, `DimensionPackerFactory` ] ). 

204 """