lsst-pipe-base 30.0.0rc3__py3-none-any.whl → 30.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lsst/pipe/base/_instrument.py +25 -15
- lsst/pipe/base/_quantumContext.py +3 -3
- lsst/pipe/base/_status.py +43 -10
- lsst/pipe/base/_task_metadata.py +2 -2
- lsst/pipe/base/all_dimensions_quantum_graph_builder.py +8 -3
- lsst/pipe/base/automatic_connection_constants.py +20 -1
- lsst/pipe/base/cli/cmd/__init__.py +18 -2
- lsst/pipe/base/cli/cmd/commands.py +149 -4
- lsst/pipe/base/connectionTypes.py +72 -160
- lsst/pipe/base/connections.py +6 -9
- lsst/pipe/base/execution_reports.py +0 -5
- lsst/pipe/base/graph/graph.py +11 -10
- lsst/pipe/base/graph/quantumNode.py +4 -4
- lsst/pipe/base/graph_walker.py +8 -10
- lsst/pipe/base/log_capture.py +1 -1
- lsst/pipe/base/log_on_close.py +4 -7
- lsst/pipe/base/pipeline.py +5 -6
- lsst/pipe/base/pipelineIR.py +2 -8
- lsst/pipe/base/pipelineTask.py +5 -7
- lsst/pipe/base/pipeline_graph/_dataset_types.py +2 -2
- lsst/pipe/base/pipeline_graph/_edges.py +32 -22
- lsst/pipe/base/pipeline_graph/_mapping_views.py +4 -7
- lsst/pipe/base/pipeline_graph/_pipeline_graph.py +14 -7
- lsst/pipe/base/pipeline_graph/expressions.py +2 -2
- lsst/pipe/base/pipeline_graph/io.py +7 -10
- lsst/pipe/base/pipeline_graph/visualization/_dot.py +13 -12
- lsst/pipe/base/pipeline_graph/visualization/_layout.py +16 -18
- lsst/pipe/base/pipeline_graph/visualization/_merge.py +4 -7
- lsst/pipe/base/pipeline_graph/visualization/_printer.py +10 -10
- lsst/pipe/base/pipeline_graph/visualization/_status_annotator.py +7 -0
- lsst/pipe/base/prerequisite_helpers.py +2 -1
- lsst/pipe/base/quantum_graph/_common.py +15 -17
- lsst/pipe/base/quantum_graph/_multiblock.py +36 -20
- lsst/pipe/base/quantum_graph/_predicted.py +7 -3
- lsst/pipe/base/quantum_graph/_provenance.py +501 -61
- lsst/pipe/base/quantum_graph/aggregator/__init__.py +0 -1
- lsst/pipe/base/quantum_graph/aggregator/_communicators.py +187 -240
- lsst/pipe/base/quantum_graph/aggregator/_config.py +87 -9
- lsst/pipe/base/quantum_graph/aggregator/_ingester.py +13 -12
- lsst/pipe/base/quantum_graph/aggregator/_scanner.py +15 -7
- lsst/pipe/base/quantum_graph/aggregator/_structs.py +3 -3
- lsst/pipe/base/quantum_graph/aggregator/_supervisor.py +19 -34
- lsst/pipe/base/quantum_graph/aggregator/_workers.py +303 -0
- lsst/pipe/base/quantum_graph/aggregator/_writer.py +3 -3
- lsst/pipe/base/quantum_graph/formatter.py +74 -4
- lsst/pipe/base/quantum_graph/ingest_graph.py +413 -0
- lsst/pipe/base/quantum_graph/visualization.py +5 -1
- lsst/pipe/base/quantum_graph_builder.py +21 -8
- lsst/pipe/base/quantum_graph_skeleton.py +31 -29
- lsst/pipe/base/quantum_provenance_graph.py +29 -12
- lsst/pipe/base/separable_pipeline_executor.py +1 -1
- lsst/pipe/base/single_quantum_executor.py +15 -8
- lsst/pipe/base/struct.py +4 -0
- lsst/pipe/base/testUtils.py +3 -3
- lsst/pipe/base/tests/mocks/_storage_class.py +2 -1
- lsst/pipe/base/version.py +1 -1
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/METADATA +3 -3
- lsst_pipe_base-30.0.1.dist-info/RECORD +129 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/WHEEL +1 -1
- lsst_pipe_base-30.0.0rc3.dist-info/RECORD +0 -127
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/entry_points.txt +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/licenses/COPYRIGHT +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/licenses/LICENSE +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/licenses/bsd_license.txt +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/licenses/gpl-v3.0.txt +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/top_level.txt +0 -0
- {lsst_pipe_base-30.0.0rc3.dist-info → lsst_pipe_base-30.0.1.dist-info}/zip-safe +0 -0
|
@@ -50,9 +50,7 @@ from typing import (
|
|
|
50
50
|
TYPE_CHECKING,
|
|
51
51
|
Any,
|
|
52
52
|
Self,
|
|
53
|
-
TypeAlias,
|
|
54
53
|
TypedDict,
|
|
55
|
-
TypeVar,
|
|
56
54
|
)
|
|
57
55
|
|
|
58
56
|
import networkx
|
|
@@ -81,18 +79,16 @@ if TYPE_CHECKING:
|
|
|
81
79
|
# These aliases make it a lot easier how the various pydantic models are
|
|
82
80
|
# structured, but they're too verbose to be worth exporting to code outside the
|
|
83
81
|
# quantum_graph subpackage.
|
|
84
|
-
TaskLabel
|
|
85
|
-
DatasetTypeName
|
|
86
|
-
ConnectionName
|
|
87
|
-
DatasetIndex
|
|
88
|
-
QuantumIndex
|
|
89
|
-
DatastoreName
|
|
90
|
-
DimensionElementName
|
|
91
|
-
DataCoordinateValues
|
|
82
|
+
type TaskLabel = str
|
|
83
|
+
type DatasetTypeName = str
|
|
84
|
+
type ConnectionName = str
|
|
85
|
+
type DatasetIndex = int
|
|
86
|
+
type QuantumIndex = int
|
|
87
|
+
type DatastoreName = str
|
|
88
|
+
type DimensionElementName = str
|
|
89
|
+
type DataCoordinateValues = list[DataIdValue]
|
|
92
90
|
|
|
93
91
|
|
|
94
|
-
_T = TypeVar("_T", bound=pydantic.BaseModel)
|
|
95
|
-
|
|
96
92
|
FORMAT_VERSION: int = 1
|
|
97
93
|
"""
|
|
98
94
|
File format version number for new files.
|
|
@@ -453,8 +449,10 @@ class BaseQuantumGraphWriter:
|
|
|
453
449
|
cdict_data: bytes | None = None,
|
|
454
450
|
zstd_level: int = 10,
|
|
455
451
|
) -> Iterator[Self]:
|
|
456
|
-
uri = ResourcePath(uri)
|
|
452
|
+
uri = ResourcePath(uri, forceDirectory=False)
|
|
457
453
|
address_writer = AddressWriter()
|
|
454
|
+
if uri.isLocal:
|
|
455
|
+
os.makedirs(uri.dirname().ospath, exist_ok=True)
|
|
458
456
|
cdict = zstandard.ZstdCompressionDict(cdict_data) if cdict_data is not None else None
|
|
459
457
|
compressor = zstandard.ZstdCompressor(level=zstd_level, dict_data=cdict)
|
|
460
458
|
with uri.open(mode="wb") as stream:
|
|
@@ -595,9 +593,9 @@ class BaseQuantumGraphReader:
|
|
|
595
593
|
)
|
|
596
594
|
|
|
597
595
|
@staticmethod
|
|
598
|
-
def _read_single_block_static(
|
|
599
|
-
name: str, model_type: type[
|
|
600
|
-
) ->
|
|
596
|
+
def _read_single_block_static[T: pydantic.BaseModel](
|
|
597
|
+
name: str, model_type: type[T], zf: zipfile.ZipFile, decompressor: Decompressor
|
|
598
|
+
) -> T:
|
|
601
599
|
"""Read a single compressed JSON block from a 'file' in a zip archive.
|
|
602
600
|
|
|
603
601
|
Parameters
|
|
@@ -620,7 +618,7 @@ class BaseQuantumGraphReader:
|
|
|
620
618
|
json_data = decompressor.decompress(compressed_data)
|
|
621
619
|
return model_type.model_validate_json(json_data)
|
|
622
620
|
|
|
623
|
-
def _read_single_block(self, name: str, model_type: type[
|
|
621
|
+
def _read_single_block[T: pydantic.BaseModel](self, name: str, model_type: type[T]) -> T:
|
|
624
622
|
"""Read a single compressed JSON block from a 'file' in a zip archive.
|
|
625
623
|
|
|
626
624
|
Parameters
|
|
@@ -43,25 +43,22 @@ import dataclasses
|
|
|
43
43
|
import logging
|
|
44
44
|
import tempfile
|
|
45
45
|
import uuid
|
|
46
|
-
|
|
46
|
+
import zipfile
|
|
47
|
+
from collections.abc import Iterator, Set
|
|
47
48
|
from contextlib import contextmanager
|
|
48
49
|
from io import BufferedReader, BytesIO
|
|
49
50
|
from operator import attrgetter
|
|
50
|
-
from typing import IO,
|
|
51
|
+
from typing import IO, Protocol, TypeVar
|
|
51
52
|
|
|
52
53
|
import pydantic
|
|
53
54
|
|
|
54
|
-
if TYPE_CHECKING:
|
|
55
|
-
import zipfile
|
|
56
|
-
|
|
57
|
-
|
|
58
55
|
_LOG = logging.getLogger(__name__)
|
|
59
56
|
|
|
60
57
|
|
|
61
58
|
_T = TypeVar("_T", bound=pydantic.BaseModel)
|
|
62
59
|
|
|
63
60
|
|
|
64
|
-
UUID_int
|
|
61
|
+
type UUID_int = int
|
|
65
62
|
|
|
66
63
|
MAX_UUID_INT: UUID_int = 2**128
|
|
67
64
|
|
|
@@ -77,7 +74,7 @@ individual quanta (especially for execution).
|
|
|
77
74
|
|
|
78
75
|
|
|
79
76
|
class Compressor(Protocol):
|
|
80
|
-
"""A protocol for objects with a
|
|
77
|
+
"""A protocol for objects with a ``compress`` method that takes and returns
|
|
81
78
|
`bytes`.
|
|
82
79
|
"""
|
|
83
80
|
|
|
@@ -208,11 +205,11 @@ class AddressWriter:
|
|
|
208
205
|
addresses: list[dict[uuid.UUID, Address]] = dataclasses.field(default_factory=list)
|
|
209
206
|
"""Addresses to store with each UUID.
|
|
210
207
|
|
|
211
|
-
Every key in one of these dictionaries must have an entry in
|
|
208
|
+
Every key in one of these dictionaries must have an entry in ``indices``.
|
|
212
209
|
The converse is not true.
|
|
213
210
|
"""
|
|
214
211
|
|
|
215
|
-
def write(self, stream: IO[bytes], int_size: int) -> None:
|
|
212
|
+
def write(self, stream: IO[bytes], int_size: int, all_ids: Set[uuid.UUID] | None = None) -> None:
|
|
216
213
|
"""Write all addresses to a file-like object.
|
|
217
214
|
|
|
218
215
|
Parameters
|
|
@@ -221,15 +218,17 @@ class AddressWriter:
|
|
|
221
218
|
Binary file-like object.
|
|
222
219
|
int_size : `int`
|
|
223
220
|
Number of bytes to use for all integers.
|
|
221
|
+
all_ids : `~collections.abc.Set` [`uuid.UUID`], optional
|
|
222
|
+
Set of the union of all UUIDs in any dictionary from a call to
|
|
223
|
+
`get_all_ids`.
|
|
224
224
|
"""
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
indices.update(address_map.keys())
|
|
225
|
+
if all_ids is None:
|
|
226
|
+
all_ids = self.get_all_ids()
|
|
228
227
|
stream.write(int_size.to_bytes(1))
|
|
229
|
-
stream.write(len(
|
|
228
|
+
stream.write(len(all_ids).to_bytes(int_size))
|
|
230
229
|
stream.write(len(self.addresses).to_bytes(int_size))
|
|
231
230
|
empty_address = Address()
|
|
232
|
-
for n, key in enumerate(sorted(
|
|
231
|
+
for n, key in enumerate(sorted(all_ids, key=attrgetter("int"))):
|
|
233
232
|
row = AddressRow(key, n, [m.get(key, empty_address) for m in self.addresses])
|
|
234
233
|
_LOG.debug("Wrote address %s.", row)
|
|
235
234
|
row.write(stream, int_size)
|
|
@@ -246,8 +245,25 @@ class AddressWriter:
|
|
|
246
245
|
int_size : `int`
|
|
247
246
|
Number of bytes to use for all integers.
|
|
248
247
|
"""
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
all_ids = self.get_all_ids()
|
|
249
|
+
zip_info = zipfile.ZipInfo(f"{name}.addr")
|
|
250
|
+
row_size = AddressReader.compute_row_size(int_size, len(self.addresses))
|
|
251
|
+
zip_info.file_size = AddressReader.compute_header_size(int_size) + len(all_ids) * row_size
|
|
252
|
+
with zf.open(zip_info, mode="w") as stream:
|
|
253
|
+
self.write(stream, int_size=int_size, all_ids=all_ids)
|
|
254
|
+
|
|
255
|
+
def get_all_ids(self) -> Set[uuid.UUID]:
|
|
256
|
+
"""Return all IDs used by any address dictionary.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
all_ids : `~collections.abc.Set` [`uuid.UUID`]
|
|
261
|
+
Set of all IDs.
|
|
262
|
+
"""
|
|
263
|
+
all_ids: set[uuid.UUID] = set()
|
|
264
|
+
for address_map in self.addresses:
|
|
265
|
+
all_ids.update(address_map.keys())
|
|
266
|
+
return all_ids
|
|
251
267
|
|
|
252
268
|
|
|
253
269
|
@dataclasses.dataclass
|
|
@@ -646,7 +662,7 @@ class MultiblockWriter:
|
|
|
646
662
|
model : `pydantic.BaseModel`
|
|
647
663
|
Model to convert to JSON and compress.
|
|
648
664
|
compressor : `Compressor`
|
|
649
|
-
Object with a
|
|
665
|
+
Object with a ``compress`` method that takes and returns `bytes`.
|
|
650
666
|
|
|
651
667
|
Returns
|
|
652
668
|
-------
|
|
@@ -743,7 +759,7 @@ class MultiblockReader:
|
|
|
743
759
|
model_type : `type` [ `pydantic.BaseModel` ]
|
|
744
760
|
Pydantic model to validate JSON with.
|
|
745
761
|
decompressor : `Decompressor`
|
|
746
|
-
Object with a
|
|
762
|
+
Object with a ``decompress`` method that takes and returns `bytes`.
|
|
747
763
|
int_size : `int`
|
|
748
764
|
Number of bytes to use for all integers.
|
|
749
765
|
page_size : `int`
|
|
@@ -793,7 +809,7 @@ class MultiblockReader:
|
|
|
793
809
|
model_type : `type` [ `pydantic.BaseModel` ]
|
|
794
810
|
Pydantic model to validate JSON with.
|
|
795
811
|
decompressor : `Decompressor`
|
|
796
|
-
Object with a
|
|
812
|
+
Object with a ``decompress`` method that takes and returns `bytes`.
|
|
797
813
|
|
|
798
814
|
Returns
|
|
799
815
|
-------
|
|
@@ -49,7 +49,7 @@ import warnings
|
|
|
49
49
|
from collections import defaultdict
|
|
50
50
|
from collections.abc import Iterable, Iterator, Mapping, Sequence
|
|
51
51
|
from contextlib import AbstractContextManager, contextmanager
|
|
52
|
-
from typing import TYPE_CHECKING, Any,
|
|
52
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
53
53
|
|
|
54
54
|
import networkx
|
|
55
55
|
import networkx.algorithms.bipartite
|
|
@@ -110,10 +110,14 @@ if TYPE_CHECKING:
|
|
|
110
110
|
from ..config import PipelineTaskConfig
|
|
111
111
|
from ..graph import QgraphSummary, QuantumGraph
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
# Sphinx needs imports for type annotations of base class members.
|
|
114
|
+
if "sphinx" in sys.modules:
|
|
115
|
+
import zipfile # noqa: F401
|
|
116
|
+
|
|
117
|
+
from ._multiblock import AddressReader, Decompressor # noqa: F401
|
|
114
118
|
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
_LOG = logging.getLogger(__name__)
|
|
117
121
|
|
|
118
122
|
|
|
119
123
|
class _PredictedThinQuantumModelV0(pydantic.BaseModel):
|