Coverage for python/lsst/daf/butler/script/queryCollections.py: 8%

68 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-11 03:16 -0700

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 software is dual licensed under the GNU General Public License and also 

10# under a 3-clause BSD license. Recipients may choose which of these licenses 

11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt, 

12# respectively. If you choose the GPL option then the following text applies 

13# (but note that there is still no warranty even if you opt for BSD instead): 

14# 

15# This program is free software: you can redistribute it and/or modify 

16# it under the terms of the GNU General Public License as published by 

17# the Free Software Foundation, either version 3 of the License, or 

18# (at your option) any later version. 

19# 

20# This program is distributed in the hope that it will be useful, 

21# but WITHOUT ANY WARRANTY; without even the implied warranty of 

22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

23# GNU General Public License for more details. 

24# 

25# You should have received a copy of the GNU General Public License 

26# along with this program. If not, see <http://www.gnu.org/licenses/>. 

27 

28from __future__ import annotations 

29 

30from collections.abc import Iterable 

31 

32from astropy.table import Table 

33 

34from .._butler import Butler 

35from ..registry import CollectionType 

36 

37 

38def _getTable( 

39 repo: str, 

40 glob: Iterable[str], 

41 collection_type: Iterable[CollectionType], 

42 inverse: bool, 

43) -> Table: 

44 """Run queryCollections and return the results in Table form. 

45 

46 Only lists the first child (or parent if `inverse` is `True`) in the 

47 description column. 

48 

49 Parameters 

50 ---------- 

51 repo : `str` 

52 The Butler repository location. 

53 glob : `collections.abc.Iterable` of `str` 

54 Wildcard to pass to ``queryCollections``. 

55 collection_type 

56 Same as `queryCollections` 

57 inverse : `bool` 

58 True if parent CHAINED datasets of each dataset should be listed in the 

59 description column, False if children of CHAINED datasets should be 

60 listed. 

61 

62 Returns 

63 ------- 

64 collections : `astropy.table.Table` 

65 Same as `queryCollections` 

66 """ 

67 typeCol = "Type" 

68 descriptionCol = "Parents" if inverse else "Children" 

69 table = Table( 

70 names=("Name", typeCol, descriptionCol), 

71 dtype=(str, str, str), 

72 ) 

73 butler = Butler.from_config(repo) 

74 names = sorted( 

75 butler.registry.queryCollections(collectionTypes=frozenset(collection_type), expression=glob or ...) 

76 ) 

77 if inverse: 

78 for name in names: 

79 type = butler.registry.getCollectionType(name) 

80 parentNames = butler.registry.getCollectionParentChains(name) 

81 if parentNames: 

82 first = True 

83 for parentName in sorted(parentNames): 

84 table.add_row((name if first else "", type.name if first else "", parentName)) 

85 first = False 

86 else: 

87 table.add_row((name, type.name, "")) 

88 # If none of the datasets has a parent dataset then remove the 

89 # description column. 

90 if not any(c for c in table[descriptionCol]): 

91 del table[descriptionCol] 

92 else: 

93 for name in names: 

94 type = butler.registry.getCollectionType(name) 

95 if type == CollectionType.CHAINED: 

96 children = butler.registry.getCollectionChain(name) 

97 if children: 

98 first = True 

99 for child in children: 

100 table.add_row((name if first else "", type.name if first else "", child)) 

101 first = False 

102 else: 

103 table.add_row((name, type.name, "")) 

104 else: 

105 table.add_row((name, type.name, "")) 

106 # If there aren't any CHAINED datasets in the results then remove the 

107 # description column. 

108 if not any(columnVal == CollectionType.CHAINED.name for columnVal in table[typeCol]): 

109 del table[descriptionCol] 

110 

111 return table 

112 

113 

114def _getTree( 

115 repo: str, 

116 glob: Iterable[str], 

117 collection_type: Iterable[CollectionType], 

118 inverse: bool, 

119) -> Table: 

120 """Run queryCollections and return the results in a table representing tree 

121 form. 

122 

123 Recursively lists children (or parents if `inverse` is `True`) 

124 

125 Parameters 

126 ---------- 

127 repo : `str` 

128 Butler repository location. 

129 glob : `collections.abc.Iterable` of `str` 

130 Wildcards to pass to ``queryCollections``. 

131 collection_type 

132 Same as `queryCollections` 

133 inverse : `bool` 

134 True if parent CHAINED datasets of each dataset should be listed in the 

135 description column, False if children of CHAINED datasets should be 

136 listed. 

137 

138 Returns 

139 ------- 

140 collections : `astropy.table.Table` 

141 Same as `queryCollections` 

142 """ 

143 table = Table( 

144 names=("Name", "Type"), 

145 dtype=(str, str), 

146 ) 

147 butler = Butler.from_config(repo, without_datastore=True) 

148 

149 def addCollection(name: str, level: int = 0) -> None: 

150 collectionType = butler.registry.getCollectionType(name) 

151 table.add_row((" " * level + name, collectionType.name)) 

152 if inverse: 

153 parentNames = butler.registry.getCollectionParentChains(name) 

154 for pname in sorted(parentNames): 

155 addCollection(pname, level + 1) 

156 else: 

157 if collectionType == CollectionType.CHAINED: 

158 childNames = butler.registry.getCollectionChain(name) 

159 for name in childNames: 

160 addCollection(name, level + 1) 

161 

162 collections = butler.registry.queryCollections( 

163 collectionTypes=frozenset(collection_type), expression=glob or ... 

164 ) 

165 for collection in sorted(collections): 

166 addCollection(collection) 

167 return table 

168 

169 

170def _getFlatten( 

171 repo: str, 

172 glob: Iterable[str], 

173 collection_type: Iterable[CollectionType], 

174) -> Table: 

175 butler = Butler.from_config(repo) 

176 collectionNames = list( 

177 butler.registry.queryCollections( 

178 collectionTypes=frozenset(collection_type), flattenChains=True, expression=glob or ... 

179 ) 

180 ) 

181 

182 collectionTypes = [butler.registry.getCollectionType(c).name for c in collectionNames] 

183 return Table((collectionNames, collectionTypes), names=("Name", "Type")) 

184 

185 

186def queryCollections( 

187 repo: str, 

188 glob: Iterable[str], 

189 collection_type: Iterable[CollectionType], 

190 chains: str, 

191) -> Table: 

192 """Get the collections whose names match an expression. 

193 

194 Parameters 

195 ---------- 

196 repo : `str` 

197 URI to the location of the repo or URI to a config file describing the 

198 repo and its location. 

199 glob : `~collections.abc.Iterable` [`str`] 

200 A list of glob-style search string that fully or partially identify 

201 the dataset type names to search for. 

202 collection_type : `~collections.abc.Iterable` [ `CollectionType` ], \ 

203 optional 

204 If provided, only return collections of these types. 

205 chains : `str` 

206 Must be one of "FLATTEN", "TABLE", or "TREE" (case sensitive). 

207 Affects contents and formatting of results, see 

208 ``cli.commands.query_collections``. 

209 

210 Returns 

211 ------- 

212 collections : `astropy.table.Table` 

213 A table containing information about collections. 

214 """ 

215 if (inverse := chains == "INVERSE-TABLE") or chains == "TABLE": 

216 return _getTable(repo, glob, collection_type, inverse) 

217 elif (inverse := chains == "INVERSE-TREE") or chains == "TREE": 

218 return _getTree(repo, glob, collection_type, inverse) 

219 elif chains == "FLATTEN": 

220 return _getFlatten(repo, glob, collection_type) 

221 raise RuntimeError(f"Value for --chains not recognized: {chains}")