Coverage for python/lsst/daf/butler/registry/_defaults.py: 29%
53 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-17 09:33 +0000
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-17 09:33 +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 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/>.
22from __future__ import annotations
24__all__ = ("RegistryDefaults",)
26from collections.abc import Sequence
27from typing import TYPE_CHECKING, AbstractSet, Any, Optional
29from lsst.utils.classes import immutable
31from ..core import DataCoordinate
32from ._collection_summary import CollectionSummary
33from ._exceptions import MissingCollectionError
34from .wildcards import CollectionWildcard
36if TYPE_CHECKING:
37 from ._registry import Registry
40@immutable
41class RegistryDefaults:
42 """A struct used to provide the default collections searched or written to
43 by a `Registry` or `Butler` instance.
45 Parameters
46 ----------
47 collections : `str` or `Iterable` [ `str` ], optional
48 An expression specifying the collections to be searched (in order) when
49 reading datasets. If a default value for a governor dimension is not
50 given via ``**kwargs``, and exactly one value for that dimension
51 appears in the datasets in ``collections``, that value is also used as
52 the default for that dimension.
53 This may be a `str` collection name or an iterable thereof.
54 See :ref:`daf_butler_collection_expressions` for more information.
55 These collections are not registered automatically and must be
56 manually registered before they are used by any `Registry` or `Butler`
57 method, but they may be manually registered after a `Registry` or
58 `Butler` is initialized with this struct.
59 run : `str`, optional
60 Name of the `~CollectionType.RUN` collection new datasets should be
61 inserted into. If ``collections`` is `None` and ``run`` is not `None`,
62 ``collections`` will be set to ``[run]``. If not `None`, this
63 collection will automatically be registered when the default struct is
64 attached to a `Registry` instance.
65 infer : `bool`, optional
66 If `True` (default) infer default data ID values from the values
67 present in the datasets in ``collections``: if all collections have the
68 same value (or no value) for a governor dimension, that value will be
69 the default for that dimension. Nonexistent collections are ignored.
70 If a default value is provided explicitly for a governor dimension via
71 ``**kwargs``, no default will be inferred for that dimension.
72 **kwargs : `str`
73 Default data ID key-value pairs. These may only identify "governor"
74 dimensions like ``instrument`` and ``skymap``, though this is only
75 checked when the defaults struct is actually attached to a `Registry`.
76 """
78 def __init__(self, collections: Any = None, run: Optional[str] = None, infer: bool = True, **kwargs: str):
79 if collections is None:
80 if run is not None:
81 collections = (run,)
82 else:
83 collections = ()
84 self.collections = CollectionWildcard.from_expression(collections).require_ordered()
85 self.run = run
86 self._infer = infer
87 self._kwargs = kwargs
89 def __repr__(self) -> str:
90 collections = f"collections={self.collections!r}" if self.collections else ""
91 run = f"run={self.run!r}" if self.run else ""
92 if self._kwargs:
93 kwargs = ", ".join([f"{k}={v!r}" for k, v in self._kwargs.items()])
94 else:
95 kwargs = ""
96 args = ", ".join([arg for arg in (collections, run, kwargs) if arg])
97 return f"{type(self).__name__}({args})"
99 def finish(self, registry: Registry) -> None:
100 """Validate the defaults struct and standardize its data ID.
102 This should be called only by a `Registry` instance when the defaults
103 struct is first associated with it.
105 Parameters
106 ----------
107 registry : `Registry`
108 Registry instance these defaults are being attached to.
110 Raises
111 ------
112 TypeError
113 Raised if a non-governor dimension was included in ``**kwargs``
114 at construction.
115 """
116 allGovernorDimensions = registry.dimensions.getGovernorDimensions()
117 if not self._kwargs.keys() <= allGovernorDimensions.names:
118 raise TypeError(
119 "Only governor dimensions may be identified by a default data "
120 f"ID, not {self._kwargs.keys() - allGovernorDimensions.names}. "
121 "(These may just be unrecognized keyword arguments passed at "
122 "Butler construction.)"
123 )
124 if self._infer and not self._kwargs.keys() == allGovernorDimensions.names:
125 summaries = []
126 for collection in self.collections:
127 try:
128 summaries.append(registry.getCollectionSummary(collection))
129 except MissingCollectionError:
130 pass
131 if summaries:
132 summary = CollectionSummary.union(*summaries)
133 for dimensionName in allGovernorDimensions.names - self._kwargs.keys():
134 values: AbstractSet[str] = summary.governors.get(dimensionName, frozenset())
135 if len(values) == 1:
136 (value,) = values
137 self._kwargs[dimensionName] = value
138 self.dataId = registry.expandDataId(self._kwargs, withDefaults=False)
140 collections: Sequence[str]
141 """The collections to search by default, in order (`Sequence` [ `str` ]).
142 """
144 run: Optional[str]
145 """Name of the run this butler writes outputs to by default (`str` or
146 `None`).
147 """
149 dataId: DataCoordinate
150 """The default data ID (`DataCoordinate`).
152 Dimensions without defaults are simply not included. Only governor
153 dimensions are ever included in defaults.
155 This attribute may not be accessed before the defaults struct is
156 attached to a `Registry` instance. It always satisfies both ``hasFull``
157 and ``hasRecords``.
158 """