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

23 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-12 10:56 -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 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/>. 

21from __future__ import annotations 

22 

23__all__ = [ 

24 "ButlerAttributeManager", 

25 "ButlerAttributeExistsError", 

26] 

27 

28from abc import abstractmethod 

29from collections.abc import Iterable 

30from typing import TYPE_CHECKING 

31 

32from ._versioning import VersionedExtension, VersionTuple 

33 

34if TYPE_CHECKING: 

35 from ._database import Database, StaticTablesContext 

36 

37 

38class ButlerAttributeExistsError(RuntimeError): 

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

40 specifying ``force`` option. 

41 """ 

42 

43 

44class ButlerAttributeManager(VersionedExtension): 

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

46 

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

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

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

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

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

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

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

54 

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

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

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

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

59 database table with a stable schema. 

60 """ 

61 

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

63 super().__init__(registry_schema_version=registry_schema_version) 

64 

65 @classmethod 

66 @abstractmethod 

67 def initialize( 

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

69 ) -> ButlerAttributeManager: 

70 """Construct an instance of the manager. 

71 

72 Parameters 

73 ---------- 

74 db : `Database` 

75 Interface to the underlying database engine and namespace. 

76 context : `StaticTablesContext` 

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

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

79 implemented with this manager. 

80 registry_schema_version : `VersionTuple` or `None` 

81 Schema version of this extension as defined in registry. 

82 

83 Returns 

84 ------- 

85 manager : `ButlerAttributeManager` 

86 An instance of `ButlerAttributeManager`. 

87 """ 

88 raise NotImplementedError() 

89 

90 @abstractmethod 

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

92 """Retrieve value of a given attribute. 

93 

94 Parameters 

95 ---------- 

96 name : `str` 

97 Attribute name, arbitrary non-empty string. 

98 default : `str`, optional 

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

100 string or `None`. 

101 

102 Returns 

103 ------- 

104 value : `str` 

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

106 returned. 

107 """ 

108 raise NotImplementedError() 

109 

110 @abstractmethod 

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

112 """Set value for a given attribute. 

113 

114 Parameters 

115 ---------- 

116 name : `str` 

117 Attribute name, arbitrary non-empty string. 

118 value : `str` 

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

120 deficiencies of some database engines we are not allowing empty 

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

122 empty string. 

123 force : `bool`, optional 

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

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

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

127 updated. 

128 

129 Raises 

130 ------ 

131 ButlerAttributeExistsError 

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

133 ValueError 

134 Raised if name or value parameters are empty. 

135 """ 

136 raise NotImplementedError() 

137 

138 @abstractmethod 

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

140 """Delete an attribute. 

141 

142 Parameters 

143 ---------- 

144 name : `str` 

145 Attribute name, arbitrary non-empty string. 

146 

147 Returns 

148 ------- 

149 existed : `bool` 

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

151 """ 

152 raise NotImplementedError() 

153 

154 @abstractmethod 

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

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

157 

158 Yields 

159 ------ 

160 name : `str` 

161 Attribute name. 

162 value : `str` 

163 Corresponding attribute value. 

164 """ 

165 raise NotImplementedError() 

166 

167 @abstractmethod 

168 def empty(self) -> bool: 

169 """Check whether attributes set is empty. 

170 

171 Returns 

172 ------- 

173 empty : `bool` 

174 True if there are no any attributes defined. 

175 """ 

176 raise NotImplementedError()