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

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

28 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/>. 

21from __future__ import annotations 

22 

23__all__ = [ 

24 "ButlerAttributeManager", 

25 "ButlerAttributeExistsError", 

26] 

27 

28from abc import abstractmethod 

29from typing import ( 

30 Iterable, 

31 Optional, 

32 Tuple, 

33 TYPE_CHECKING, 

34) 

35 

36from ._versioning import VersionedExtension 

37 

38if TYPE_CHECKING: 38 ↛ 39line 38 didn't jump to line 39, because the condition on line 38 was never true

39 from ._database import Database, StaticTablesContext 

40 

41 

42class ButlerAttributeExistsError(RuntimeError): 

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

44 specifying ``force`` option. 

45 """ 

46 

47 

48class ButlerAttributeManager(VersionedExtension): 

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

50 

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

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

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

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

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

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

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

58 

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

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

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

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

63 database table with a stable schema. 

64 """ 

65 

66 @classmethod 

67 @abstractmethod 

68 def initialize(cls, db: Database, context: StaticTablesContext) -> 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 

80 Returns 

81 ------- 

82 manager : `ButlerAttributeManager` 

83 An instance of `ButlerAttributeManager`. 

84 """ 

85 raise NotImplementedError() 

86 

87 @abstractmethod 

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

89 """Retrieve value of a given attribute. 

90 

91 Parameters 

92 ---------- 

93 name : `str` 

94 Attribute name, arbitrary non-empty string. 

95 default : `str`, optional 

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

97 string or `None`. 

98 

99 Returns 

100 ------- 

101 value : `str` 

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

103 returned. 

104 """ 

105 raise NotImplementedError() 

106 

107 @abstractmethod 

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

109 """Set value for a given attribute. 

110 

111 Parameters 

112 ---------- 

113 name : `str` 

114 Attribute name, arbitrary non-empty string. 

115 value : `str` 

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

117 deficiencies of some database engines we are not allowing empty 

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

119 empty string. 

120 force : `bool`, optional 

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

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

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

124 updated. 

125 

126 Raises 

127 ------ 

128 ButlerAttributeExistsError 

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

130 ValueError 

131 Raised if name or value parameters are empty. 

132 """ 

133 raise NotImplementedError() 

134 

135 @abstractmethod 

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

137 """Delete an attribute. 

138 

139 Parameters 

140 ---------- 

141 name : `str` 

142 Attribute name, arbitrary non-empty string. 

143 

144 Returns 

145 ------- 

146 existed : `bool` 

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

148 """ 

149 raise NotImplementedError() 

150 

151 @abstractmethod 

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

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

154 

155 Yields 

156 ------ 

157 name : `str` 

158 Attribute name. 

159 value : `str` 

160 Corresponding attribute value. 

161 """ 

162 raise NotImplementedError() 

163 

164 @abstractmethod 

165 def empty(self) -> bool: 

166 """Check whether attributes set is empty. 

167 

168 Returns 

169 ------- 

170 empty : `bool` 

171 True if there are no any attributes defined. 

172 """ 

173 raise NotImplementedError()