Coverage for python/lsst/daf/butler/registry/interfaces/_obscore.py: 65%
41 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-23 02:06 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-23 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
23"""Interfaces for classes that manage obscore table(s) in a `Registry`.
24"""
26__all__ = ["ObsCoreTableManager"]
28from abc import abstractmethod
29from collections.abc import Iterable, Iterator, Mapping
30from contextlib import contextmanager
31from typing import TYPE_CHECKING, Any, Type
33import sqlalchemy
35from ._versioning import VersionedExtension
37if TYPE_CHECKING: 37 ↛ 38line 37 didn't jump to line 38, because the condition on line 37 was never true
38 from lsst.sphgeom import Region
40 from ...core import DatasetRef, DimensionUniverse
41 from ..queries import SqlQueryContext
42 from ._collections import CollectionRecord
43 from ._database import Database, StaticTablesContext
44 from ._datasets import DatasetRecordStorageManager
45 from ._dimensions import DimensionRecordStorageManager
48class ObsCoreTableManager(VersionedExtension):
49 """An interface for populating ObsCore tables(s)."""
51 @classmethod
52 @abstractmethod
53 def initialize(
54 cls,
55 db: Database,
56 context: StaticTablesContext,
57 *,
58 universe: DimensionUniverse,
59 config: Mapping,
60 datasets: Type[DatasetRecordStorageManager],
61 dimensions: DimensionRecordStorageManager,
62 ) -> ObsCoreTableManager:
63 """Construct an instance of the manager.
65 Parameters
66 ----------
67 db : `Database`
68 Interface to the underlying database engine and namespace.
69 context : `StaticTablesContext`
70 Context object obtained from `Database.declareStaticTables`; used
71 to declare any tables that should always be present in a layer
72 implemented with this manager.
73 universe : `DimensionUniverse`
74 All dimensions known to the registry.
75 config : `dict` [ `str`, `Any` ]
76 Configuration of the obscore manager.
77 datasets : `type`
78 Type of dataset manager.
79 dimensions: `DimensionRecordStorageManager`
80 Manager for Registry dimensions.
82 Returns
83 -------
84 manager : `ObsCoreTableManager`
85 An instance of a concrete `ObsCoreTableManager` subclass.
86 """
87 raise NotImplementedError()
89 @abstractmethod
90 def config_json(self) -> str:
91 """Dump configuration in JSON format.
93 Returns
94 -------
95 json : `str`
96 Configuration serialized in JSON format.
97 """
98 raise NotImplementedError()
100 @abstractmethod
101 def add_datasets(self, refs: Iterable[DatasetRef], context: SqlQueryContext) -> int:
102 """Possibly add datasets to the obscore table.
104 This method should be called when new datasets are added to a RUN
105 collection.
107 Parameters
108 ----------
109 refs : `iterable` [ `DatasetRef` ]
110 Dataset refs to add. Dataset refs have to be completely expanded.
111 If a record with the same dataset ID is already in obscore table,
112 the dataset is ignored.
113 context : `SqlQueryContext`
114 Context used to execute queries for additional dimension metadata.
116 Returns
117 -------
118 count : `int`
119 Actual number of records inserted into obscore table.
121 Notes
122 -----
123 Dataset data types and collection names are checked against configured
124 list of collections and dataset types, non-matching datasets are
125 ignored and not added to the obscore table.
127 When configuration parameter ``collection_type`` is not "RUN", this
128 method should return immediately.
130 Note that there is no matching method to remove datasets from obscore
131 table, we assume that removal happens via foreign key constraint to
132 dataset table with "ON DELETE CASCADE" option.
133 """
134 raise NotImplementedError()
136 @abstractmethod
137 def associate(
138 self, refs: Iterable[DatasetRef], collection: CollectionRecord, context: SqlQueryContext
139 ) -> int:
140 """Possibly add datasets to the obscore table.
142 This method should be called when existing datasets are associated with
143 a TAGGED collection.
145 Parameters
146 ----------
147 refs : `iterable` [ `DatasetRef` ]
148 Dataset refs to add. Dataset refs have to be completely expanded.
149 If a record with the same dataset ID is already in obscore table,
150 the dataset is ignored.
151 collection : `CollectionRecord`
152 Collection record for a TAGGED collection.
153 context : `SqlQueryContext`
154 Context used to execute queries for additional dimension metadata.
156 Returns
157 -------
158 count : `int`
159 Actual number of records inserted into obscore table.
161 Notes
162 -----
163 Dataset data types and collection names are checked against configured
164 list of collections and dataset types, non-matching datasets are
165 ignored and not added to the obscore table.
167 When configuration parameter ``collection_type`` is not "TAGGED", this
168 method should return immediately.
169 """
170 raise NotImplementedError()
172 @abstractmethod
173 def disassociate(self, refs: Iterable[DatasetRef], collection: CollectionRecord) -> int:
174 """Possibly remove datasets from the obscore table.
176 This method should be called when datasets are disassociated from a
177 TAGGED collection.
179 Parameters
180 ----------
181 refs : `iterable` [ `DatasetRef` ]
182 Dataset refs to remove. Dataset refs have to be resolved.
183 collection : `CollectionRecord`
184 Collection record for a TAGGED collection.
186 Returns
187 -------
188 count : `int`
189 Actual number of records removed from obscore table.
191 Notes
192 -----
193 Dataset data types and collection names are checked against configured
194 list of collections and dataset types, non-matching datasets are
195 ignored and not added to the obscore table.
197 When configuration parameter ``collection_type`` is not "TAGGED", this
198 method should return immediately.
199 """
200 raise NotImplementedError()
202 @abstractmethod
203 def update_exposure_regions(self, instrument: str, region_data: Iterable[tuple[int, int, Region]]) -> int:
204 """Update existing exposure records with spatial region data.
206 Parameters
207 ----------
208 instrument : `str`
209 Instrument name.
210 region_data : `Iterable`[`tuple`[`int`, `int`, `~lsst.sphgeom.Region`]]
211 Sequence of tuples, each tuple contains three values - exposure ID,
212 detector ID, and corresponding region.
214 Returns
215 -------
216 count : `int`
217 Actual number of records updated.
219 Notes
220 -----
221 This method is needed to update obscore records for raw exposures which
222 are ingested before their corresponding visits are defined. Exposure
223 records added when visit is already defined will get their regions
224 from their matching visits automatically.
225 """
226 raise NotImplementedError()
228 @abstractmethod
229 @contextmanager
230 def query(self, **kwargs: Any) -> Iterator[sqlalchemy.engine.CursorResult]:
231 """Run a SELECT query against obscore table and return result rows.
233 Parameters
234 ----------
235 **kwargs
236 Restriction on values of individual obscore columns. Key is the
237 column name, value is the required value of the column. Multiple
238 restrictions are ANDed together.
240 Returns
241 -------
242 result_context : `sqlalchemy.engine.CursorResult`
243 Context manager that returns the query result object when entered.
244 These results are invalidated when the context is exited.
246 Notes
247 -----
248 This method is intended mostly for tests that need to check the
249 contents of obscore table.
250 """
251 raise NotImplementedError()