Coverage for python/lsst/daf/butler/registry/queries/find_first_dataset.py: 71%
37 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-12 09:20 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-12 09:20 +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/>.
21from __future__ import annotations
23__all__ = ("FindFirstDataset",)
25import dataclasses
26from collections.abc import Sequence, Set
27from typing import final
29from lsst.daf.relation import ColumnTag, Relation, RowFilter, UnaryCommutator, UnaryOperationRelation
30from lsst.utils.classes import cached_getter
32from ...core import DatasetColumnTag, DimensionKeyColumnTag
35@final
36@dataclasses.dataclass(frozen=True)
37class FindFirstDataset(RowFilter):
38 """A custom relation operation that selects the first dataset from an
39 upstream relation according to its collection rank.
40 """
42 dimensions: Sequence[DimensionKeyColumnTag]
43 """Dimensions to group by while finding the first dataset within each group
44 (`~collections.abc.Sequence` [ `DimensionKeyColumnTag` ]).
45 """
47 rank: DatasetColumnTag
48 """Dataset rank column whose lowest per-group values should be selected
49 (`DatasetColumnTag`).
50 """
52 @property
53 @cached_getter
54 def columns_required(self) -> Set[ColumnTag]:
55 # Docstring inherited.
56 result: set[ColumnTag] = {self.rank}
57 result.update(self.dimensions)
58 return result
60 @property
61 def is_empty_invariant(self) -> bool:
62 # Docstring inherited.
63 return True
65 @property
66 def is_order_dependent(self) -> bool:
67 # Docstring inherited.
68 return False
70 def __str__(self) -> str:
71 return "find_first"
73 def applied_min_rows(self, target: Relation) -> int:
74 # Docstring inherited.
75 return 1 if target.min_rows else 0
77 def commute(self, current: UnaryOperationRelation) -> UnaryCommutator:
78 # Docstring inherited.
79 if not self.columns_required <= current.target.columns:
80 return UnaryCommutator(
81 first=None,
82 second=current.operation,
83 done=False,
84 messages=(
85 f"{current.target} is missing columns "
86 f"{set(self.columns_required - current.target.columns)}",
87 ),
88 )
89 if current.operation.is_count_dependent:
90 return UnaryCommutator(
91 first=None,
92 second=current.operation,
93 done=False,
94 messages=(f"{current.operation} is count-dependent",),
95 )
96 return UnaryCommutator(self, current.operation)