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

22 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-04-04 02:06 -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 typing import TYPE_CHECKING, Iterable, Optional, Tuple 

30 

31from ._versioning import VersionedExtension, VersionTuple 

32 

33if TYPE_CHECKING: 

34 from ._database import Database, StaticTablesContext 

35 

36 

37class ButlerAttributeExistsError(RuntimeError): 

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

39 specifying ``force`` option. 

40 """ 

41 

42 

43class ButlerAttributeManager(VersionedExtension): 

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

45 

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

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

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

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

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

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

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

53 

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

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

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

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

58 database table with a stable schema. 

59 """ 

60 

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

62 super().__init__(registry_schema_version=registry_schema_version) 

63 

64 @classmethod 

65 @abstractmethod 

66 def initialize( 

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

68 ) -> ButlerAttributeManager: 

69 """Construct an instance of the manager. 

70 

71 Parameters 

72 ---------- 

73 db : `Database` 

74 Interface to the underlying database engine and namespace. 

75 context : `StaticTablesContext` 

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

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

78 implemented with this manager. 

79 registry_schema_version : `VersionTuple` or `None` 

80 Schema version of this extension as defined in registry. 

81 

82 Returns 

83 ------- 

84 manager : `ButlerAttributeManager` 

85 An instance of `ButlerAttributeManager`. 

86 """ 

87 raise NotImplementedError() 

88 

89 @abstractmethod 

90 def get(self, name: str, default: Optional[str] = None) -> Optional[str]: 

91 """Retrieve value of a given attribute. 

92 

93 Parameters 

94 ---------- 

95 name : `str` 

96 Attribute name, arbitrary non-empty string. 

97 default : `str`, optional 

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

99 string or `None`. 

100 

101 Returns 

102 ------- 

103 value : `str` 

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

105 returned. 

106 """ 

107 raise NotImplementedError() 

108 

109 @abstractmethod 

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

111 """Set value for a given attribute. 

112 

113 Parameters 

114 ---------- 

115 name : `str` 

116 Attribute name, arbitrary non-empty string. 

117 value : `str` 

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

119 deficiencies of some database engines we are not allowing empty 

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

121 empty string. 

122 force : `bool`, optional 

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

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

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

126 updated. 

127 

128 Raises 

129 ------ 

130 ButlerAttributeExistsError 

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

132 ValueError 

133 Raised if name or value parameters are empty. 

134 """ 

135 raise NotImplementedError() 

136 

137 @abstractmethod 

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

139 """Delete an attribute. 

140 

141 Parameters 

142 ---------- 

143 name : `str` 

144 Attribute name, arbitrary non-empty string. 

145 

146 Returns 

147 ------- 

148 existed : `bool` 

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

150 """ 

151 raise NotImplementedError() 

152 

153 @abstractmethod 

154 def items(self) -> Iterable[Tuple[str, str]]: 

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

156 

157 Yields 

158 ------ 

159 name : `str` 

160 Attribute name. 

161 value : `str` 

162 Corresponding attribute value. 

163 """ 

164 raise NotImplementedError() 

165 

166 @abstractmethod 

167 def empty(self) -> bool: 

168 """Check whether attributes set is empty. 

169 

170 Returns 

171 ------- 

172 empty : `bool` 

173 True if there are no any attributes defined. 

174 """ 

175 raise NotImplementedError()