Coverage for python / lsst / pipe / base / quantum_graph / formatter.py: 86%
52 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-13 01:29 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-13 01:29 -0800
1# This file is part of pipe_base.
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__ = ("ProvenanceFormatter",)
32import uuid
33from typing import Any, ClassVar
35import pydantic
37from lsst.daf.butler import FormatterV2
38from lsst.resources import ResourcePath
39from lsst.utils.logging import getLogger
41from ..pipeline_graph import TaskImportMode
42from ._provenance import ProvenanceQuantumGraphReader
44_LOG = getLogger(__file__)
47class _ProvenanceFormatterParameters(pydantic.BaseModel):
48 """A Pydantic model for validating and applying defaults to the
49 read parameters of `ProvenanceFormatter`.
50 """
52 import_mode: TaskImportMode = TaskImportMode.DO_NOT_IMPORT
53 quanta: list[uuid.UUID] | None = None
54 datasets: list[uuid.UUID] | None = None
55 read_init_quanta: bool = True
57 @pydantic.field_validator("quanta", mode="before")
58 @classmethod
59 def quanta_to_list(cls, v: Any) -> list[uuid.UUID]:
60 return list(v)
62 @pydantic.field_validator("datasets", mode="before")
63 @classmethod
64 def datasets_to_list(cls, v: Any) -> list[uuid.UUID]:
65 return list(v)
67 @property
68 def nodes(self) -> list[uuid.UUID]:
69 if self.quanta is not None: 69 ↛ 74line 69 didn't jump to line 74 because the condition on line 69 was always true
70 if self.datasets is not None: 70 ↛ 73line 70 didn't jump to line 73 because the condition on line 70 was always true
71 return self.quanta + self.datasets
72 else:
73 return self.quanta
74 elif self.datasets is not None:
75 return self.datasets
76 raise ValueError("'datasets' and/or 'quanta' parameters are required for this component")
79class ProvenanceFormatter(FormatterV2):
80 """Butler interface for reading `ProvenanceQuantumGraph` objects."""
82 default_extension: ClassVar[str] = ".qg"
83 can_read_from_uri: ClassVar[bool] = True
85 def read_from_uri(self, uri: ResourcePath, component: str | None = None, expected_size: int = -1) -> Any:
86 parameters = _ProvenanceFormatterParameters.model_validate(self.file_descriptor.parameters or {})
87 with ProvenanceQuantumGraphReader.open(uri, import_mode=parameters.import_mode) as reader:
88 match component:
89 case None:
90 if parameters.read_init_quanta: 90 ↛ 92line 90 didn't jump to line 92 because the condition on line 90 was always true
91 reader.read_init_quanta()
92 reader.read_quanta(parameters.quanta)
93 reader.read_datasets(parameters.datasets)
94 return reader.graph
95 case "metadata":
96 return reader.fetch_metadata(parameters.nodes)
97 case "logs":
98 return reader.fetch_logs(parameters.nodes)
99 case "packages":
100 return reader.fetch_packages()
101 raise AssertionError(f"Unexpected component {component!r}.")