lsst-ctrl-mpexec 29.2025.1600__tar.gz → 29.2025.1800__tar.gz
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_ctrl_mpexec-29.2025.1600/python/lsst_ctrl_mpexec.egg-info → lsst_ctrl_mpexec-29.2025.1800}/PKG-INFO +1 -1
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/configuring-pipetask-tasks.rst +1 -1
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/cmd/commands.py +1 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/opt/options.py +10 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/run_qbb.py +5 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cmdLineFwk.py +16 -4
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/singleQuantumExecutor.py +22 -6
- lsst_ctrl_mpexec-29.2025.1800/python/lsst/ctrl/mpexec/version.py +2 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800/python/lsst_ctrl_mpexec.egg-info}/PKG-INFO +1 -1
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cmdLineFwk.py +22 -2
- lsst_ctrl_mpexec-29.2025.1600/python/lsst/ctrl/mpexec/version.py +0 -2
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/COPYRIGHT +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/LICENSE +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/MANIFEST.in +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/README.rst +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/bsd_license.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/CHANGES.rst +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/index.rst +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/pipetask.rst +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/gpl-v3.0.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/pyproject.toml +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/_pipeline_graph_factory.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/cmd/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/opt/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/opt/arguments.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/opt/optionGroups.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/pipetask.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/__init__.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/build.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/cleanup.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/confirmable.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/pre_exec_init_qbb.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/purge.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/qgraph.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/report.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/run.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/script/update_graph_run.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/utils.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/dotTools.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/execFixupDataId.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/executionGraphFixup.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/log_capture.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/mpGraphExecutor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/preExecInit.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/py.typed +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/quantumGraphExecutor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/reports.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/separablePipelineExecutor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/showInfo.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/simple_pipeline_executor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/taskFactory.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/util.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/SOURCES.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/dependency_links.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/entry_points.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/requires.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/top_level.txt +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst_ctrl_mpexec.egg-info/zip-safe +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/setup.cfg +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdCleanup.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdPurge.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdQgraph.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdReport.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdUpdateGraphRun.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliScript.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliUtils.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_execution_storage_class_conversion.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_executors.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_preExecInit.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_reports.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_separablePipelineExecutor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_simple_pipeline_executor.py +0 -0
- {lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_taskFactory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-ctrl-mpexec
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.1800
|
|
4
4
|
Summary: Pipeline execution infrastructure for the Rubin Observatory LSST Science Pipelines.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -285,7 +285,7 @@ The ``taskName`` is the pipeline task label and can either come from the name se
|
|
|
285
285
|
|
|
286
286
|
Here are two examples:
|
|
287
287
|
|
|
288
|
-
- :file:`obs_lsst/config/
|
|
288
|
+
- :file:`obs_lsst/config/makeDirectWarp.py`: specifies which parameters are preferred when warping images using the ``obs_lsst`` observatory package.
|
|
289
289
|
- :file:`obs_lsst/config/latiss/isr.py``: provides overrides for the instrument signature removal (aka detrending) task for the ``latiss`` camera in the ``obs_lsst`` observatory package.
|
|
290
290
|
|
|
291
291
|
Overall, the priority order for setting task configurations is configurations is (highest priority first):
|
|
@@ -311,6 +311,7 @@ def pre_exec_init_qbb(repo: str, qgraph: str, **kwargs: Any) -> None:
|
|
|
311
311
|
@ctrlMpExecOpts.enable_implicit_threading_option()
|
|
312
312
|
@ctrlMpExecOpts.cores_per_quantum_option()
|
|
313
313
|
@ctrlMpExecOpts.memory_per_quantum_option()
|
|
314
|
+
@ctrlMpExecOpts.no_existing_outputs_option()
|
|
314
315
|
def run_qbb(repo: str, qgraph: str, **kwargs: Any) -> None:
|
|
315
316
|
"""Execute pipeline using Quantum-Backed Butler.
|
|
316
317
|
|
|
@@ -396,6 +396,16 @@ clobber_outputs_option = MWOptionDecorator(
|
|
|
396
396
|
)
|
|
397
397
|
|
|
398
398
|
|
|
399
|
+
no_existing_outputs_option = MWOptionDecorator(
|
|
400
|
+
"--no-existing-outputs",
|
|
401
|
+
help=(
|
|
402
|
+
"Assume that no predicted outputs already exist in the output run collection. "
|
|
403
|
+
"This will eliminate existence checks that otherwise run before each quantum is executed."
|
|
404
|
+
),
|
|
405
|
+
is_flag=True,
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
399
409
|
skip_init_writes_option = MWOptionDecorator(
|
|
400
410
|
"--skip-init-writes",
|
|
401
411
|
help=unwrap(
|
|
@@ -53,6 +53,7 @@ def run_qbb(
|
|
|
53
53
|
cores_per_quantum: int,
|
|
54
54
|
memory_per_quantum: str,
|
|
55
55
|
raise_on_partial_outputs: bool,
|
|
56
|
+
no_existing_outputs: bool,
|
|
56
57
|
) -> None:
|
|
57
58
|
"""Implement the command line interface ``pipetask run-qbb`` subcommand.
|
|
58
59
|
|
|
@@ -104,6 +105,9 @@ def run_qbb(
|
|
|
104
105
|
units of MB) or a combination of number and unit.
|
|
105
106
|
raise_on_partial_outputs : `bool`
|
|
106
107
|
Consider partial outputs an error instead of a success.
|
|
108
|
+
no_existing_outputs : `bool`
|
|
109
|
+
Whether to assume that no predicted outputs for these quanta already
|
|
110
|
+
exist in the output run collection.
|
|
107
111
|
"""
|
|
108
112
|
# Fork option still exists for compatibility but we use spawn instead.
|
|
109
113
|
if start_method == "fork":
|
|
@@ -131,6 +135,7 @@ def run_qbb(
|
|
|
131
135
|
cores_per_quantum=cores_per_quantum,
|
|
132
136
|
memory_per_quantum=memory_per_quantum,
|
|
133
137
|
raise_on_partial_outputs=raise_on_partial_outputs,
|
|
138
|
+
no_existing_outputs=no_existing_outputs,
|
|
134
139
|
)
|
|
135
140
|
|
|
136
141
|
f = CmdLineFwk()
|
|
@@ -75,7 +75,7 @@ from lsst.pipe.base.mermaid_tools import graph2mermaid
|
|
|
75
75
|
from lsst.pipe.base.pipeline_graph import NodeType
|
|
76
76
|
from lsst.resources import ResourcePath
|
|
77
77
|
from lsst.utils import doImportType
|
|
78
|
-
from lsst.utils.logging import getLogger
|
|
78
|
+
from lsst.utils.logging import VERBOSE, getLogger
|
|
79
79
|
from lsst.utils.threads import disable_implicit_threading
|
|
80
80
|
|
|
81
81
|
from ._pipeline_graph_factory import PipelineGraphFactory
|
|
@@ -844,7 +844,7 @@ class CmdLineFwk:
|
|
|
844
844
|
_LOG.debug("Will try to import debug.py")
|
|
845
845
|
import debug # type: ignore # noqa:F401
|
|
846
846
|
except ImportError:
|
|
847
|
-
_LOG.
|
|
847
|
+
_LOG.warning("No 'debug' module found.")
|
|
848
848
|
|
|
849
849
|
# Save all InitOutputs, configs, etc.
|
|
850
850
|
preExecInit = PreExecInit(butler, taskFactory, extendRun=args.extend_run)
|
|
@@ -977,6 +977,7 @@ class CmdLineFwk:
|
|
|
977
977
|
return None
|
|
978
978
|
|
|
979
979
|
def preExecInitQBB(self, task_factory: TaskFactory, args: SimpleNamespace) -> None:
|
|
980
|
+
_LOG.verbose("Reading full quantum graph from %s.", args.qgraph)
|
|
980
981
|
# Load quantum graph. We do not really need individual Quanta here,
|
|
981
982
|
# but we need datastore records for initInputs, and those are only
|
|
982
983
|
# available from Quanta, so load the whole thing.
|
|
@@ -986,8 +987,10 @@ class CmdLineFwk:
|
|
|
986
987
|
_ButlerFactory.defineDatastoreCache()
|
|
987
988
|
|
|
988
989
|
# Make QBB.
|
|
990
|
+
_LOG.verbose("Initializing quantum-backed butler.")
|
|
989
991
|
butler = qgraph.make_init_qbb(args.butler_config, config_search_paths=args.config_search_path)
|
|
990
992
|
# Save all InitOutputs, configs, etc.
|
|
993
|
+
_LOG.verbose("Instantiating tasks and saving init-outputs.")
|
|
991
994
|
preExecInit = PreExecInitLimited(butler, task_factory)
|
|
992
995
|
preExecInit.initialize(qgraph)
|
|
993
996
|
|
|
@@ -997,7 +1000,13 @@ class CmdLineFwk:
|
|
|
997
1000
|
|
|
998
1001
|
# Load quantum graph.
|
|
999
1002
|
nodes = args.qgraph_node_id or None
|
|
1000
|
-
|
|
1003
|
+
with lsst.utils.timer.time_this(
|
|
1004
|
+
_LOG,
|
|
1005
|
+
msg=f"Reading {str(len(nodes)) if nodes is not None else 'all'} quanta.",
|
|
1006
|
+
level=VERBOSE,
|
|
1007
|
+
) as qg_read_time:
|
|
1008
|
+
qgraph = QuantumGraph.loadUri(args.qgraph, nodes=nodes, graphID=args.qgraph_id)
|
|
1009
|
+
job_metadata = {"qg_read_time": qg_read_time.duration, "qg_size": len(qgraph)}
|
|
1001
1010
|
|
|
1002
1011
|
if qgraph.metadata is None:
|
|
1003
1012
|
raise ValueError("QuantumGraph is missing metadata, cannot continue.")
|
|
@@ -1023,8 +1032,11 @@ class CmdLineFwk:
|
|
|
1023
1032
|
enableLsstDebug=args.enableLsstDebug,
|
|
1024
1033
|
limited_butler_factory=_butler_factory,
|
|
1025
1034
|
resources=resources,
|
|
1026
|
-
assumeNoExistingOutputs=
|
|
1035
|
+
assumeNoExistingOutputs=args.no_existing_outputs,
|
|
1036
|
+
skipExisting=True,
|
|
1037
|
+
clobberOutputs=True,
|
|
1027
1038
|
raise_on_partial_outputs=args.raise_on_partial_outputs,
|
|
1039
|
+
job_metadata=job_metadata,
|
|
1028
1040
|
)
|
|
1029
1041
|
|
|
1030
1042
|
timeout = self.MP_TIMEOUT if args.timeout is None else args.timeout
|
|
@@ -34,12 +34,13 @@ import logging
|
|
|
34
34
|
import time
|
|
35
35
|
import uuid
|
|
36
36
|
from collections import defaultdict
|
|
37
|
-
from collections.abc import Callable
|
|
37
|
+
from collections.abc import Callable, Mapping
|
|
38
38
|
from itertools import chain
|
|
39
39
|
from typing import Any, cast
|
|
40
40
|
|
|
41
41
|
from lsst.daf.butler import (
|
|
42
42
|
Butler,
|
|
43
|
+
ButlerMetrics,
|
|
43
44
|
CollectionType,
|
|
44
45
|
DatasetRef,
|
|
45
46
|
DatasetType,
|
|
@@ -127,6 +128,11 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
127
128
|
`lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead of
|
|
128
129
|
considering the partial result a success and continuing to run
|
|
129
130
|
downstream tasks.
|
|
131
|
+
job_metadata : `~collections.abc.Mapping`
|
|
132
|
+
Mapping with extra metadata to embed within the quantum metadata under
|
|
133
|
+
the "job" key. This is intended to correspond to information common
|
|
134
|
+
to all quanta being executed in a single process, such as the time
|
|
135
|
+
taken to load the quantum graph in a BPS job.
|
|
130
136
|
"""
|
|
131
137
|
|
|
132
138
|
def __init__(
|
|
@@ -141,6 +147,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
141
147
|
skipExisting: bool = False,
|
|
142
148
|
assumeNoExistingOutputs: bool = False,
|
|
143
149
|
raise_on_partial_outputs: bool = True,
|
|
150
|
+
job_metadata: Mapping[str, int | str | float] | None = None,
|
|
144
151
|
):
|
|
145
152
|
self.butler = butler
|
|
146
153
|
self.taskFactory = taskFactory
|
|
@@ -150,6 +157,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
150
157
|
self.resources = resources
|
|
151
158
|
self.assumeNoExistingOutputs = assumeNoExistingOutputs
|
|
152
159
|
self.raise_on_partial_outputs = raise_on_partial_outputs
|
|
160
|
+
self.job_metadata = job_metadata
|
|
153
161
|
|
|
154
162
|
if self.butler is None:
|
|
155
163
|
assert limited_butler_factory is not None, "limited_butler_factory is needed when butler is None"
|
|
@@ -246,6 +254,8 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
246
254
|
fullMetadata = _TASK_FULL_METADATA_TYPE()
|
|
247
255
|
fullMetadata[task_node.label] = _TASK_METADATA_TYPE()
|
|
248
256
|
fullMetadata["quantum"] = quantumMetadata
|
|
257
|
+
if self.job_metadata is not None:
|
|
258
|
+
fullMetadata["job"] = self.job_metadata
|
|
249
259
|
self.writeMetadata(quantum, fullMetadata, task_node, limited_butler)
|
|
250
260
|
return quantum
|
|
251
261
|
|
|
@@ -255,7 +265,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
255
265
|
_LOG.debug("Will try to import debug.py")
|
|
256
266
|
import debug # type: ignore # noqa:F401
|
|
257
267
|
except ImportError:
|
|
258
|
-
_LOG.
|
|
268
|
+
_LOG.warning("No 'debug' module found.")
|
|
259
269
|
|
|
260
270
|
# initialize global state
|
|
261
271
|
self.initGlobals(quantum)
|
|
@@ -273,7 +283,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
273
283
|
task = self.taskFactory.makeTask(task_node, limited_butler, init_input_refs)
|
|
274
284
|
logInfo(None, "start", metadata=quantumMetadata) # type: ignore[arg-type]
|
|
275
285
|
try:
|
|
276
|
-
caveats, outputsPut = self.runQuantum(
|
|
286
|
+
caveats, outputsPut, butler_metrics = self.runQuantum(
|
|
277
287
|
task, quantum, task_node, limited_butler, quantum_id=quantum_id
|
|
278
288
|
)
|
|
279
289
|
except Exception as e:
|
|
@@ -286,6 +296,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
286
296
|
)
|
|
287
297
|
raise
|
|
288
298
|
else:
|
|
299
|
+
quantumMetadata["butler_metrics"] = butler_metrics.model_dump()
|
|
289
300
|
quantumMetadata["caveats"] = caveats.value
|
|
290
301
|
# Stringify the UUID for easier compatibility with
|
|
291
302
|
# PropertyList.
|
|
@@ -293,6 +304,8 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
293
304
|
logInfo(None, "end", metadata=quantumMetadata) # type: ignore[arg-type]
|
|
294
305
|
fullMetadata = task.getFullMetadata()
|
|
295
306
|
fullMetadata["quantum"] = quantumMetadata
|
|
307
|
+
if self.job_metadata is not None:
|
|
308
|
+
fullMetadata["job"] = self.job_metadata
|
|
296
309
|
self.writeMetadata(quantum, fullMetadata, task_node, limited_butler)
|
|
297
310
|
stopTime = time.time()
|
|
298
311
|
_LOG.info(
|
|
@@ -488,7 +501,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
488
501
|
/,
|
|
489
502
|
limited_butler: LimitedButler,
|
|
490
503
|
quantum_id: uuid.UUID | None = None,
|
|
491
|
-
) -> tuple[QuantumSuccessCaveats, list[uuid.UUID]]:
|
|
504
|
+
) -> tuple[QuantumSuccessCaveats, list[uuid.UUID], ButlerMetrics]:
|
|
492
505
|
"""Execute task on a single quantum.
|
|
493
506
|
|
|
494
507
|
Parameters
|
|
@@ -511,6 +524,8 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
511
524
|
ids_put : list[ `uuid.UUID` ]
|
|
512
525
|
Record of all the dataset IDs that were written by this quantum
|
|
513
526
|
being executed.
|
|
527
|
+
metrics : `lsst.daf.butler.ButlerMetrics`
|
|
528
|
+
Butler metrics recorded for this quantum.
|
|
514
529
|
"""
|
|
515
530
|
flags = QuantumSuccessCaveats.NO_CAVEATS
|
|
516
531
|
|
|
@@ -522,7 +537,8 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
522
537
|
|
|
523
538
|
# Call task runQuantum() method.
|
|
524
539
|
try:
|
|
525
|
-
|
|
540
|
+
with limited_butler.record_metrics() as butler_metrics:
|
|
541
|
+
task.runQuantum(butlerQC, inputRefs, outputRefs)
|
|
526
542
|
except NoWorkFound as err:
|
|
527
543
|
# Not an error, just an early exit.
|
|
528
544
|
_LOG.info(
|
|
@@ -565,7 +581,7 @@ class SingleQuantumExecutor(QuantumExecutor):
|
|
|
565
581
|
if not butlerQC.outputsPut == butlerQC.allOutputs:
|
|
566
582
|
flags |= QuantumSuccessCaveats.ANY_OUTPUTS_MISSING
|
|
567
583
|
ids_put = [output[2] for output in butlerQC.outputsPut]
|
|
568
|
-
return flags, ids_put
|
|
584
|
+
return flags, ids_put, butler_metrics
|
|
569
585
|
|
|
570
586
|
def writeMetadata(
|
|
571
587
|
self, quantum: Quantum, metadata: Any, task_node: TaskNode, /, limited_butler: LimitedButler
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-ctrl-mpexec
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.1800
|
|
4
4
|
Summary: Pipeline execution infrastructure for the Rubin Observatory LSST Science Pipelines.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -656,7 +656,12 @@ class CmdLineFwkTestCaseWithButler(unittest.TestCase):
|
|
|
656
656
|
with tempfile.NamedTemporaryFile(suffix=".qgraph") as temp_graph:
|
|
657
657
|
qgraph.saveUri(temp_graph.name)
|
|
658
658
|
|
|
659
|
-
args = _makeArgs(
|
|
659
|
+
args = _makeArgs(
|
|
660
|
+
butler_config=self.root,
|
|
661
|
+
qgraph=temp_graph.name,
|
|
662
|
+
config_search_path=[],
|
|
663
|
+
no_existing_outputs=False,
|
|
664
|
+
)
|
|
660
665
|
|
|
661
666
|
# Check that pre-exec-init can run.
|
|
662
667
|
fwk.preExecInitQBB(taskFactory, args)
|
|
@@ -670,6 +675,16 @@ class CmdLineFwkTestCaseWithButler(unittest.TestCase):
|
|
|
670
675
|
|
|
671
676
|
self.assertEqual(taskFactory.countExec, self.nQuanta)
|
|
672
677
|
|
|
678
|
+
some_task_label = next(iter(qgraph.pipeline_graph.tasks))
|
|
679
|
+
(some_metadata_ref,) = butler.query_datasets(
|
|
680
|
+
f"{some_task_label}_metadata",
|
|
681
|
+
limit=1,
|
|
682
|
+
collections=output_run,
|
|
683
|
+
)
|
|
684
|
+
some_metadata = butler.get(some_metadata_ref)
|
|
685
|
+
self.assertIn("qg_read_time", some_metadata["job"])
|
|
686
|
+
self.assertIn("qg_size", some_metadata["job"])
|
|
687
|
+
|
|
673
688
|
# Update the output run and try again.
|
|
674
689
|
new_output_run = output_run + "_new"
|
|
675
690
|
qgraph.updateRun(new_output_run, metadata_key="output_run", update_graph_id=True)
|
|
@@ -679,7 +694,12 @@ class CmdLineFwkTestCaseWithButler(unittest.TestCase):
|
|
|
679
694
|
with tempfile.NamedTemporaryFile(suffix=".qgraph") as temp_graph:
|
|
680
695
|
qgraph.saveUri(temp_graph.name)
|
|
681
696
|
|
|
682
|
-
args = _makeArgs(
|
|
697
|
+
args = _makeArgs(
|
|
698
|
+
butler_config=self.root,
|
|
699
|
+
qgraph=temp_graph.name,
|
|
700
|
+
config_search_path=[],
|
|
701
|
+
no_existing_outputs=False,
|
|
702
|
+
)
|
|
683
703
|
|
|
684
704
|
# Check that pre-exec-init can run.
|
|
685
705
|
fwk.preExecInitQBB(taskFactory, args)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/CHANGES.rst
RENAMED
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/index.rst
RENAMED
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/doc/lsst.ctrl.mpexec/pipetask.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/__init__.py
RENAMED
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/cli/utils.py
RENAMED
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/dotTools.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/reports.py
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/showInfo.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/python/lsst/ctrl/mpexec/util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_ctrl_mpexec-29.2025.1600 → lsst_ctrl_mpexec-29.2025.1800}/tests/test_cliCmdUpdateGraphRun.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|