Hide keyboard shortcuts

Hot-keys 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

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 ABC, abstractmethod 

29from typing import ( 

30 Iterable, 

31 Optional, 

32 Tuple, 

33 TYPE_CHECKING, 

34) 

35 

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

37 from ._database import Database, StaticTablesContext 

38 

39 

40class ButlerAttributeExistsError(RuntimeError): 

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

42 specifying ``force`` option. 

43 """ 

44 

45 

46class ButlerAttributeManager(ABC): 

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

48 

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

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

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

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

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

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

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

56 

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

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

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

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

61 database table with a stable schema. 

62 """ 

63 

64 @classmethod 

65 @abstractmethod 

66 def initialize(cls, db: Database, context: StaticTablesContext) -> ButlerAttributeManager: 

67 """Construct an instance of the manager. 

68 

69 Parameters 

70 ---------- 

71 db : `Database` 

72 Interface to the underlying database engine and namespace. 

73 context : `StaticTablesContext` 

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

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

76 implemented with this manager. 

77 

78 Returns 

79 ------- 

80 manager : `ButlerAttributeManager` 

81 An instance of `ButlerAttributeManager`. 

82 """ 

83 raise NotImplementedError() 

84 

85 @abstractmethod 

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

87 """Retrieve value of a given attribute. 

88 

89 Parameters 

90 ---------- 

91 name : `str` 

92 Attribute name, arbitrary non-empty string. 

93 default : `str`, optional 

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

95 string or `None`. 

96 

97 Returns 

98 ------- 

99 value : `str` 

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

101 returned. 

102 """ 

103 raise NotImplementedError() 

104 

105 @abstractmethod 

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

107 """Set value for a given attribute. 

108 

109 Parameters 

110 ---------- 

111 name : `str` 

112 Attribute name, arbitrary non-empty string. 

113 value : `str` 

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

115 deficiencies of some database engines we are not allowing empty 

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

117 empty string. 

118 force : `bool`, optional 

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

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

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

122 updated. 

123 

124 Raises 

125 ------ 

126 ButlerAttributeExistsError 

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

128 ValueError 

129 Raised if name or value parameters are empty. 

130 """ 

131 raise NotImplementedError() 

132 

133 @abstractmethod 

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

135 """Delete an attribute. 

136 

137 Parameters 

138 ---------- 

139 name : `str` 

140 Attribute name, arbitrary non-empty string. 

141 

142 Returns 

143 ------- 

144 existed : `bool` 

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

146 """ 

147 raise NotImplementedError() 

148 

149 @abstractmethod 

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

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

152 

153 Yields 

154 ------ 

155 name : `str` 

156 Attribute name. 

157 value : `str` 

158 Corresponding attribute value. 

159 """ 

160 raise NotImplementedError()