Coverage for python/lsst/daf/butler/core/_column_tags.py: 64%

72 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-11 02:31 -0800

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 

24__all__ = ( 

25 "DatasetColumnTag", 

26 "DimensionKeyColumnTag", 

27 "DimensionRecordColumnTag", 

28 "is_timespan_column", 

29) 

30 

31import dataclasses 

32from collections.abc import Iterable 

33from typing import TYPE_CHECKING, Any, TypeVar, final 

34 

35_S = TypeVar("_S") 

36 

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

38 from lsst.daf.relation import ColumnTag 

39 

40 

41class _BaseColumnTag: 

42 

43 __slots__ = () 

44 

45 @classmethod 

46 def filter_from(cls: type[_S], tags: Iterable[Any]) -> set[_S]: 

47 return {tag for tag in tags if type(tag) is cls} 

48 

49 

50@final 

51@dataclasses.dataclass(frozen=True, slots=True) 

52class DimensionKeyColumnTag(_BaseColumnTag): 

53 """An identifier for `~lsst.daf.relation.Relation` columns that represent 

54 a dimension primary key value. 

55 """ 

56 

57 dimension: str 

58 """Name of the dimension (`str`).""" 

59 

60 def __str__(self) -> str: 

61 return self.dimension 

62 

63 @property 

64 def qualified_name(self) -> str: 

65 return self.dimension 

66 

67 @property 

68 def is_key(self) -> bool: 

69 return True 

70 

71 @classmethod 

72 def generate(cls, dimensions: Iterable[str]) -> list[DimensionKeyColumnTag]: 

73 """Return a list of column tags from an iterable of dimension 

74 names. 

75 

76 Parameters 

77 ---------- 

78 dimensions : `Iterable` [ `str` ] 

79 Dimension names. 

80 

81 Returns 

82 ------- 

83 tags : `list` [ `DimensionKeyColumnTag` ] 

84 List of column tags. 

85 """ 

86 return [cls(d) for d in dimensions] 

87 

88 

89@final 

90@dataclasses.dataclass(frozen=True, slots=True) 

91class DimensionRecordColumnTag(_BaseColumnTag): 

92 """An identifier for `~lsst.daf.relation.Relation` columns that represent 

93 non-key columns in a dimension or dimension element record. 

94 """ 

95 

96 element: str 

97 """Name of the dimension element (`str`). 

98 """ 

99 

100 column: str 

101 """Name of the column (`str`).""" 

102 

103 def __str__(self) -> str: 

104 return f"{self.element}.{self.column}" 

105 

106 @property 

107 def qualified_name(self) -> str: 

108 return f"n!{self.element}:{self.column}" 

109 

110 @property 

111 def is_key(self) -> bool: 

112 return False 

113 

114 @classmethod 

115 def generate(cls, element: str, columns: Iterable[str]) -> list[DimensionRecordColumnTag]: 

116 """Return a list of column tags from an iterable of column names 

117 for a single dimension element. 

118 

119 Parameters 

120 ---------- 

121 element : `str` 

122 Name of the dimension element. 

123 columns : `Iterable` [ `str` ] 

124 Column names. 

125 

126 Returns 

127 ------- 

128 tags : `list` [ `DimensionRecordColumnTag` ] 

129 List of column tags. 

130 """ 

131 return [cls(element, column) for column in columns] 

132 

133 

134@final 

135@dataclasses.dataclass(frozen=True, slots=True) 

136class DatasetColumnTag(_BaseColumnTag): 

137 """An identifier for `~lsst.daf.relation.Relation` columns that represent 

138 columns from a dataset query or subquery. 

139 """ 

140 

141 dataset_type: str 

142 """Name of the dataset type (`str`).""" 

143 

144 column: str 

145 """Name of the column (`str`). 

146 

147 Allowed values are: 

148 

149 - "dataset_id" (autoincrement or UUID primary key) 

150 - "run" (collection primary key, not collection name) 

151 - "ingest_date" 

152 - "timespan" (validity range, or NULL for non-calibration collections) 

153 - "rank" (collection position in ordered search) 

154 """ 

155 

156 def __str__(self) -> str: 

157 return f"{self.dataset_type}.{self.column}" 

158 

159 @property 

160 def qualified_name(self) -> str: 

161 return f"t!{self.dataset_type}:{self.column}" 

162 

163 @property 

164 def is_key(self) -> bool: 

165 return self.column == "dataset_id" or self.column == "run" 

166 

167 @classmethod 

168 def generate(cls, dataset_type: str, columns: Iterable[str]) -> list[DatasetColumnTag]: 

169 """Return a list of column tags from an iterable of column names 

170 for a single dataset type. 

171 

172 Parameters 

173 ---------- 

174 dataset_type : `str` 

175 Name of the dataset type. 

176 columns : `Iterable` [ `str` ] 

177 Column names. 

178 

179 Returns 

180 ------- 

181 tags : `list` [ `DatasetColumnTag` ] 

182 List of column tags. 

183 """ 

184 return [cls(dataset_type, column) for column in columns] 

185 

186 

187def is_timespan_column(tag: ColumnTag) -> bool: 

188 """Test whether a column tag is a timespan. 

189 

190 Parameters 

191 ---------- 

192 tag : `ColumnTag` 

193 Column tag to test. 

194 

195 Returns 

196 ------- 

197 is_timespan : `bool` 

198 Whether the given column is a timespan. 

199 """ 

200 match tag: 

201 case DimensionRecordColumnTag(column="timespan"): 

202 return True 

203 case DatasetColumnTag(column="timespan"): 

204 return True 

205 return False