lsst-pipe-base 30.0.1rc1__py3-none-any.whl → 30.2025.5100__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 +20 -31
- lsst/pipe/base/_quantumContext.py +3 -3
- lsst/pipe/base/_status.py +10 -43
- lsst/pipe/base/_task_metadata.py +2 -2
- lsst/pipe/base/all_dimensions_quantum_graph_builder.py +3 -8
- lsst/pipe/base/automatic_connection_constants.py +1 -20
- lsst/pipe/base/cli/cmd/__init__.py +2 -18
- lsst/pipe/base/cli/cmd/commands.py +4 -149
- lsst/pipe/base/connectionTypes.py +160 -72
- lsst/pipe/base/connections.py +9 -6
- lsst/pipe/base/execution_reports.py +5 -0
- lsst/pipe/base/graph/graph.py +10 -11
- lsst/pipe/base/graph/quantumNode.py +4 -4
- lsst/pipe/base/graph_walker.py +10 -8
- lsst/pipe/base/log_capture.py +80 -40
- lsst/pipe/base/mp_graph_executor.py +15 -51
- lsst/pipe/base/pipeline.py +6 -5
- lsst/pipe/base/pipelineIR.py +8 -2
- lsst/pipe/base/pipelineTask.py +7 -5
- lsst/pipe/base/pipeline_graph/_dataset_types.py +2 -2
- lsst/pipe/base/pipeline_graph/_edges.py +22 -32
- lsst/pipe/base/pipeline_graph/_mapping_views.py +7 -4
- lsst/pipe/base/pipeline_graph/_pipeline_graph.py +7 -14
- lsst/pipe/base/pipeline_graph/expressions.py +2 -2
- lsst/pipe/base/pipeline_graph/io.py +10 -7
- lsst/pipe/base/pipeline_graph/visualization/_dot.py +12 -13
- lsst/pipe/base/pipeline_graph/visualization/_layout.py +18 -16
- lsst/pipe/base/pipeline_graph/visualization/_merge.py +7 -4
- lsst/pipe/base/pipeline_graph/visualization/_printer.py +10 -10
- lsst/pipe/base/pipeline_graph/visualization/_status_annotator.py +0 -7
- lsst/pipe/base/prerequisite_helpers.py +1 -2
- lsst/pipe/base/quantum_graph/_common.py +20 -19
- lsst/pipe/base/quantum_graph/_multiblock.py +31 -37
- lsst/pipe/base/quantum_graph/_predicted.py +13 -111
- lsst/pipe/base/quantum_graph/_provenance.py +45 -1136
- lsst/pipe/base/quantum_graph/aggregator/__init__.py +1 -0
- lsst/pipe/base/quantum_graph/aggregator/_communicators.py +289 -204
- lsst/pipe/base/quantum_graph/aggregator/_config.py +9 -87
- lsst/pipe/base/quantum_graph/aggregator/_ingester.py +12 -13
- lsst/pipe/base/quantum_graph/aggregator/_scanner.py +235 -49
- lsst/pipe/base/quantum_graph/aggregator/_structs.py +116 -6
- lsst/pipe/base/quantum_graph/aggregator/_supervisor.py +39 -29
- lsst/pipe/base/quantum_graph/aggregator/_writer.py +351 -34
- lsst/pipe/base/quantum_graph/visualization.py +1 -5
- lsst/pipe/base/quantum_graph_builder.py +8 -21
- lsst/pipe/base/quantum_graph_executor.py +13 -116
- lsst/pipe/base/quantum_graph_skeleton.py +29 -31
- lsst/pipe/base/quantum_provenance_graph.py +12 -29
- lsst/pipe/base/separable_pipeline_executor.py +3 -19
- lsst/pipe/base/single_quantum_executor.py +42 -67
- lsst/pipe/base/struct.py +0 -4
- lsst/pipe/base/testUtils.py +3 -3
- lsst/pipe/base/tests/mocks/_storage_class.py +1 -2
- lsst/pipe/base/version.py +1 -1
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/METADATA +3 -3
- lsst_pipe_base-30.2025.5100.dist-info/RECORD +125 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/WHEEL +1 -1
- lsst/pipe/base/log_on_close.py +0 -76
- lsst/pipe/base/quantum_graph/aggregator/_workers.py +0 -303
- lsst/pipe/base/quantum_graph/formatter.py +0 -171
- lsst/pipe/base/quantum_graph/ingest_graph.py +0 -413
- lsst_pipe_base-30.0.1rc1.dist-info/RECORD +0 -129
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/entry_points.txt +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/licenses/COPYRIGHT +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/licenses/LICENSE +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/licenses/bsd_license.txt +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/licenses/gpl-v3.0.txt +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/top_level.txt +0 -0
- {lsst_pipe_base-30.0.1rc1.dist-info → lsst_pipe_base-30.2025.5100.dist-info}/zip-safe +0 -0
lsst/pipe/base/_instrument.py
CHANGED
|
@@ -31,14 +31,14 @@ __all__ = ("Instrument",)
|
|
|
31
31
|
|
|
32
32
|
import contextlib
|
|
33
33
|
import datetime
|
|
34
|
+
import os.path
|
|
34
35
|
from abc import ABCMeta, abstractmethod
|
|
35
36
|
from collections.abc import Sequence
|
|
36
37
|
from typing import TYPE_CHECKING, Any, Self, cast, final
|
|
37
38
|
|
|
38
|
-
from lsst.daf.butler import DataCoordinate, DataId, DimensionPacker, DimensionRecord, Formatter
|
|
39
|
+
from lsst.daf.butler import DataCoordinate, DataId, DimensionPacker, DimensionRecord, Formatter
|
|
39
40
|
from lsst.daf.butler.registry import DataIdError
|
|
40
41
|
from lsst.pex.config import Config, RegistryField
|
|
41
|
-
from lsst.resources import ResourcePath, ResourcePathExpression
|
|
42
42
|
from lsst.utils import doImportType
|
|
43
43
|
from lsst.utils.introspection import get_full_type_name
|
|
44
44
|
|
|
@@ -65,10 +65,10 @@ class Instrument(metaclass=ABCMeta):
|
|
|
65
65
|
the base class.
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
|
-
configPaths: Sequence[
|
|
68
|
+
configPaths: Sequence[str] = ()
|
|
69
69
|
"""Paths to config files to read for specific Tasks.
|
|
70
70
|
|
|
71
|
-
The paths in this list should contain files of the form
|
|
71
|
+
The paths in this list should contain files of the form `task.py`, for
|
|
72
72
|
each of the Tasks that requires special configuration.
|
|
73
73
|
"""
|
|
74
74
|
|
|
@@ -99,8 +99,7 @@ class Instrument(metaclass=ABCMeta):
|
|
|
99
99
|
|
|
100
100
|
@abstractmethod
|
|
101
101
|
def register(self, registry: Registry, *, update: bool = False) -> None:
|
|
102
|
-
"""Insert instrument, and other relevant records into
|
|
103
|
-
registry.
|
|
102
|
+
"""Insert instrument, and other relevant records into `Registry`.
|
|
104
103
|
|
|
105
104
|
Parameters
|
|
106
105
|
----------
|
|
@@ -110,10 +109,6 @@ class Instrument(metaclass=ABCMeta):
|
|
|
110
109
|
If `True` (`False` is default), update existing records if they
|
|
111
110
|
differ from the new ones.
|
|
112
111
|
|
|
113
|
-
Returns
|
|
114
|
-
-------
|
|
115
|
-
None
|
|
116
|
-
|
|
117
112
|
Raises
|
|
118
113
|
------
|
|
119
114
|
lsst.daf.butler.registry.ConflictingDefinitionError
|
|
@@ -132,6 +127,13 @@ class Instrument(metaclass=ABCMeta):
|
|
|
132
127
|
the level of individual dimension entries; new detectors and filters
|
|
133
128
|
should be added, but changes to any existing record should not be.
|
|
134
129
|
This can generally be achieved via a block like
|
|
130
|
+
|
|
131
|
+
.. code-block:: python
|
|
132
|
+
|
|
133
|
+
with registry.transaction():
|
|
134
|
+
registry.syncDimensionData("instrument", ...)
|
|
135
|
+
registry.syncDimensionData("detector", ...)
|
|
136
|
+
self.registerFilters(registry)
|
|
135
137
|
"""
|
|
136
138
|
raise NotImplementedError()
|
|
137
139
|
|
|
@@ -312,7 +314,7 @@ class Instrument(metaclass=ABCMeta):
|
|
|
312
314
|
return instrument_cls(collection_prefix=collection_prefix)
|
|
313
315
|
|
|
314
316
|
@staticmethod
|
|
315
|
-
def importAll(registry: Registry) ->
|
|
317
|
+
def importAll(registry: Registry) -> None:
|
|
316
318
|
"""Import all the instruments known to this registry.
|
|
317
319
|
|
|
318
320
|
This will ensure that all metadata translators have been registered.
|
|
@@ -322,43 +324,31 @@ class Instrument(metaclass=ABCMeta):
|
|
|
322
324
|
registry : `lsst.daf.butler.Registry`
|
|
323
325
|
Butler registry to query to find the information.
|
|
324
326
|
|
|
325
|
-
Returns
|
|
326
|
-
-------
|
|
327
|
-
imported : `dict` [`str`, `type` [`Instrument`]]
|
|
328
|
-
A mapping containing all the instrument classes that were loaded
|
|
329
|
-
successfully, keyed by their butler names.
|
|
330
|
-
|
|
331
327
|
Notes
|
|
332
328
|
-----
|
|
333
329
|
It is allowed for a particular instrument class to fail on import.
|
|
334
330
|
This might simply indicate that a particular obs package has
|
|
335
331
|
not been setup.
|
|
336
332
|
"""
|
|
337
|
-
imported: dict[str, type[Instrument]] = {}
|
|
338
333
|
records = list(registry.queryDimensionRecords("instrument"))
|
|
339
334
|
for record in records:
|
|
340
335
|
cls = record.class_name
|
|
341
|
-
instrument_name: str = cast(str, record.name)
|
|
342
336
|
with contextlib.suppress(Exception):
|
|
343
|
-
|
|
344
|
-
assert issubclass(instr, Instrument)
|
|
345
|
-
imported[instrument_name] = instr
|
|
346
|
-
return imported
|
|
337
|
+
doImportType(cls)
|
|
347
338
|
|
|
348
339
|
@abstractmethod
|
|
349
|
-
def getRawFormatter(self, dataId: DataId) -> type[Formatter
|
|
340
|
+
def getRawFormatter(self, dataId: DataId) -> type[Formatter]:
|
|
350
341
|
"""Return the Formatter class that should be used to read a particular
|
|
351
342
|
raw file.
|
|
352
343
|
|
|
353
344
|
Parameters
|
|
354
345
|
----------
|
|
355
|
-
dataId : `
|
|
346
|
+
dataId : `DataId`
|
|
356
347
|
Dimension-based ID for the raw file or files being ingested.
|
|
357
348
|
|
|
358
349
|
Returns
|
|
359
350
|
-------
|
|
360
|
-
formatter : `
|
|
361
|
-
[`lsst.daf.butler.Formatter` | `lsst.daf.butler.FormatterV2` ]
|
|
351
|
+
formatter : `lsst.daf.butler.Formatter` class
|
|
362
352
|
Class to be used that reads the file into the correct
|
|
363
353
|
Python object for the raw data.
|
|
364
354
|
"""
|
|
@@ -376,10 +366,9 @@ class Instrument(metaclass=ABCMeta):
|
|
|
376
366
|
Config instance to which overrides should be applied.
|
|
377
367
|
"""
|
|
378
368
|
for root in self.configPaths:
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
config.load(uri)
|
|
369
|
+
path = os.path.join(root, f"{name}.py")
|
|
370
|
+
if os.path.exists(path):
|
|
371
|
+
config.load(path)
|
|
383
372
|
|
|
384
373
|
@staticmethod
|
|
385
374
|
def formatCollectionTimestamp(timestamp: str | datetime.datetime) -> str:
|
|
@@ -380,8 +380,8 @@ class QuantumContext:
|
|
|
380
380
|
if dataset is directly a `list` of `~lsst.daf.butler.DatasetRef`
|
|
381
381
|
or a single `~lsst.daf.butler.DatasetRef`. If ``values.NAME`` is
|
|
382
382
|
None, no output is written.
|
|
383
|
-
dataset : `OutputQuantizedConnection` or `list` \
|
|
384
|
-
|
|
383
|
+
dataset : `OutputQuantizedConnection` or `list`[`DatasetRef`] \
|
|
384
|
+
or `DatasetRef`
|
|
385
385
|
This argument may either be an `InputQuantizedConnection` which
|
|
386
386
|
describes all the inputs of a quantum, a list of
|
|
387
387
|
`lsst.daf.butler.DatasetRef`, or a single
|
|
@@ -460,7 +460,7 @@ class QuantumContext:
|
|
|
460
460
|
|
|
461
461
|
Parameters
|
|
462
462
|
----------
|
|
463
|
-
ref : `
|
|
463
|
+
ref : `DatasetRef`
|
|
464
464
|
The dataset to attach provenance to. This dataset must have been
|
|
465
465
|
retrieved by this quantum context.
|
|
466
466
|
extra : `dict` [ `str`, `int` | `float` | `str` | `bool` ]
|
lsst/pipe/base/_status.py
CHANGED
|
@@ -275,23 +275,15 @@ class ExceptionInfo(pydantic.BaseModel):
|
|
|
275
275
|
class QuantumAttemptStatus(enum.Enum):
|
|
276
276
|
"""Enum summarizing an attempt to run a quantum."""
|
|
277
277
|
|
|
278
|
-
ABORTED = -4
|
|
279
|
-
"""The quantum failed with a hard error that prevented both logs and
|
|
280
|
-
metadata from being written.
|
|
281
|
-
|
|
282
|
-
This state is only set if information from higher-level tooling (e.g. BPS)
|
|
283
|
-
is available to distinguish it from ``UNKNOWN``.
|
|
284
|
-
"""
|
|
285
|
-
|
|
286
278
|
UNKNOWN = -3
|
|
287
279
|
"""The status of this attempt is unknown.
|
|
288
280
|
|
|
289
|
-
This means no logs or metadata were written, and it at least could
|
|
290
|
-
determined whether the quantum was blocked by an upstream failure
|
|
291
|
-
was definitely blocked, `BLOCKED` is set instead).
|
|
281
|
+
This usually means no logs or metadata were written, and it at least could
|
|
282
|
+
not be determined whether the quantum was blocked by an upstream failure
|
|
283
|
+
(if it was definitely blocked, `BLOCKED` is set instead).
|
|
292
284
|
"""
|
|
293
285
|
|
|
294
|
-
|
|
286
|
+
LOGS_MISSING = -2
|
|
295
287
|
"""Task metadata was written for this attempt but logs were not.
|
|
296
288
|
|
|
297
289
|
This is a rare condition that requires a hard failure (i.e. the kind that
|
|
@@ -300,21 +292,20 @@ class QuantumAttemptStatus(enum.Enum):
|
|
|
300
292
|
"""
|
|
301
293
|
|
|
302
294
|
FAILED = -1
|
|
303
|
-
"""Execution of the quantum failed
|
|
295
|
+
"""Execution of the quantum failed.
|
|
304
296
|
|
|
305
297
|
This is always set if the task metadata dataset was not written but logs
|
|
306
298
|
were, as is the case when a Python exception is caught and handled by the
|
|
307
|
-
execution system.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
metadata dataset was not.
|
|
299
|
+
execution system. It may also be set in cases where logs were not written
|
|
300
|
+
either, but other information was available (e.g. from higher-level
|
|
301
|
+
orchestration tooling) to mark it as a failure.
|
|
311
302
|
"""
|
|
312
303
|
|
|
313
304
|
BLOCKED = 0
|
|
314
305
|
"""This quantum was not executed because an upstream quantum failed.
|
|
315
306
|
|
|
316
|
-
Upstream quanta with status `UNKNOWN
|
|
317
|
-
|
|
307
|
+
Upstream quanta with status `UNKNOWN` or `FAILED` are considered blockers;
|
|
308
|
+
`LOGS_MISSING` is not.
|
|
318
309
|
"""
|
|
319
310
|
|
|
320
311
|
SUCCESSFUL = 1
|
|
@@ -328,30 +319,6 @@ class QuantumAttemptStatus(enum.Enum):
|
|
|
328
319
|
these "successes with caveats" are reported.
|
|
329
320
|
"""
|
|
330
321
|
|
|
331
|
-
@property
|
|
332
|
-
def has_metadata(self) -> bool:
|
|
333
|
-
"""Whether the task metadata dataset was produced."""
|
|
334
|
-
return self is self.SUCCESSFUL or self is self.ABORTED_SUCCESS
|
|
335
|
-
|
|
336
|
-
@property
|
|
337
|
-
def has_log(self) -> bool:
|
|
338
|
-
"""Whether the log dataset was produced."""
|
|
339
|
-
return self is self.SUCCESSFUL or self is self.FAILED
|
|
340
|
-
|
|
341
|
-
@property
|
|
342
|
-
def title(self) -> str:
|
|
343
|
-
"""A version of this status' name suitable for use as a title in a plot
|
|
344
|
-
or table.
|
|
345
|
-
"""
|
|
346
|
-
return self.name.capitalize().replace("_", " ")
|
|
347
|
-
|
|
348
|
-
@property
|
|
349
|
-
def is_rare(self) -> bool:
|
|
350
|
-
"""Whether this status is rare enough that it should only be listed
|
|
351
|
-
when it actually occurs.
|
|
352
|
-
"""
|
|
353
|
-
return self in (self.ABORTED, self.ABORTED_SUCCESS, self.UNKNOWN)
|
|
354
|
-
|
|
355
322
|
|
|
356
323
|
class GetSetDictMetadataHolder(Protocol):
|
|
357
324
|
"""Protocol for objects that have a ``metadata`` attribute that satisfies
|
lsst/pipe/base/_task_metadata.py
CHANGED
|
@@ -37,7 +37,7 @@ import itertools
|
|
|
37
37
|
import numbers
|
|
38
38
|
import sys
|
|
39
39
|
from collections.abc import Collection, Iterator, Mapping, Sequence
|
|
40
|
-
from typing import Any, Protocol
|
|
40
|
+
from typing import Any, Protocol, TypeAlias, Union
|
|
41
41
|
|
|
42
42
|
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
|
|
43
43
|
|
|
@@ -47,7 +47,7 @@ _ALLOWED_PRIMITIVE_TYPES = (str, float, int, bool)
|
|
|
47
47
|
|
|
48
48
|
# Note that '|' syntax for unions doesn't work when we have to use a string
|
|
49
49
|
# literal (and we do since it's recursive and not an annotation).
|
|
50
|
-
|
|
50
|
+
NestedMetadataDict: TypeAlias = Mapping[str, Union[str, float, int, bool, "NestedMetadataDict"]]
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
class PropertySetLike(Protocol):
|
|
@@ -574,7 +574,7 @@ class _DimensionGroupBranch:
|
|
|
574
574
|
|
|
575
575
|
Parameters
|
|
576
576
|
----------
|
|
577
|
-
log : `lsst.
|
|
577
|
+
log : `lsst.logging.LsstLogAdapter`
|
|
578
578
|
Logger to use for status reporting.
|
|
579
579
|
log_indent : `str`, optional
|
|
580
580
|
Indentation to prefix the log message. This is used when recursing
|
|
@@ -739,7 +739,7 @@ class _DimensionGroupTree:
|
|
|
739
739
|
Query constraint specified by the user.
|
|
740
740
|
data_id_tables : `~collections.abc.Iterable` [ `astropy.table.Table` ]
|
|
741
741
|
Data ID tables being joined into the query.
|
|
742
|
-
log : `lsst.
|
|
742
|
+
log : `lsst.log.LsstLogAdapter`
|
|
743
743
|
Logger that supports ``verbose`` output.
|
|
744
744
|
"""
|
|
745
745
|
universe = self.all_dimensions.universe
|
|
@@ -805,7 +805,7 @@ class _DimensionGroupTree:
|
|
|
805
805
|
----------
|
|
806
806
|
requested : `DatasetQueryConstraintVariant`
|
|
807
807
|
Query constraint specified by the user.
|
|
808
|
-
log : `lsst.
|
|
808
|
+
log : `lsst.log.LsstLogAdapter`
|
|
809
809
|
Logger that supports ``verbose`` output.
|
|
810
810
|
"""
|
|
811
811
|
overall_inputs: dict[str, DatasetTypeNode] = {
|
|
@@ -834,11 +834,6 @@ class _DimensionGroupTree:
|
|
|
834
834
|
remainder,
|
|
835
835
|
)
|
|
836
836
|
self.dataset_constraint.intersection_update(inputs)
|
|
837
|
-
if not self.dataset_constraint:
|
|
838
|
-
raise QuantumGraphBuilderError(
|
|
839
|
-
"An explicit dataset query constraint was provided, but it does not include any "
|
|
840
|
-
f"inputs to the pipeline subset with tasks {list(self.subgraph.tasks.keys())}."
|
|
841
|
-
)
|
|
842
837
|
case _:
|
|
843
838
|
raise QuantumGraphBuilderError(
|
|
844
839
|
f"Unable to handle type {requested} given as dataset query constraint."
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
27
27
|
|
|
28
28
|
"""Constants used to define the connections automatically added for each
|
|
29
|
-
PipelineTask by the execution system
|
|
29
|
+
PipelineTask by the execution system.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
from __future__ import annotations
|
|
@@ -43,10 +43,6 @@ __all__ = (
|
|
|
43
43
|
"METADATA_OUTPUT_TEMPLATE",
|
|
44
44
|
"PACKAGES_INIT_OUTPUT_NAME",
|
|
45
45
|
"PACKAGES_INIT_OUTPUT_STORAGE_CLASS",
|
|
46
|
-
"PROVENANCE_DATASET_TYPE_NAME",
|
|
47
|
-
"PROVENANCE_STORAGE_CLASS",
|
|
48
|
-
"RESOURCE_USAGE_STORAGE_CLASS",
|
|
49
|
-
"RESOURCE_USAGE_TEMPLATE",
|
|
50
46
|
)
|
|
51
47
|
|
|
52
48
|
|
|
@@ -95,18 +91,3 @@ type names.
|
|
|
95
91
|
METADATA_OUTPUT_STORAGE_CLASS: str = "TaskMetadata"
|
|
96
92
|
"""Name of the storage class for task metadata output datasets.
|
|
97
93
|
"""
|
|
98
|
-
|
|
99
|
-
PROVENANCE_DATASET_TYPE_NAME: str = "run_provenance"
|
|
100
|
-
"""Name of the dataset used to store per-RUN provenance."""
|
|
101
|
-
|
|
102
|
-
PROVENANCE_STORAGE_CLASS: str = "ProvenanceQuantumGraph"
|
|
103
|
-
"""Name of the storage class used to store provenance."""
|
|
104
|
-
|
|
105
|
-
RESOURCE_USAGE_TEMPLATE: str = "{label}_resource_usage"
|
|
106
|
-
"""String template used to form the name of the resource usage dataset type for
|
|
107
|
-
a task.
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
RESOURCE_USAGE_STORAGE_CLASS: str = "ArrowAstropy"
|
|
111
|
-
"""Storage class of the resource usage dataset type for a task.
|
|
112
|
-
"""
|
|
@@ -25,22 +25,6 @@
|
|
|
25
25
|
# You should have received a copy of the GNU General Public License
|
|
26
26
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
27
27
|
|
|
28
|
-
__all__ = [
|
|
29
|
-
"register_instrument",
|
|
30
|
-
"transfer_from_graph",
|
|
31
|
-
"zip_from_graph",
|
|
32
|
-
"retrieve_artifacts_for_quanta",
|
|
33
|
-
"aggregate_graph",
|
|
34
|
-
"ingest_graph",
|
|
35
|
-
"provenance_report",
|
|
36
|
-
]
|
|
28
|
+
__all__ = ["register_instrument", "transfer_from_graph", "zip_from_graph", "retrieve_artifacts_for_quanta", "aggregate_graph"]
|
|
37
29
|
|
|
38
|
-
from .commands import (
|
|
39
|
-
register_instrument,
|
|
40
|
-
retrieve_artifacts_for_quanta,
|
|
41
|
-
transfer_from_graph,
|
|
42
|
-
zip_from_graph,
|
|
43
|
-
aggregate_graph,
|
|
44
|
-
ingest_graph,
|
|
45
|
-
provenance_report,
|
|
46
|
-
)
|
|
30
|
+
from .commands import (register_instrument, retrieve_artifacts_for_quanta, transfer_from_graph, zip_from_graph, aggregate_graph)
|
|
@@ -25,9 +25,6 @@
|
|
|
25
25
|
# You should have received a copy of the GNU General Public License
|
|
26
26
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
27
27
|
|
|
28
|
-
import functools
|
|
29
|
-
import operator
|
|
30
|
-
from collections.abc import Iterable
|
|
31
28
|
from typing import Any
|
|
32
29
|
|
|
33
30
|
import click
|
|
@@ -43,7 +40,6 @@ from lsst.daf.butler.cli.opt import (
|
|
|
43
40
|
from lsst.daf.butler.cli.utils import ButlerCommand, split_commas, unwrap
|
|
44
41
|
|
|
45
42
|
from ... import script
|
|
46
|
-
from ..._status import QuantumAttemptStatus, QuantumSuccessCaveats
|
|
47
43
|
from ...quantum_graph import aggregator
|
|
48
44
|
from ..opt import instrument_argument, update_output_chain_option
|
|
49
45
|
|
|
@@ -165,7 +161,7 @@ _AGGREGATOR_DEFAULTS = aggregator.AggregatorConfig()
|
|
|
165
161
|
|
|
166
162
|
@click.command(short_help="Scan for the outputs of an active or completed quantum graph.", cls=ButlerCommand)
|
|
167
163
|
@click.argument("predicted_graph", required=True)
|
|
168
|
-
@repo_argument(required=True, help="Path
|
|
164
|
+
@repo_argument(required=True, help="Path to the central butler repository.")
|
|
169
165
|
@click.option(
|
|
170
166
|
"-o",
|
|
171
167
|
"--output",
|
|
@@ -185,9 +181,9 @@ _AGGREGATOR_DEFAULTS = aggregator.AggregatorConfig()
|
|
|
185
181
|
help="Number of processes to use.",
|
|
186
182
|
)
|
|
187
183
|
@click.option(
|
|
188
|
-
"--incomplete
|
|
189
|
-
"
|
|
190
|
-
default=_AGGREGATOR_DEFAULTS.
|
|
184
|
+
"--complete/--incomplete",
|
|
185
|
+
"assume_complete",
|
|
186
|
+
default=_AGGREGATOR_DEFAULTS.assume_complete,
|
|
191
187
|
help="Whether execution has completed (and failures cannot be retried).",
|
|
192
188
|
)
|
|
193
189
|
@click.option(
|
|
@@ -253,14 +249,6 @@ _AGGREGATOR_DEFAULTS = aggregator.AggregatorConfig()
|
|
|
253
249
|
default=_AGGREGATOR_DEFAULTS.mock_storage_classes,
|
|
254
250
|
help="Enable support for storage classes created by the lsst.pipe.base.tests.mocks package.",
|
|
255
251
|
)
|
|
256
|
-
@click.option(
|
|
257
|
-
"--promise-ingest-graph/--no-promise-ingest-graph",
|
|
258
|
-
default=_AGGREGATOR_DEFAULTS.promise_ingest_graph,
|
|
259
|
-
help=(
|
|
260
|
-
"Promise to run 'butler ingest-graph' later, allowing aggregate-graph "
|
|
261
|
-
"to skip metadata/log/config ingestion for now."
|
|
262
|
-
),
|
|
263
|
-
)
|
|
264
252
|
def aggregate_graph(predicted_graph: str, repo: str, **kwargs: Any) -> None:
|
|
265
253
|
"""Scan for quantum graph's outputs to gather provenance, ingest datasets
|
|
266
254
|
into the central butler repository, and delete datasets that are no
|
|
@@ -280,136 +268,3 @@ def aggregate_graph(predicted_graph: str, repo: str, **kwargs: Any) -> None:
|
|
|
280
268
|
# When this exception is raised, we'll have already logged the relevant
|
|
281
269
|
# traceback from a separate worker.
|
|
282
270
|
raise click.ClickException(str(err)) from None
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
@click.command(
|
|
286
|
-
short_help="Ingest a provenance quantum graph into a butler.",
|
|
287
|
-
cls=ButlerCommand,
|
|
288
|
-
)
|
|
289
|
-
@repo_argument(required=True, help="Path or alias for the butler repository.")
|
|
290
|
-
@click.argument("provenance_graph", required=False)
|
|
291
|
-
@transfer_option(default="move")
|
|
292
|
-
@click.option("--batch-size", default=10000, help="How many datasets to process in each transaction.")
|
|
293
|
-
@click.option(
|
|
294
|
-
"--output-run",
|
|
295
|
-
default=None,
|
|
296
|
-
help=(
|
|
297
|
-
"Name of the output RUN collection. Must be provided if the provenance graph is not"
|
|
298
|
-
" provided (so the graph can be found in the butler)."
|
|
299
|
-
),
|
|
300
|
-
)
|
|
301
|
-
def ingest_graph(
|
|
302
|
-
*,
|
|
303
|
-
repo: str,
|
|
304
|
-
provenance_graph: str | None,
|
|
305
|
-
transfer: str | None,
|
|
306
|
-
batch_size: int,
|
|
307
|
-
output_run: str | None,
|
|
308
|
-
) -> None:
|
|
309
|
-
"""Ingest a provenance graph into a butler repository."""
|
|
310
|
-
from ...quantum_graph.ingest_graph import ingest_graph as ingest_graph_py
|
|
311
|
-
|
|
312
|
-
ingest_graph_py(repo, provenance_graph, transfer=transfer, batch_size=batch_size, output_run=output_run)
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
@click.command(
|
|
316
|
-
short_help="Print and write provenance reports.",
|
|
317
|
-
cls=ButlerCommand,
|
|
318
|
-
)
|
|
319
|
-
@click.argument("repo_or_qg")
|
|
320
|
-
@click.argument("collection", required=False, default=None)
|
|
321
|
-
@click.option(
|
|
322
|
-
"--state",
|
|
323
|
-
multiple=True,
|
|
324
|
-
type=click.Choice(QuantumAttemptStatus),
|
|
325
|
-
help=(
|
|
326
|
-
"Additional quantum state to include in the status report and data ID tables "
|
|
327
|
-
"(FAILED, ABORTED, and ABORTED_SUCCESS are included by default)."
|
|
328
|
-
),
|
|
329
|
-
)
|
|
330
|
-
@click.option(
|
|
331
|
-
"--no-state",
|
|
332
|
-
multiple=True,
|
|
333
|
-
type=str,
|
|
334
|
-
metavar="STATE",
|
|
335
|
-
help="Quantum state to drop from in status report and data ID tables (same options as --state).",
|
|
336
|
-
)
|
|
337
|
-
@click.option(
|
|
338
|
-
"--status-report",
|
|
339
|
-
default=None,
|
|
340
|
-
metavar="URI",
|
|
341
|
-
help="File or URI (.json) for a detailed report (with data IDs) on quanta with certain states.",
|
|
342
|
-
)
|
|
343
|
-
@click.option(
|
|
344
|
-
"--quantum-table/--no-quantum-table",
|
|
345
|
-
default=True,
|
|
346
|
-
help="Whether to print summary of quantum status counts to STDOUT.",
|
|
347
|
-
)
|
|
348
|
-
@click.option(
|
|
349
|
-
"--exception-table/--no-exception-table",
|
|
350
|
-
default=True,
|
|
351
|
-
help="Whether to print summary of exception type counts STDOUT.",
|
|
352
|
-
)
|
|
353
|
-
@click.option(
|
|
354
|
-
"--caveat",
|
|
355
|
-
multiple=True,
|
|
356
|
-
type=click.Choice(QuantumSuccessCaveats),
|
|
357
|
-
help=(
|
|
358
|
-
"Include successful quanta in the status report if they have this caveat. "
|
|
359
|
-
"May be passed multiple times; any matching caveat is included. "
|
|
360
|
-
"Passing this option implicitly adds '--state SUCCESSFUL'."
|
|
361
|
-
),
|
|
362
|
-
)
|
|
363
|
-
@click.option(
|
|
364
|
-
"--data-id-table-dir",
|
|
365
|
-
default=None,
|
|
366
|
-
metavar="URI",
|
|
367
|
-
help=(
|
|
368
|
-
"Directory (may be a URI) for a tree of data ID tables for each "
|
|
369
|
-
"task label, status, and exception type combination in the status report."
|
|
370
|
-
),
|
|
371
|
-
)
|
|
372
|
-
def provenance_report(
|
|
373
|
-
*,
|
|
374
|
-
repo_or_qg: str,
|
|
375
|
-
collection: str | None,
|
|
376
|
-
state: Iterable[QuantumAttemptStatus],
|
|
377
|
-
no_state: Iterable[str],
|
|
378
|
-
status_report: str | None,
|
|
379
|
-
quantum_table: bool = False,
|
|
380
|
-
exception_table: bool = False,
|
|
381
|
-
caveat: Iterable[QuantumSuccessCaveats],
|
|
382
|
-
data_id_table_dir: str | None,
|
|
383
|
-
) -> None:
|
|
384
|
-
"""Read a provenance quantum graph from a butler or file and use it to
|
|
385
|
-
generate reports.
|
|
386
|
-
|
|
387
|
-
REPO_OR_QG is a path or alias for the butler repository (if reading an
|
|
388
|
-
ingested graph, as indicated by passing COLLECTION), or the path to a
|
|
389
|
-
provenance quantum graph file.
|
|
390
|
-
"""
|
|
391
|
-
from ...quantum_graph import ProvenanceQuantumGraph
|
|
392
|
-
|
|
393
|
-
states = set(state)
|
|
394
|
-
states.add(QuantumAttemptStatus.FAILED)
|
|
395
|
-
states.add(QuantumAttemptStatus.ABORTED)
|
|
396
|
-
states.add(QuantumAttemptStatus.ABORTED_SUCCESS)
|
|
397
|
-
for state_name in no_state:
|
|
398
|
-
states.discard(QuantumAttemptStatus.__members__[state_name])
|
|
399
|
-
with_caveats: QuantumSuccessCaveats | None = None
|
|
400
|
-
if caveat:
|
|
401
|
-
states.add(QuantumAttemptStatus.SUCCESSFUL)
|
|
402
|
-
with_caveats = functools.reduce(
|
|
403
|
-
operator.__or__,
|
|
404
|
-
caveat,
|
|
405
|
-
QuantumSuccessCaveats.NO_CAVEATS,
|
|
406
|
-
)
|
|
407
|
-
with ProvenanceQuantumGraph.from_args(repo_or_qg, collection=collection, datasets=()) as (graph, _):
|
|
408
|
-
graph.make_many_reports(
|
|
409
|
-
status_report_file=status_report,
|
|
410
|
-
states=states,
|
|
411
|
-
print_quantum_table=quantum_table,
|
|
412
|
-
print_exception_table=exception_table,
|
|
413
|
-
with_caveats=with_caveats,
|
|
414
|
-
data_id_table_dir=data_id_table_dir,
|
|
415
|
-
)
|