Coverage for python/lsst/daf/butler/registry/interfaces/_attributes.py: 97%
23 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-10-02 08:00 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-10-02 08:00 +0000
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 software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27from __future__ import annotations
29__all__ = [
30 "ButlerAttributeManager",
31 "ButlerAttributeExistsError",
32]
34from abc import abstractmethod
35from collections.abc import Iterable
36from typing import TYPE_CHECKING
38from ._versioning import VersionedExtension, VersionTuple
40if TYPE_CHECKING:
41 from ._database import Database, StaticTablesContext
44class ButlerAttributeExistsError(RuntimeError):
45 """Exception raised when trying to update existing attribute without
46 specifying ``force`` option.
47 """
50class ButlerAttributeManager(VersionedExtension):
51 """An interface for managing butler attributes in a `Registry`.
53 Attributes are represented in registry as a set of name-value pairs, both
54 have string type. Any non-string data types (e.g. integers) need to be
55 converted to/from strings on client side. Attribute names can be arbitrary
56 strings, no particular structure is enforced by this interface. Attribute
57 names are globally unique, to avoid potential collision clients should
58 follow some common convention for attribute names, e.g. dot-separated
59 components (``config.managers.opaque``).
61 One of the critical pieces of information that will be stored as
62 attribute is the version of database schema which needs to be known
63 before registry can do any operations on database. For that reasons it is
64 likely there will be only one implementation of this interface which uses
65 database table with a stable schema.
66 """
68 def __init__(self, *, registry_schema_version: VersionTuple | None = None) -> None:
69 super().__init__(registry_schema_version=registry_schema_version)
71 @classmethod
72 @abstractmethod
73 def initialize(
74 cls, db: Database, context: StaticTablesContext, registry_schema_version: VersionTuple | None = None
75 ) -> ButlerAttributeManager:
76 """Construct an instance of the manager.
78 Parameters
79 ----------
80 db : `Database`
81 Interface to the underlying database engine and namespace.
82 context : `StaticTablesContext`
83 Context object obtained from `Database.declareStaticTables`; used
84 to declare any tables that should always be present in a layer
85 implemented with this manager.
86 registry_schema_version : `VersionTuple` or `None`
87 Schema version of this extension as defined in registry.
89 Returns
90 -------
91 manager : `ButlerAttributeManager`
92 An instance of `ButlerAttributeManager`.
93 """
94 raise NotImplementedError()
96 @abstractmethod
97 def get(self, name: str, default: str | None = None) -> str | None:
98 """Retrieve value of a given attribute.
100 Parameters
101 ----------
102 name : `str`
103 Attribute name, arbitrary non-empty string.
104 default : `str`, optional
105 Default value returned when attribute does not exist, can be
106 string or `None`.
108 Returns
109 -------
110 value : `str`
111 Attribute value, if attribute does not exist then ``default`` is
112 returned.
113 """
114 raise NotImplementedError()
116 @abstractmethod
117 def set(self, name: str, value: str, *, force: bool = False) -> None:
118 """Set value for a given attribute.
120 Parameters
121 ----------
122 name : `str`
123 Attribute name, arbitrary non-empty string.
124 value : `str`
125 New value for an attribute, an arbitrary string. Due to
126 deficiencies of some database engines we are not allowing empty
127 strings to be stored in the database, and ``value`` cannot be an
128 empty string.
129 force : `bool`, optional
130 Controls handling of existing attributes. With default `False`
131 value an exception is raised if attribute ``name`` already exists,
132 if `True` is passed then value of the existing attribute will be
133 updated.
135 Raises
136 ------
137 ButlerAttributeExistsError
138 Raised if attribute already exists but ``force`` option is false.
139 ValueError
140 Raised if name or value parameters are empty.
141 """
142 raise NotImplementedError()
144 @abstractmethod
145 def delete(self, name: str) -> bool:
146 """Delete an attribute.
148 Parameters
149 ----------
150 name : `str`
151 Attribute name, arbitrary non-empty string.
153 Returns
154 -------
155 existed : `bool`
156 `True` is returned if attribute existed before it was deleted.
157 """
158 raise NotImplementedError()
160 @abstractmethod
161 def items(self) -> Iterable[tuple[str, str]]:
162 """Iterate over attributes and yield their names and values.
164 Yields
165 ------
166 name : `str`
167 Attribute name.
168 value : `str`
169 Corresponding attribute value.
170 """
171 raise NotImplementedError()
173 @abstractmethod
174 def empty(self) -> bool:
175 """Check whether attributes set is empty.
177 Returns
178 -------
179 empty : `bool`
180 True if there are no any attributes defined.
181 """
182 raise NotImplementedError()