lsst-ctrl-mpexec 29.2025.2400__py3-none-any.whl → 29.2025.3200__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.
Files changed (35) hide show
  1. lsst/ctrl/mpexec/__init__.py +1 -2
  2. lsst/ctrl/mpexec/cli/butler_factory.py +464 -0
  3. lsst/ctrl/mpexec/cli/cmd/commands.py +7 -1
  4. lsst/ctrl/mpexec/cli/opt/optionGroups.py +0 -13
  5. lsst/ctrl/mpexec/cli/opt/options.py +0 -46
  6. lsst/ctrl/mpexec/cli/script/build.py +49 -36
  7. lsst/ctrl/mpexec/cli/script/pre_exec_init_qbb.py +3 -1
  8. lsst/ctrl/mpexec/cli/script/qgraph.py +0 -25
  9. lsst/ctrl/mpexec/cli/script/run.py +2 -1
  10. lsst/ctrl/mpexec/cli/script/run_qbb.py +2 -1
  11. lsst/ctrl/mpexec/cmdLineFwk.py +30 -556
  12. lsst/ctrl/mpexec/execFixupDataId.py +9 -101
  13. lsst/ctrl/mpexec/executionGraphFixup.py +12 -37
  14. lsst/ctrl/mpexec/log_capture.py +9 -195
  15. lsst/ctrl/mpexec/mpGraphExecutor.py +60 -696
  16. lsst/ctrl/mpexec/quantumGraphExecutor.py +20 -90
  17. lsst/ctrl/mpexec/reports.py +30 -206
  18. lsst/ctrl/mpexec/separablePipelineExecutor.py +12 -263
  19. lsst/ctrl/mpexec/showInfo.py +2 -2
  20. lsst/ctrl/mpexec/simple_pipeline_executor.py +11 -590
  21. lsst/ctrl/mpexec/singleQuantumExecutor.py +75 -532
  22. lsst/ctrl/mpexec/taskFactory.py +12 -38
  23. lsst/ctrl/mpexec/version.py +1 -1
  24. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/METADATA +1 -1
  25. lsst_ctrl_mpexec-29.2025.3200.dist-info/RECORD +51 -0
  26. lsst/ctrl/mpexec/dotTools.py +0 -100
  27. lsst_ctrl_mpexec-29.2025.2400.dist-info/RECORD +0 -51
  28. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/WHEEL +0 -0
  29. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/entry_points.txt +0 -0
  30. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/licenses/COPYRIGHT +0 -0
  31. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/licenses/LICENSE +0 -0
  32. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/licenses/bsd_license.txt +0 -0
  33. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/licenses/gpl-v3.0.txt +0 -0
  34. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/top_level.txt +0 -0
  35. {lsst_ctrl_mpexec-29.2025.2400.dist-info → lsst_ctrl_mpexec-29.2025.3200.dist-info}/zip-safe +0 -0
@@ -25,100 +25,30 @@
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
- from __future__ import annotations
28
+ __all__ = ("QuantumExecutor", "QuantumGraphExecutor")
29
29
 
30
- __all__ = ["QuantumExecutor", "QuantumGraphExecutor"]
30
+ from deprecated.sphinx import deprecated
31
31
 
32
- from abc import ABC, abstractmethod
33
- from typing import TYPE_CHECKING
32
+ import lsst.pipe.base.quantum_graph_executor
34
33
 
35
- from .reports import QuantumReport, Report
34
+ # TODO[DM-51962]: Remove this module.
36
35
 
37
- if TYPE_CHECKING:
38
- import uuid
39
36
 
40
- from lsst.daf.butler import Quantum
41
- from lsst.pipe.base import QuantumGraph
42
- from lsst.pipe.base.pipeline_graph import TaskNode
37
+ @deprecated(
38
+ "The QuantumExecutor class has moved to lsst.pipe.base.quantum_graph_executor. "
39
+ "This forwarding shim will be removed after v30.",
40
+ version="v30",
41
+ category=FutureWarning,
42
+ )
43
+ class QuantumExecutor(lsst.pipe.base.quantum_graph_executor.QuantumExecutor): # noqa: D101
44
+ pass
43
45
 
44
46
 
45
- class QuantumExecutor(ABC):
46
- """Class which abstracts execution of a single Quantum.
47
-
48
- In general implementation should not depend on execution model and
49
- execution should always happen in-process. Main reason for existence
50
- of this class is to provide do-nothing implementation that can be used
51
- in the unit tests.
52
- """
53
-
54
- @abstractmethod
55
- def execute(
56
- self, task_node: TaskNode, /, quantum: Quantum, quantum_id: uuid.UUID | None = None
57
- ) -> tuple[Quantum, QuantumReport | None]:
58
- """Execute single quantum.
59
-
60
- Parameters
61
- ----------
62
- task_node : `~lsst.pipe.base.pipeline_graph.TaskNode`
63
- Task definition structure.
64
- quantum : `~lsst.daf.butler.Quantum`
65
- Quantum for this execution.
66
- quantum_id : `uuid.UUID` or `None`, optional
67
- The ID of the quantum to be executed.
68
-
69
- Returns
70
- -------
71
- quantum : `~lsst.daf.butler.Quantum`
72
- The quantum actually executed.
73
- report : `~lsst.ctrl.mpexec.QuantumReport`
74
- Structure describing the status of the execution of a quantum.
75
- `None` is returned if implementation does not support this
76
- feature.
77
-
78
- Notes
79
- -----
80
- Any exception raised by the task or code that wraps task execution is
81
- propagated to the caller of this method.
82
- """
83
- raise NotImplementedError()
84
-
85
-
86
- class QuantumGraphExecutor(ABC):
87
- """Class which abstracts QuantumGraph execution.
88
-
89
- Any specific execution model is implemented in sub-class by overriding
90
- the `execute` method.
91
- """
92
-
93
- @abstractmethod
94
- def execute(self, graph: QuantumGraph) -> None:
95
- """Execute whole graph.
96
-
97
- Implementation of this method depends on particular execution model
98
- and it has to be provided by a subclass. Execution model determines
99
- what happens here; it can be either actual running of the task or,
100
- for example, generation of the scripts for delayed batch execution.
101
-
102
- Parameters
103
- ----------
104
- graph : `~lsst.pipe.base.QuantumGraph`
105
- Execution graph.
106
- """
107
- raise NotImplementedError()
108
-
109
- def getReport(self) -> Report | None:
110
- """Return execution report from last call to `execute`.
111
-
112
- Returns
113
- -------
114
- report : `~lsst.ctrl.mpexec.Report`, optional
115
- Structure describing the status of the execution of a quantum
116
- graph. `None` is returned if implementation does not support
117
- this feature.
118
-
119
- Raises
120
- ------
121
- RuntimeError
122
- Raised if this method is called before `execute`.
123
- """
124
- return None
47
+ @deprecated(
48
+ "The QuantumGraphExecutor class has moved to lsst.pipe.base.quantum_graph_executor. "
49
+ "This forwarding shim will be removed after v30.",
50
+ version="v30",
51
+ category=FutureWarning,
52
+ )
53
+ class QuantumGraphExecutor(lsst.pipe.base.quantum_graph_executor.QuantumGraphExecutor): # noqa: D101
54
+ pass
@@ -25,219 +25,43 @@
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
- from __future__ import annotations
28
+ __all__ = ("ExceptionInfo", "ExecutionStatus", "QuantumReport", "Report")
29
29
 
30
- __all__ = ["ExceptionInfo", "ExecutionStatus", "QuantumReport", "Report"]
30
+ from deprecated.sphinx import deprecated
31
31
 
32
- import enum
33
- import sys
34
- from typing import Any
32
+ import lsst.pipe.base.quantum_reports
35
33
 
36
- import pydantic
34
+ # TODO[DM-51962]: Remove this module.
37
35
 
38
- from lsst.daf.butler import DataCoordinate, DataId, DataIdValue
39
- from lsst.pipe.base import QgraphSummary
40
- from lsst.utils.introspection import get_full_type_name
36
+ # We can't make this shim warn because enums can't be subclassed.
37
+ ExecutionStatus = lsst.pipe.base.quantum_reports.ExecutionStatus
41
38
 
42
39
 
43
- def _serializeDataId(dataId: DataId) -> dict[str, DataIdValue]:
44
- if isinstance(dataId, DataCoordinate):
45
- return dict(dataId.required)
46
- else:
47
- return dataId # type: ignore
40
+ @deprecated(
41
+ "The ExceptionInfo class has moved to lsst.pipe.base.quantum_reports. "
42
+ "This forwarding shim will be removed after v30.",
43
+ version="v30",
44
+ category=FutureWarning,
45
+ )
46
+ class ExceptionInfo(lsst.pipe.base.quantum_reports.ExceptionInfo): # noqa: D101
47
+ pass
48
48
 
49
49
 
50
- class ExecutionStatus(enum.Enum):
51
- """Possible values for job execution status.
50
+ @deprecated(
51
+ "The QuantumReport class has moved to lsst.pipe.base.quantum_reports. "
52
+ "This forwarding shim will be removed after v30.",
53
+ version="v30",
54
+ category=FutureWarning,
55
+ )
56
+ class QuantumReport(lsst.pipe.base.quantum_reports.QuantumReport): # noqa: D101
57
+ pass
52
58
 
53
- Status `FAILURE` is set if one or more tasks failed. Status `TIMEOUT` is
54
- set if there are no failures but one or more tasks timed out. Timeouts can
55
- only be detected in multi-process mode, child task is killed on timeout
56
- and usually should have non-zero exit code.
57
- """
58
59
 
59
- SUCCESS = "success"
60
- FAILURE = "failure"
61
- TIMEOUT = "timeout"
62
- SKIPPED = "skipped"
63
-
64
-
65
- class ExceptionInfo(pydantic.BaseModel):
66
- """Information about exception."""
67
-
68
- className: str
69
- """Name of the exception class if exception was raised."""
70
-
71
- message: str
72
- """Exception message for in-process quantum execution, None if
73
- quantum was executed in sub-process.
74
- """
75
-
76
- @classmethod
77
- def from_exception(cls, exception: Exception) -> ExceptionInfo:
78
- """Construct instance from an exception.
79
-
80
- Parameters
81
- ----------
82
- exception : `Exception`
83
- Exception to wrap.
84
-
85
- Returns
86
- -------
87
- info : `ExceptionInfo`
88
- Information about the exception.
89
- """
90
- return cls(className=get_full_type_name(exception), message=str(exception))
91
-
92
-
93
- class QuantumReport(pydantic.BaseModel):
94
- """Task execution report for a single Quantum.
95
-
96
- Parameters
97
- ----------
98
- dataId : `~lsst.daf.butler.DataId`
99
- Quantum data ID.
100
- taskLabel : `str`
101
- Label for task executing this Quantum.
102
- status : `ExecutionStatus`
103
- Status of this quantum execution.
104
- exitCode : `int` or `None`, optional
105
- Exit code for sub-process executing this Quantum. `None` for
106
- in-process execution. Negative if process was killed by a signal.
107
- exceptionInfo : `ExceptionInfo` or `None`, optional
108
- Exception information if an exception was raised.
109
- """
110
-
111
- status: ExecutionStatus = ExecutionStatus.SUCCESS
112
- """Execution status, one of the values in `ExecutionStatus` enum."""
113
-
114
- dataId: dict[str, DataIdValue]
115
- """Quantum DataId."""
116
-
117
- taskLabel: str | None
118
- """Label for a task executing this Quantum."""
119
-
120
- exitCode: int | None = None
121
- """Exit code for a sub-process executing Quantum, None for in-process
122
- Quantum execution. Negative if process was killed by a signal.
123
- """
124
-
125
- exceptionInfo: ExceptionInfo | None = None
126
- """Exception information if exception was raised."""
127
-
128
- def __init__(
129
- self,
130
- dataId: DataId,
131
- taskLabel: str,
132
- status: ExecutionStatus = ExecutionStatus.SUCCESS,
133
- exitCode: int | None = None,
134
- exceptionInfo: ExceptionInfo | None = None,
135
- ):
136
- super().__init__(
137
- status=status,
138
- dataId=_serializeDataId(dataId),
139
- taskLabel=taskLabel,
140
- exitCode=exitCode,
141
- exceptionInfo=exceptionInfo,
142
- )
143
-
144
- @classmethod
145
- def from_exception(
146
- cls,
147
- exception: Exception,
148
- dataId: DataId,
149
- taskLabel: str,
150
- *,
151
- exitCode: int | None = None,
152
- ) -> QuantumReport:
153
- """Construct report instance from an exception and other pieces of
154
- data.
155
-
156
- Parameters
157
- ----------
158
- exception : `Exception`
159
- Exception caught from processing quantum.
160
- dataId : `~lsst.daf.butler.DataId`
161
- Data ID of quantum.
162
- taskLabel : `str`
163
- Label of task.
164
- exitCode : `int`, optional
165
- Exit code for the process, used when it is known that the process
166
- will exit with that exit code.
167
- """
168
- return cls(
169
- status=ExecutionStatus.FAILURE,
170
- dataId=dataId,
171
- taskLabel=taskLabel,
172
- exitCode=exitCode,
173
- exceptionInfo=ExceptionInfo.from_exception(exception),
174
- )
175
-
176
- @classmethod
177
- def from_exit_code(
178
- cls,
179
- exitCode: int,
180
- dataId: DataId,
181
- taskLabel: str,
182
- ) -> QuantumReport:
183
- """Construct report instance from an exit code and other pieces of
184
- data.
185
-
186
- Parameters
187
- ----------
188
- exitCode : `int`
189
- The exit code of the subprocess.
190
- dataId : `~lsst.daf.butler.DataId`
191
- The quantum Data ID.
192
- taskLabel : `str`
193
- The task label.
194
- """
195
- return cls(
196
- status=ExecutionStatus.SUCCESS if exitCode == 0 else ExecutionStatus.FAILURE,
197
- dataId=dataId,
198
- taskLabel=taskLabel,
199
- exitCode=exitCode,
200
- )
201
-
202
-
203
- class Report(pydantic.BaseModel):
204
- """Execution report for the whole job with one or few quanta."""
205
-
206
- qgraphSummary: QgraphSummary
207
- """Summary report about QuantumGraph."""
208
-
209
- status: ExecutionStatus = ExecutionStatus.SUCCESS
210
- """Job status."""
211
-
212
- cmdLine: list[str] | None = None
213
- """Command line for the whole job."""
214
-
215
- exitCode: int | None = None
216
- """Job exit code, this obviously cannot be set in pipetask."""
217
-
218
- exceptionInfo: ExceptionInfo | None = None
219
- """Exception information if exception was raised."""
220
-
221
- quantaReports: list[QuantumReport] = []
222
- """List of per-quantum reports, ordering is not specified. Some or all
223
- quanta may not produce a report.
224
- """
225
-
226
- # Always want to validate the default value for cmdLine so
227
- # use a model_validator.
228
- @pydantic.model_validator(mode="before")
229
- @classmethod
230
- def _set_cmdLine(cls, data: Any) -> Any:
231
- if data.get("cmdLine") is None:
232
- data["cmdLine"] = sys.argv
233
- return data
234
-
235
- def set_exception(self, exception: Exception) -> None:
236
- """Update exception information from an exception object.
237
-
238
- Parameters
239
- ----------
240
- exception : `Exception`
241
- Exception to use to extract information from.
242
- """
243
- self.exceptionInfo = ExceptionInfo.from_exception(exception)
60
+ @deprecated(
61
+ "The Report class has moved to lsst.pipe.base.quantum_reports. "
62
+ "This forwarding shim will be removed after v30.",
63
+ version="v30",
64
+ category=FutureWarning,
65
+ )
66
+ class Report(lsst.pipe.base.quantum_reports.Report): # noqa: D101
67
+ pass
@@ -25,271 +25,20 @@
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
+ __all__ = ("SeparablePipelineExecutor",)
28
29
 
29
- from __future__ import annotations
30
+ from deprecated.sphinx import deprecated
30
31
 
31
- __all__ = [
32
- "SeparablePipelineExecutor",
33
- ]
32
+ import lsst.pipe.base.separable_pipeline_executor
34
33
 
34
+ # TODO[DM-51962]: Remove this module.
35
35
 
36
- import datetime
37
- import getpass
38
- import logging
39
- from collections.abc import Iterable
40
- from typing import Any
41
36
 
42
- import lsst.pipe.base
43
- import lsst.resources
44
- from lsst.daf.butler import Butler
45
- from lsst.pipe.base.all_dimensions_quantum_graph_builder import AllDimensionsQuantumGraphBuilder
46
- from lsst.pipe.base.quantum_graph_builder import QuantumGraphBuilder
47
-
48
- from .mpGraphExecutor import MPGraphExecutor
49
- from .preExecInit import PreExecInit
50
- from .quantumGraphExecutor import QuantumGraphExecutor
51
- from .singleQuantumExecutor import SingleQuantumExecutor
52
- from .taskFactory import TaskFactory
53
-
54
- _LOG = logging.getLogger(__name__)
55
-
56
-
57
- class SeparablePipelineExecutor:
58
- """An executor that allows each step of pipeline execution to be
59
- run independently.
60
-
61
- The executor can run any or all of the following steps:
62
-
63
- * pre-execution initialization
64
- * pipeline building
65
- * quantum graph generation
66
- * quantum graph execution
67
-
68
- Any of these steps can also be handed off to external code without
69
- compromising the remaining ones.
70
-
71
- Parameters
72
- ----------
73
- butler : `lsst.daf.butler.Butler`
74
- A Butler whose ``collections`` and ``run`` attributes contain the input
75
- and output collections to use for processing.
76
- clobber_output : `bool`, optional
77
- If set, the pipeline execution overwrites existing output files.
78
- Otherwise, any conflict between existing and new outputs is an error.
79
- skip_existing_in : iterable [`str`], optional
80
- If not empty, the pipeline execution searches the listed collections
81
- for existing outputs, and skips any quanta that have run to completion
82
- (or have no work to do). Otherwise, all tasks are attempted (subject to
83
- ``clobber_output``).
84
- task_factory : `lsst.pipe.base.TaskFactory`, optional
85
- A custom task factory for use in pre-execution and execution. By
86
- default, a new instance of `lsst.ctrl.mpexec.TaskFactory` is used.
87
- resources : `~lsst.pipe.base.ExecutionResources`
88
- The resources available to each quantum being executed.
89
- raise_on_partial_outputs : `bool`, optional
90
- If `True` raise exceptions chained by
91
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead of
92
- considering the partial result a success and continuing to run
93
- downstream tasks.
94
- """
95
-
96
- def __init__(
97
- self,
98
- butler: Butler,
99
- clobber_output: bool = False,
100
- skip_existing_in: Iterable[str] | None = None,
101
- task_factory: lsst.pipe.base.TaskFactory | None = None,
102
- resources: lsst.pipe.base.ExecutionResources | None = None,
103
- raise_on_partial_outputs: bool = True,
104
- ):
105
- self._butler = Butler.from_config(
106
- butler=butler, collections=butler.collections.defaults, run=butler.run
107
- )
108
- if not self._butler.collections.defaults:
109
- raise ValueError("Butler must specify input collections for pipeline.")
110
- if not self._butler.run:
111
- raise ValueError("Butler must specify output run for pipeline.")
112
-
113
- self._clobber_output = clobber_output
114
- self._skip_existing_in = list(skip_existing_in) if skip_existing_in else []
115
-
116
- self._task_factory = task_factory if task_factory else TaskFactory()
117
- self.resources = resources
118
- self.raise_on_partial_outputs = raise_on_partial_outputs
119
-
120
- def pre_execute_qgraph(
121
- self,
122
- graph: lsst.pipe.base.QuantumGraph,
123
- register_dataset_types: bool = False,
124
- save_init_outputs: bool = True,
125
- save_versions: bool = True,
126
- ) -> None:
127
- """Run pre-execution initialization.
128
-
129
- This method will be deprecated after DM-38041, to be replaced with a
130
- method that takes either a `~lsst.pipe.base.Pipeline` or a
131
- ``ResolvedPipelineGraph`` instead of a `~lsst.pipe.base.QuantumGraph`.
132
-
133
- Parameters
134
- ----------
135
- graph : `lsst.pipe.base.QuantumGraph`
136
- The quantum graph defining the pipeline and datasets to
137
- be initialized.
138
- register_dataset_types : `bool`, optional
139
- If `True`, register all output dataset types from the pipeline
140
- represented by ``graph``.
141
- save_init_outputs : `bool`, optional
142
- If `True`, create init-output datasets in this object's output run.
143
- save_versions : `bool`, optional
144
- If `True`, save a package versions dataset.
145
- """
146
- pre_exec_init = PreExecInit(self._butler, self._task_factory, extendRun=self._clobber_output)
147
- pre_exec_init.initialize(
148
- graph=graph,
149
- saveInitOutputs=save_init_outputs,
150
- registerDatasetTypes=register_dataset_types,
151
- saveVersions=save_versions,
152
- )
153
-
154
- def make_pipeline(self, pipeline_uri: str | lsst.resources.ResourcePath) -> lsst.pipe.base.Pipeline:
155
- """Build a pipeline from pipeline and configuration information.
156
-
157
- Parameters
158
- ----------
159
- pipeline_uri : `str` or `lsst.resources.ResourcePath`
160
- URI to a file containing a pipeline definition. A URI fragment may
161
- be used to specify a subset of the pipeline, as described in
162
- :ref:`pipeline-running-intro`.
163
-
164
- Returns
165
- -------
166
- pipeline : `lsst.pipe.base.Pipeline`
167
- The fully-built pipeline.
168
- """
169
- return lsst.pipe.base.Pipeline.from_uri(pipeline_uri)
170
-
171
- def make_quantum_graph(
172
- self,
173
- pipeline: lsst.pipe.base.Pipeline,
174
- where: str = "",
175
- *,
176
- builder_class: type[QuantumGraphBuilder] = AllDimensionsQuantumGraphBuilder,
177
- attach_datastore_records: bool = False,
178
- **kwargs: Any,
179
- ) -> lsst.pipe.base.QuantumGraph:
180
- """Build a quantum graph from a pipeline and input datasets.
181
-
182
- Parameters
183
- ----------
184
- pipeline : `lsst.pipe.base.Pipeline`
185
- The pipeline for which to generate a quantum graph.
186
- where : `str`, optional
187
- A data ID query that constrains the quanta generated. Must not be
188
- provided if a custom ``builder_class`` is given and that class does
189
- not accept ``where`` as a construction argument.
190
- builder_class : `type` [ \
191
- `lsst.pipe.base.quantum_graph_builder.QuantumGraphBuilder` ], \
192
- optional
193
- Quantum graph builder implementation. Ignored if ``builder`` is
194
- provided.
195
- attach_datastore_records : `bool`, optional
196
- Whether to attach datastore records. These are currently used only
197
- by `lsst.daf.butler.QuantumBackedButler`, which is not used by
198
- `SeparablePipelineExecutor` for execution.
199
- **kwargs
200
- Additional keyword arguments are forwarded to ``builder_class``
201
- when a quantum graph builder instance is constructed. All
202
- arguments accepted by the
203
- `~lsst.pipe.base.quantum_graph_builder.QuantumGraphBuilder` base
204
- class are provided automatically (from explicit arguments to this
205
- method and executor attributes) and do not need to be included
206
- as keyword arguments.
207
-
208
- Returns
209
- -------
210
- graph : `lsst.pipe.base.QuantumGraph`
211
- The quantum graph for ``pipeline`` as run on the datasets
212
- identified by ``where``.
213
-
214
- Notes
215
- -----
216
- This method does no special handling of empty quantum graphs. If
217
- needed, clients can use `len` to test if the returned graph is empty.
218
- """
219
- metadata = {
220
- "input": self._butler.collections.defaults,
221
- "output_run": self._butler.run,
222
- "skip_existing_in": self._skip_existing_in,
223
- "skip_existing": bool(self._skip_existing_in),
224
- "data_query": where,
225
- "user": getpass.getuser(),
226
- "time": str(datetime.datetime.now()),
227
- }
228
- if where:
229
- # Only pass 'where' if it's actually provided, since some
230
- # QuantumGraphBuilder subclasses may not accept it.
231
- kwargs["where"] = where
232
- qg_builder = builder_class(
233
- pipeline.to_graph(),
234
- self._butler,
235
- skip_existing_in=self._skip_existing_in,
236
- clobber=self._clobber_output,
237
- **kwargs,
238
- )
239
- graph = qg_builder.build(metadata=metadata, attach_datastore_records=attach_datastore_records)
240
- _LOG.info(
241
- "QuantumGraph contains %d quanta for %d tasks, graph ID: %r",
242
- len(graph),
243
- len(graph.taskGraph),
244
- graph.graphID,
245
- )
246
- return graph
247
-
248
- def run_pipeline(
249
- self,
250
- graph: lsst.pipe.base.QuantumGraph,
251
- fail_fast: bool = False,
252
- graph_executor: QuantumGraphExecutor | None = None,
253
- num_proc: int = 1,
254
- ) -> None:
255
- """Run a pipeline in the form of a prepared quantum graph.
256
-
257
- Pre-execution initialization must have already been run;
258
- see `pre_execute_qgraph`.
259
-
260
- Parameters
261
- ----------
262
- graph : `lsst.pipe.base.QuantumGraph`
263
- The pipeline and datasets to execute.
264
- fail_fast : `bool`, optional
265
- If `True`, abort all execution if any task fails when
266
- running with multiple processes. Only used with the default graph
267
- executor).
268
- graph_executor : `lsst.ctrl.mpexec.QuantumGraphExecutor`, optional
269
- A custom graph executor. By default, a new instance of
270
- `lsst.ctrl.mpexec.MPGraphExecutor` is used.
271
- num_proc : `int`, optional
272
- The number of processes that can be used to run the pipeline. The
273
- default value ensures that no subprocess is created. Only used with
274
- the default graph executor.
275
- """
276
- if not graph_executor:
277
- quantum_executor = SingleQuantumExecutor(
278
- self._butler,
279
- self._task_factory,
280
- skipExistingIn=self._skip_existing_in,
281
- clobberOutputs=self._clobber_output,
282
- resources=self.resources,
283
- raise_on_partial_outputs=self.raise_on_partial_outputs,
284
- )
285
- graph_executor = MPGraphExecutor(
286
- numProc=num_proc,
287
- timeout=2_592_000.0, # In practice, timeout is never helpful; set to 30 days.
288
- quantumExecutor=quantum_executor,
289
- failFast=fail_fast,
290
- )
291
- # Have to reset connection pool to avoid sharing connections with
292
- # forked processes.
293
- self._butler.registry.resetConnectionPool()
294
-
295
- graph_executor.execute(graph)
37
+ @deprecated(
38
+ "The SeparablePipelineExecutor class has moved to lsst.pipe.base.separable_pipeline_executor. "
39
+ "This forwarding shim will be removed after v30.",
40
+ version="v30",
41
+ category=FutureWarning,
42
+ )
43
+ class SeparablePipelineExecutor(lsst.pipe.base.separable_pipeline_executor.SeparablePipelineExecutor): # noqa: D101
44
+ pass
@@ -46,7 +46,7 @@ from lsst.pipe.base.pipeline_graph import visualization
46
46
 
47
47
  from . import util
48
48
  from ._pipeline_graph_factory import PipelineGraphFactory
49
- from .cmdLineFwk import _ButlerFactory
49
+ from .cli.butler_factory import ButlerFactory
50
50
 
51
51
 
52
52
  class _FilteredStream:
@@ -385,7 +385,7 @@ class ShowInfo:
385
385
  for compName, compUri in components.items():
386
386
  print(f" {compName}: {compUri}", file=self.stream)
387
387
 
388
- butler = _ButlerFactory.makeReadButler(args)
388
+ butler = ButlerFactory.make_read_butler(args)
389
389
  for node in graph:
390
390
  print(f"Quantum {node.nodeId}: {node.taskDef.taskName}", file=self.stream)
391
391
  print(" inputs:", file=self.stream)