Coverage for python/lsst/daf/butler/registry/interfaces/_attributes.py: 73%
28 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-25 02:05 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-25 02:05 -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
23__all__ = [
24 "ButlerAttributeManager",
25 "ButlerAttributeExistsError",
26]
28from abc import abstractmethod
29from typing import TYPE_CHECKING, Iterable, Optional, Tuple
31from ._versioning import VersionedExtension
33if TYPE_CHECKING: 33 ↛ 34line 33 didn't jump to line 34, because the condition on line 33 was never true
34 from ._database import Database, StaticTablesContext
37class ButlerAttributeExistsError(RuntimeError):
38 """Exception raised when trying to update existing attribute without
39 specifying ``force`` option.
40 """
43class ButlerAttributeManager(VersionedExtension):
44 """An interface for managing butler attributes in a `Registry`.
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``).
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 """
61 @classmethod
62 @abstractmethod
63 def initialize(cls, db: Database, context: StaticTablesContext) -> ButlerAttributeManager:
64 """Construct an instance of the manager.
66 Parameters
67 ----------
68 db : `Database`
69 Interface to the underlying database engine and namespace.
70 context : `StaticTablesContext`
71 Context object obtained from `Database.declareStaticTables`; used
72 to declare any tables that should always be present in a layer
73 implemented with this manager.
75 Returns
76 -------
77 manager : `ButlerAttributeManager`
78 An instance of `ButlerAttributeManager`.
79 """
80 raise NotImplementedError()
82 @abstractmethod
83 def get(self, name: str, default: Optional[str] = None) -> Optional[str]:
84 """Retrieve value of a given attribute.
86 Parameters
87 ----------
88 name : `str`
89 Attribute name, arbitrary non-empty string.
90 default : `str`, optional
91 Default value returned when attribute does not exist, can be
92 string or `None`.
94 Returns
95 -------
96 value : `str`
97 Attribute value, if attribute does not exist then ``default`` is
98 returned.
99 """
100 raise NotImplementedError()
102 @abstractmethod
103 def set(self, name: str, value: str, *, force: bool = False) -> None:
104 """Set value for a given attribute.
106 Parameters
107 ----------
108 name : `str`
109 Attribute name, arbitrary non-empty string.
110 value : `str`
111 New value for an attribute, an arbitrary string. Due to
112 deficiencies of some database engines we are not allowing empty
113 strings to be stored in the database, and ``value`` cannot be an
114 empty string.
115 force : `bool`, optional
116 Controls handling of existing attributes. With default `False`
117 value an exception is raised if attribute ``name`` already exists,
118 if `True` is passed then value of the existing attribute will be
119 updated.
121 Raises
122 ------
123 ButlerAttributeExistsError
124 Raised if attribute already exists but ``force`` option is false.
125 ValueError
126 Raised if name or value parameters are empty.
127 """
128 raise NotImplementedError()
130 @abstractmethod
131 def delete(self, name: str) -> bool:
132 """Delete an attribute.
134 Parameters
135 ----------
136 name : `str`
137 Attribute name, arbitrary non-empty string.
139 Returns
140 -------
141 existed : `bool`
142 `True` is returned if attribute existed before it was deleted.
143 """
144 raise NotImplementedError()
146 @abstractmethod
147 def items(self) -> Iterable[Tuple[str, str]]:
148 """Iterate over attributes and yield their names and values.
150 Yields
151 ------
152 name : `str`
153 Attribute name.
154 value : `str`
155 Corresponding attribute value.
156 """
157 raise NotImplementedError()
159 @abstractmethod
160 def empty(self) -> bool:
161 """Check whether attributes set is empty.
163 Returns
164 -------
165 empty : `bool`
166 True if there are no any attributes defined.
167 """
168 raise NotImplementedError()