Coverage for python/lsst/daf/butler/registry/_butler_registry.py: 84%

31 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-08-12 09:20 +0000

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

25 

26from abc import abstractmethod 

27from typing import TYPE_CHECKING 

28 

29from lsst.resources import ResourcePathExpression 

30 

31from ..core import Config, DimensionConfig 

32from ._config import RegistryConfig 

33from ._defaults import RegistryDefaults 

34from ._registry import Registry 

35 

36if TYPE_CHECKING: 

37 from .._butlerConfig import ButlerConfig 

38 from .interfaces import CollectionRecord, DatastoreRegistryBridgeManager 

39 

40 

41class _ButlerRegistry(Registry): 

42 """Registry interface extended with methods used by Butler implementation. 

43 

44 Each registry implementation can have its own constructor parameters. 

45 The assumption is that an instance of a specific subclass will be 

46 constructed from configuration using `Registry.fromConfig()`. 

47 The base class will look for a ``cls`` entry and call that specific 

48 `fromConfig()` method. 

49 """ 

50 

51 defaultConfigFile: str | None = None 

52 """Path to configuration defaults. Accessed within the ``configs`` resource 

53 or relative to a search path. Can be None if no defaults specified. 

54 """ 

55 

56 @classmethod 

57 def forceRegistryConfig( 

58 cls, config: ButlerConfig | RegistryConfig | Config | str | None 

59 ) -> RegistryConfig: 

60 """Force the supplied config to a `RegistryConfig`. 

61 

62 Parameters 

63 ---------- 

64 config : `RegistryConfig`, `Config` or `str` or `None` 

65 Registry configuration, if missing then default configuration will 

66 be loaded from registry.yaml. 

67 

68 Returns 

69 ------- 

70 registry_config : `RegistryConfig` 

71 A registry config. 

72 """ 

73 if not isinstance(config, RegistryConfig): 

74 if isinstance(config, str | Config) or config is None: 

75 config = RegistryConfig(config) 

76 else: 

77 raise ValueError(f"Incompatible Registry configuration: {config}") 

78 return config 

79 

80 @classmethod 

81 @abstractmethod 

82 def createFromConfig( 

83 cls, 

84 config: RegistryConfig | str | None = None, 

85 dimensionConfig: DimensionConfig | str | None = None, 

86 butlerRoot: ResourcePathExpression | None = None, 

87 ) -> _ButlerRegistry: 

88 """Create registry database and return `_ButlerRegistry` instance. 

89 

90 This method initializes database contents, database must be empty 

91 prior to calling this method. 

92 

93 Parameters 

94 ---------- 

95 config : `RegistryConfig` or `str`, optional 

96 Registry configuration, if missing then default configuration will 

97 be loaded from registry.yaml. 

98 dimensionConfig : `DimensionConfig` or `str`, optional 

99 Dimensions configuration, if missing then default configuration 

100 will be loaded from dimensions.yaml. 

101 butlerRoot : convertible to `lsst.resources.ResourcePath`, optional 

102 Path to the repository root this `Registry` will manage. 

103 

104 Returns 

105 ------- 

106 registry : `_ButlerRegistry` 

107 A new `_ButlerRegistry` instance. 

108 

109 Notes 

110 ----- 

111 This class will determine the concrete `_ButlerRegistry` subclass to 

112 use from configuration. Each subclass should implement this method 

113 even if it can not create a registry. 

114 """ 

115 raise NotImplementedError() 

116 

117 @classmethod 

118 @abstractmethod 

119 def fromConfig( 

120 cls, 

121 config: ButlerConfig | RegistryConfig | Config | str, 

122 butlerRoot: ResourcePathExpression | None = None, 

123 writeable: bool = True, 

124 defaults: RegistryDefaults | None = None, 

125 ) -> _ButlerRegistry: 

126 """Create `_ButlerRegistry` subclass instance from ``config``. 

127 

128 Registry database must be initialized prior to calling this method. 

129 

130 Parameters 

131 ---------- 

132 config : `ButlerConfig`, `RegistryConfig`, `Config` or `str` 

133 Registry configuration 

134 butlerRoot : convertible to `lsst.resources.ResourcePath`, optional 

135 Path to the repository root this `Registry` will manage. 

136 writeable : `bool`, optional 

137 If `True` (default) create a read-write connection to the database. 

138 defaults : `~lsst.daf.butler.registry.RegistryDefaults`, optional 

139 Default collection search path and/or output `~CollectionType.RUN` 

140 collection. 

141 

142 Returns 

143 ------- 

144 registry : `_ButlerRegistry` (subclass) 

145 A new `_ButlerRegistry` subclass instance. 

146 

147 Notes 

148 ----- 

149 This class will determine the concrete `_ButlerRegistry` subclass to 

150 use from configuration. Each subclass should implement this method. 

151 """ 

152 # The base class implementation should trampoline to the correct 

153 # subclass. No implementation should ever use this implementation 

154 # directly. If no class is specified, default to the standard 

155 # registry. 

156 raise NotImplementedError() 

157 

158 @abstractmethod 

159 def copy(self, defaults: RegistryDefaults | None = None) -> _ButlerRegistry: 

160 """Create a new `_ButlerRegistry` backed by the same data repository 

161 and connection as this one, but independent defaults. 

162 

163 Parameters 

164 ---------- 

165 defaults : `~lsst.daf.butler.registry.RegistryDefaults`, optional 

166 Default collections and data ID values for the new registry. If 

167 not provided, ``self.defaults`` will be used (but future changes 

168 to either registry's defaults will not affect the other). 

169 

170 Returns 

171 ------- 

172 copy : `_ButlerRegistry` 

173 A new `_ButlerRegistry` instance with its own defaults. 

174 

175 Notes 

176 ----- 

177 Because the new registry shares a connection with the original, they 

178 also share transaction state (despite the fact that their `transaction` 

179 context manager methods do not reflect this), and must be used with 

180 care. 

181 """ 

182 raise NotImplementedError() 

183 

184 @abstractmethod 

185 def _get_collection_record(self, name: str) -> CollectionRecord: 

186 """Return the record for this collection. 

187 

188 Parameters 

189 ---------- 

190 name : `str` 

191 Name of the collection for which the record is to be retrieved. 

192 

193 Returns 

194 ------- 

195 record : `CollectionRecord` 

196 The record for this collection. 

197 """ 

198 raise NotImplementedError() 

199 

200 @abstractmethod 

201 def getDatastoreBridgeManager(self) -> DatastoreRegistryBridgeManager: 

202 """Return an object that allows a new `Datastore` instance to 

203 communicate with this `Registry`. 

204 

205 Returns 

206 ------- 

207 manager : `~.interfaces.DatastoreRegistryBridgeManager` 

208 Object that mediates communication between this `Registry` and its 

209 associated datastores. 

210 """ 

211 raise NotImplementedError()