Coverage for python/lsst/daf/butler/_butlerRepoIndex.py: 37%

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

43 statements  

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__ = ("ButlerRepoIndex",) 

25 

26import os 

27 

28from typing import ( 

29 ClassVar, 

30 Dict, 

31 Set, 

32) 

33 

34from .core import ( 

35 ButlerURI, 

36 Config, 

37) 

38 

39 

40class ButlerRepoIndex: 

41 """Index of all known butler repositories. 

42 

43 The index of butler repositories is found by looking for a 

44 configuration file at the URI pointed at by the environment 

45 variable ``$DAF_BUTLER_REPOSITORY_INDEX``. The configuration file 

46 is a simple dictionary lookup of the form: 

47 

48 .. code-block:: yaml 

49 

50 label1: uri1 

51 label2: uri2 

52 

53 and can be in YAML or JSON format. The content of the file will be 

54 cached. 

55 """ 

56 

57 index_env_var: ClassVar[str] = "DAF_BUTLER_REPOSITORY_INDEX" 

58 """The name of the environment variable to read to locate the index.""" 

59 

60 _cache: ClassVar[Dict[ButlerURI, Config]] = {} 

61 """Cache of indexes. In most scenarios only one index will be found 

62 and the environment will not change. In tests this may not be true.""" 

63 

64 @classmethod 

65 def _read_repository_index(cls, index_uri: ButlerURI) -> Config: 

66 """Read the repository index from the supplied URI. 

67 

68 Parameters 

69 ---------- 

70 index_uri : `str` or `ButlerURI` 

71 URI of the repository index. 

72 

73 Returns 

74 ------- 

75 repo_index : `Config` 

76 The index found at this URI. 

77 

78 Raises 

79 ------ 

80 FileNotFoundError 

81 Raised if the URI does not exist. 

82 

83 Notes 

84 ----- 

85 Does check the cache before reading the file. 

86 """ 

87 if index_uri in cls._cache: 

88 return cls._cache[index_uri] 

89 

90 repo_index = Config(index_uri) 

91 cls._cache[index_uri] = repo_index 

92 

93 return repo_index 

94 

95 @classmethod 

96 def _get_index_uri(cls) -> ButlerURI: 

97 """Find the URI to the repository index. 

98 

99 Returns 

100 ------- 

101 index_uri : `ButlerURI` 

102 URI to the repository index. 

103 

104 Raises 

105 ------ 

106 KeyError 

107 Raised if the location of the index could not be determined. 

108 """ 

109 index_uri = os.environ.get(cls.index_env_var) 

110 if index_uri is None: 

111 raise KeyError(f"No repository index defined in enviroment variable {cls.index_env_var}") 

112 return ButlerURI(index_uri) 

113 

114 @classmethod 

115 def _read_repository_index_from_environment(cls) -> Config: 

116 """Look in environment for index location and read it. 

117 

118 Returns 

119 ------- 

120 repo_index : `Config` 

121 The index found in the environment. 

122 """ 

123 index_uri = cls._get_index_uri() 

124 return cls._read_repository_index(index_uri) 

125 

126 @classmethod 

127 def get_known_repos(cls) -> Set[str]: 

128 """Retrieve the list of known repository labels. 

129 

130 Returns 

131 ------- 

132 repos : `set` of `str` 

133 All the known labels. Can be empty if no index can be found. 

134 """ 

135 try: 

136 repo_index = cls._read_repository_index_from_environment() 

137 except (FileNotFoundError, KeyError): 

138 return set() 

139 return set(repo_index) 

140 

141 @classmethod 

142 def get_repo_uri(cls, label: str) -> ButlerURI: 

143 """Look up the label in a butler repository index. 

144 

145 Parameters 

146 ---------- 

147 label : `str` 

148 Label of the Butler repository to look up. 

149 

150 Returns 

151 ------- 

152 uri : `ButlerURI` 

153 URI to the Butler repository associated with the given label. 

154 

155 Raises 

156 ------ 

157 KeyError 

158 Raised if the label is not found in the index, or if an index 

159 can not be found at all. 

160 FileNotFoundError 

161 Raised if an index is defined in the environment but it 

162 can not be found. 

163 """ 

164 repo_index = cls._read_repository_index_from_environment() 

165 repo_uri = repo_index.get(label) 

166 if repo_uri is None: 

167 # This should not raise since it worked earlier. 

168 try: 

169 index_uri = str(cls._get_index_uri()) 

170 except KeyError: 

171 index_uri = "<environment variable not defined>" 

172 raise KeyError(f"Label '{label}' not known to repository index at {index_uri}") 

173 return ButlerURI(repo_uri)