Coverage for python/lsst/daf/butler/registry/interfaces/_attributes.py: 98%

25 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-10 10:14 +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 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/>. 

27from __future__ import annotations 

28 

29__all__ = [ 

30 "ButlerAttributeManager", 

31 "ButlerAttributeExistsError", 

32] 

33 

34from abc import abstractmethod 

35from collections.abc import Iterable 

36from typing import TYPE_CHECKING 

37 

38from ._versioning import VersionedExtension, VersionTuple 

39 

40if TYPE_CHECKING: 

41 from ._database import Database, StaticTablesContext 

42 

43 

44class ButlerAttributeExistsError(RuntimeError): 

45 """Exception raised when trying to update existing attribute without 

46 specifying ``force`` option. 

47 """ 

48 

49 

50class ButlerAttributeManager(VersionedExtension): 

51 """An interface for managing butler attributes in a `Registry`. 

52 

53 Parameters 

54 ---------- 

55 registry_schema_version : `VersionTuple` or `None`, optional 

56 Version of registry schema. 

57 

58 Notes 

59 ----- 

60 Attributes are represented in registry as a set of name-value pairs, both 

61 have string type. Any non-string data types (e.g. integers) need to be 

62 converted to/from strings on client side. Attribute names can be arbitrary 

63 strings, no particular structure is enforced by this interface. Attribute 

64 names are globally unique, to avoid potential collision clients should 

65 follow some common convention for attribute names, e.g. dot-separated 

66 components (``config.managers.opaque``). 

67 

68 One of the critical pieces of information that will be stored as 

69 attribute is the version of database schema which needs to be known 

70 before registry can do any operations on database. For that reasons it is 

71 likely there will be only one implementation of this interface which uses 

72 database table with a stable schema. 

73 """ 

74 

75 def __init__(self, *, registry_schema_version: VersionTuple | None = None) -> None: 

76 super().__init__(registry_schema_version=registry_schema_version) 

77 

78 @classmethod 

79 @abstractmethod 

80 def initialize( 

81 cls, db: Database, context: StaticTablesContext, registry_schema_version: VersionTuple | None = None 

82 ) -> ButlerAttributeManager: 

83 """Construct an instance of the manager. 

84 

85 Parameters 

86 ---------- 

87 db : `Database` 

88 Interface to the underlying database engine and namespace. 

89 context : `StaticTablesContext` 

90 Context object obtained from `Database.declareStaticTables`; used 

91 to declare any tables that should always be present in a layer 

92 implemented with this manager. 

93 registry_schema_version : `VersionTuple` or `None` 

94 Schema version of this extension as defined in registry. 

95 

96 Returns 

97 ------- 

98 manager : `ButlerAttributeManager` 

99 An instance of `ButlerAttributeManager`. 

100 """ 

101 raise NotImplementedError() 

102 

103 @abstractmethod 

104 def get(self, name: str, default: str | None = None) -> str | None: 

105 """Retrieve value of a given attribute. 

106 

107 Parameters 

108 ---------- 

109 name : `str` 

110 Attribute name, arbitrary non-empty string. 

111 default : `str`, optional 

112 Default value returned when attribute does not exist, can be 

113 string or `None`. 

114 

115 Returns 

116 ------- 

117 value : `str` 

118 Attribute value, if attribute does not exist then ``default`` is 

119 returned. 

120 """ 

121 raise NotImplementedError() 

122 

123 @abstractmethod 

124 def set(self, name: str, value: str, *, force: bool = False) -> None: 

125 """Set value for a given attribute. 

126 

127 Parameters 

128 ---------- 

129 name : `str` 

130 Attribute name, arbitrary non-empty string. 

131 value : `str` 

132 New value for an attribute, an arbitrary string. Due to 

133 deficiencies of some database engines we are not allowing empty 

134 strings to be stored in the database, and ``value`` cannot be an 

135 empty string. 

136 force : `bool`, optional 

137 Controls handling of existing attributes. With default `False` 

138 value an exception is raised if attribute ``name`` already exists, 

139 if `True` is passed then value of the existing attribute will be 

140 updated. 

141 

142 Raises 

143 ------ 

144 ButlerAttributeExistsError 

145 Raised if attribute already exists but ``force`` option is false. 

146 ValueError 

147 Raised if name or value parameters are empty. 

148 """ 

149 raise NotImplementedError() 

150 

151 @abstractmethod 

152 def delete(self, name: str) -> bool: 

153 """Delete an attribute. 

154 

155 Parameters 

156 ---------- 

157 name : `str` 

158 Attribute name, arbitrary non-empty string. 

159 

160 Returns 

161 ------- 

162 existed : `bool` 

163 `True` is returned if attribute existed before it was deleted. 

164 """ 

165 raise NotImplementedError() 

166 

167 @abstractmethod 

168 def items(self) -> Iterable[tuple[str, str]]: 

169 """Iterate over attributes and yield their names and values. 

170 

171 Yields 

172 ------ 

173 name : `str` 

174 Attribute name. 

175 value : `str` 

176 Corresponding attribute value. 

177 """ 

178 raise NotImplementedError() 

179 

180 @abstractmethod 

181 def empty(self) -> bool: 

182 """Check whether attributes set is empty. 

183 

184 Returns 

185 ------- 

186 empty : `bool` 

187 True if there are no any attributes defined. 

188 """ 

189 raise NotImplementedError() 

190 

191 @abstractmethod 

192 def clone(self, db: Database) -> ButlerAttributeManager: 

193 """Make an independent copy of this manager instance bound to a new 

194 `Database` instance. 

195 

196 Parameters 

197 ---------- 

198 db : `Database` 

199 New `Database` object to use when instantiating the manager. 

200 

201 Returns 

202 ------- 

203 instance : `ButlerAttributeManager` 

204 New manager instance with the same configuration as this instance, 

205 but bound to a new Database object. 

206 """ 

207 raise NotImplementedError()