Coverage for python / lsst / daf / butler / registry / obscore / _config.py: 90%
88 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 08:55 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-22 08:55 +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/>.
28from __future__ import annotations
30__all__ = [
31 "ConfigCollectionType",
32 "DatasetTypeConfig",
33 "ExtraColumnConfig",
34 "ExtraColumnType",
35 "ObsCoreConfig",
36 "ObsCoreManagerConfig",
37 "SpatialPluginConfig",
38]
40import enum
41from typing import Any
43import pydantic
44from pydantic import StrictBool, StrictFloat, StrictInt, StrictStr
47class ExtraColumnType(str, enum.Enum):
48 """Enum class defining possible values for types of extra columns."""
50 bool = "bool"
51 int = "int"
52 float = "float"
53 string = "string"
56class ExtraColumnConfig(pydantic.BaseModel):
57 """Configuration class describing specification of additional column in
58 obscore table.
59 """
61 template: str
62 """Template string for formatting the column value."""
64 type: ExtraColumnType = ExtraColumnType.string
65 """Column type, formatted string will be converted to this actual type."""
67 length: int | None = None
68 """Optional length qualifier for a column, only used for strings."""
70 doc: str | None = None
71 """Documentation string for this column."""
74class DatasetTypeConfig(pydantic.BaseModel):
75 """Configuration describing dataset type-related options."""
77 dataproduct_type: str
78 """Value for the ``dataproduct_type`` column."""
80 dataproduct_subtype: str | None = None
81 """Value for the ``dataproduct_subtype`` column, optional."""
83 calib_level: int
84 """Value for the ``calib_level`` column."""
86 o_ucd: str | None = None
87 """Value for the ``o_ucd`` column, optional."""
89 access_format: str | None = None
90 """Value for the ``access_format`` column, optional."""
92 obs_id_fmt: str | None = None
93 """Format string for ``obs_id`` column, optional. Uses `str.format`
94 syntax.
95 """
97 datalink_url_fmt: str | None = None
98 """Format string for ``access_url`` column for DataLink."""
100 obs_collection: str | None = None
101 """Value for the ``obs_collection`` column, if specified it overrides
102 global value in `ObsCoreConfig`."""
104 s_xel: tuple[int, int] | None = None
105 """The number of pixels in the first and second dimension of the dataset
106 type.
107 """
109 extra_columns: (
110 None | (dict[str, StrictFloat | StrictInt | StrictBool | StrictStr | ExtraColumnConfig])
111 ) = None
112 """Description for additional columns, optional.
114 Keys are the names of the columns, values can be literal constants with the
115 values, or ExtraColumnConfig mappings."""
118class SpatialPluginConfig(pydantic.BaseModel):
119 """Configuration class for a spatial plugin."""
121 cls: str
122 """Name of the class implementing plugin methods."""
124 config: dict[str, Any] = pydantic.Field(default_factory=dict)
125 """Configuration object passed to plugin ``initialize()`` method."""
128class ObsCoreConfig(pydantic.BaseModel):
129 """Configuration which controls conversion of Registry datasets into
130 obscore records.
132 This configuration is a base class for ObsCore manager configuration class.
133 It can also be used by other tools that use `RecordFactory` to convert
134 datasets into obscore records.
135 """
137 collections: list[str] | None = None
138 """Registry collections to include, if missing then all collections are
139 used. Depending on implementation the name in the list can be either a
140 full collection name or a regular expression.
141 """
143 dataset_types: dict[str, DatasetTypeConfig]
144 """Per-dataset type configuration, key is the dataset type name."""
146 obs_collection: str | None = None
147 """Value for the ``obs_collection`` column. This can be overridden in
148 dataset type configuration.
149 """
151 facility_name: str
152 """Default value for the ``facility_name`` column. If an instrument
153 is listed in ``facility_map`` that will be used in preference but this
154 value must always be set as a fallback."""
156 facility_map: dict[str, str] = pydantic.Field(default_factory=dict)
157 """Mapping of instrument name to facility name. Takes precedence over
158 the ``facility_name``."""
160 extra_columns: (
161 None | (dict[str, StrictFloat | StrictInt | StrictBool | StrictStr | ExtraColumnConfig])
162 ) = None
163 """Description for additional columns, optional.
165 Keys are the names of the columns, values can be literal constants with the
166 values, or ExtraColumnConfig mappings."""
168 indices: dict[str, str | list[str]] | None = None
169 """Description of indices, key is the index name, value is the list of
170 column names or a single column name. The index name may not be used for
171 an actual index.
172 """
174 spectral_ranges: dict[str, tuple[float | None, float | None]] = {}
175 """Maps band name or filter name to a min/max of spectral range. One or
176 both ends can be specified as `None`.
177 """
179 spatial_plugins: dict[str, SpatialPluginConfig] = {}
180 """Optional configuration for plugins managing spatial columns and
181 indices. The key is an arbitrary name and the value is an object describing
182 plugin class and its configuration options. By default there is no spatial
183 indexing support, but a standard ``s_region`` column is always included.
184 """
186 fallback_instrument: str | None = None
187 """Instrument to use if a dataset type does not have an instrument
188 dimension. Will be left unset if `None`. Can be dangerous to set this
189 in a repository containing data from multiple instruments."""
191 obs_publisher_did_fmt: str | None = None
192 """Format string to generate an obs_publisher_did for a record. Assumes
193 that a single string is suitable for all results.
194 """
197class ConfigCollectionType(str, enum.Enum):
198 """Enum class defining possible values for configuration attributes."""
200 RUN = "RUN"
201 TAGGED = "TAGGED"
204class ObsCoreManagerConfig(ObsCoreConfig):
205 """Complete configuration for ObsCore manager."""
207 namespace: str = "daf_butler_obscore"
208 """Unique namespace to distinguish different instances, used for schema
209 migration purposes.
210 """
212 version: int
213 """Version of configuration, used for schema migration purposes. It needs
214 to be incremented on every change of configuration that causes a schema or
215 data migration.
216 """
218 table_name: str = "obscore"
219 """Name of the table for ObsCore records."""
221 collection_type: ConfigCollectionType
222 """Type of the collections that can appear in ``collections`` attribute.
224 When ``collection_type`` is ``RUN`` then ``collections`` contains regular
225 expressions that will be used to match RUN collections only. When
226 ``collection_type`` is ``TAGGED`` then ``collections`` must contain
227 exactly one collection name which must be TAGGED collection.
228 """
230 @pydantic.model_validator(mode="after")
231 def validate_collection_type(self) -> ObsCoreManagerConfig:
232 """Check that contents of ``collections`` is consistent with
233 ``collection_type``.
234 """
235 if self.collection_type is ConfigCollectionType.TAGGED:
236 collections: list[str] | None = self.collections
237 if collections is None or len(collections) != 1:
238 raise ValueError("'collections' must have one element when 'collection_type' is TAGGED")
239 return self