lsst-ctrl-mpexec 29.2025.2100__py3-none-any.whl → 29.2025.3100__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 (28) hide show
  1. lsst/ctrl/mpexec/__init__.py +1 -2
  2. lsst/ctrl/mpexec/cli/cmd/commands.py +1 -1
  3. lsst/ctrl/mpexec/cli/script/pre_exec_init_qbb.py +3 -1
  4. lsst/ctrl/mpexec/cli/script/run.py +2 -1
  5. lsst/ctrl/mpexec/cli/script/run_qbb.py +2 -1
  6. lsst/ctrl/mpexec/cmdLineFwk.py +23 -23
  7. lsst/ctrl/mpexec/execFixupDataId.py +9 -101
  8. lsst/ctrl/mpexec/executionGraphFixup.py +12 -37
  9. lsst/ctrl/mpexec/log_capture.py +9 -195
  10. lsst/ctrl/mpexec/mpGraphExecutor.py +60 -696
  11. lsst/ctrl/mpexec/quantumGraphExecutor.py +20 -90
  12. lsst/ctrl/mpexec/reports.py +30 -206
  13. lsst/ctrl/mpexec/separablePipelineExecutor.py +12 -263
  14. lsst/ctrl/mpexec/simple_pipeline_executor.py +11 -453
  15. lsst/ctrl/mpexec/singleQuantumExecutor.py +75 -532
  16. lsst/ctrl/mpexec/taskFactory.py +12 -38
  17. lsst/ctrl/mpexec/version.py +1 -1
  18. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/METADATA +1 -1
  19. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/RECORD +27 -28
  20. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/WHEEL +1 -1
  21. lsst/ctrl/mpexec/dotTools.py +0 -100
  22. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/entry_points.txt +0 -0
  23. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/licenses/COPYRIGHT +0 -0
  24. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/licenses/LICENSE +0 -0
  25. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/licenses/bsd_license.txt +0 -0
  26. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/licenses/gpl-v3.0.txt +0 -0
  27. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/top_level.txt +0 -0
  28. {lsst_ctrl_mpexec-29.2025.2100.dist-info → lsst_ctrl_mpexec-29.2025.3100.dist-info}/zip-safe +0 -0
@@ -25,462 +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
- from __future__ import annotations
29
-
30
28
  __all__ = ("SimplePipelineExecutor",)
31
29
 
32
- import datetime
33
- import getpass
34
- from collections.abc import Iterable, Iterator, Mapping
35
- from typing import Any
36
-
37
- from lsst.daf.butler import Butler, CollectionType, Quantum
38
- from lsst.pex.config import Config
39
- from lsst.pipe.base import ExecutionResources, Instrument, Pipeline, PipelineGraph, PipelineTask, QuantumGraph
40
- from lsst.pipe.base.all_dimensions_quantum_graph_builder import AllDimensionsQuantumGraphBuilder
41
-
42
- from .preExecInit import PreExecInit
43
- from .singleQuantumExecutor import SingleQuantumExecutor
44
- from .taskFactory import TaskFactory
45
-
46
-
47
- class SimplePipelineExecutor:
48
- """A simple, high-level executor for pipelines.
49
-
50
- Parameters
51
- ----------
52
- quantum_graph : `~lsst.pipe.base.QuantumGraph`
53
- Graph to be executed.
54
- butler : `~lsst.daf.butler.Butler`
55
- Object that manages all I/O. Must be initialized with `collections`
56
- and `run` properties that correspond to the input and output
57
- collections, which must be consistent with those used to create
58
- ``quantum_graph``.
59
- resources : `~lsst.pipe.base.ExecutionResources`
60
- The resources available to each quantum being executed.
61
- raise_on_partial_outputs : `bool`, optional
62
- If `True` raise exceptions chained by
63
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead of
64
- considering the partial result a success and continuing to run
65
- downstream tasks.
66
-
67
- Notes
68
- -----
69
- Most callers should use one of the `classmethod` factory functions
70
- (`from_pipeline_filename`, `from_task_class`, `from_pipeline`) instead of
71
- invoking the constructor directly; these guarantee that the
72
- `~lsst.daf.butler.Butler` and `~lsst.pipe.base.QuantumGraph` are created
73
- consistently.
74
-
75
- This class is intended primarily to support unit testing and small-scale
76
- integration testing of `~lsst.pipe.base.PipelineTask` classes. It
77
- deliberately lacks many features present in the command-line-only
78
- ``pipetask`` tool in order to keep the implementation simple. Python
79
- callers that need more sophistication should call lower-level tools like
80
- `~lsst.pipe.base.quantum_graph_builder.QuantumGraphBuilder`, `PreExecInit`,
81
- and `SingleQuantumExecutor` directly.
82
- """
83
-
84
- def __init__(
85
- self,
86
- quantum_graph: QuantumGraph,
87
- butler: Butler,
88
- resources: ExecutionResources | None = None,
89
- raise_on_partial_outputs: bool = True,
90
- ):
91
- self.quantum_graph = quantum_graph
92
- self.butler = butler
93
- self.resources = resources
94
- self.raise_on_partial_outputs = raise_on_partial_outputs
95
-
96
- @classmethod
97
- def prep_butler(
98
- cls,
99
- root: str,
100
- inputs: Iterable[str],
101
- output: str,
102
- output_run: str | None = None,
103
- ) -> Butler:
104
- """Return configured `~lsst.daf.butler.Butler`.
105
-
106
- Helper method for creating `~lsst.daf.butler.Butler` instances with
107
- collections appropriate for processing.
108
-
109
- Parameters
110
- ----------
111
- root : `str`
112
- Root of the butler data repository; must already exist, with all
113
- necessary input data.
114
- inputs : `~collections.abc.Iterable` [ `str` ]
115
- Collections to search for all input datasets, in search order.
116
- output : `str`
117
- Name of a new output `~lsst.daf.butler.CollectionType.CHAINED`
118
- collection to create that will combine both inputs and outputs.
119
- output_run : `str`, optional
120
- Name of the output `~lsst.daf.butler.CollectionType.RUN` that will
121
- directly hold all output datasets. If not provided, a name will
122
- be created from ``output`` and a timestamp.
123
-
124
- Returns
125
- -------
126
- butler : `~lsst.daf.butler.Butler`
127
- Butler client instance compatible with all `classmethod` factories.
128
- Always writeable.
129
- """
130
- if output_run is None:
131
- output_run = f"{output}/{Instrument.makeCollectionTimestamp()}"
132
- # Make initial butler with no collections, since we haven't created
133
- # them yet.
134
- butler = Butler.from_config(root, writeable=True)
135
- butler.registry.registerCollection(output_run, CollectionType.RUN)
136
- butler.registry.registerCollection(output, CollectionType.CHAINED)
137
- collections = [output_run]
138
- collections.extend(inputs)
139
- butler.registry.setCollectionChain(output, collections)
140
- # Remake butler to let it infer default data IDs from collections, now
141
- # that those collections exist.
142
- return Butler.from_config(butler=butler, collections=[output], run=output_run)
143
-
144
- @classmethod
145
- def from_pipeline_filename(
146
- cls,
147
- pipeline_filename: str,
148
- *,
149
- where: str = "",
150
- bind: Mapping[str, Any] | None = None,
151
- butler: Butler,
152
- resources: ExecutionResources | None = None,
153
- raise_on_partial_outputs: bool = True,
154
- attach_datastore_records: bool = False,
155
- ) -> SimplePipelineExecutor:
156
- """Create an executor by building a QuantumGraph from an on-disk
157
- pipeline YAML file.
158
-
159
- Parameters
160
- ----------
161
- pipeline_filename : `str`
162
- Name of the YAML file to load the pipeline definition from.
163
- where : `str`, optional
164
- Data ID query expression that constraints the quanta generated.
165
- bind : `~collections.abc.Mapping`, optional
166
- Mapping containing literal values that should be injected into the
167
- ``where`` expression, keyed by the identifiers they replace.
168
- butler : `~lsst.daf.butler.Butler`
169
- Butler that manages all I/O. `prep_butler` can be used to create
170
- one.
171
- resources : `~lsst.pipe.base.ExecutionResources`
172
- The resources available to each quantum being executed.
173
- raise_on_partial_outputs : `bool`, optional
174
- If `True` raise exceptions chained by
175
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead
176
- of considering the partial result a success and continuing to run
177
- downstream tasks.
178
- attach_datastore_records : `bool`, optional
179
- Whether to attach datastore records to the quantum graph. This is
180
- usually unnecessary, unless the executor is used to test behavior
181
- that depends on datastore records.
182
-
183
- Returns
184
- -------
185
- executor : `SimplePipelineExecutor`
186
- An executor instance containing the constructed
187
- `~lsst.pipe.base.QuantumGraph` and `~lsst.daf.butler.Butler`, ready
188
- for `run` to be called.
189
- """
190
- pipeline = Pipeline.fromFile(pipeline_filename)
191
- return cls.from_pipeline(
192
- pipeline,
193
- butler=butler,
194
- where=where,
195
- bind=bind,
196
- resources=resources,
197
- raise_on_partial_outputs=raise_on_partial_outputs,
198
- attach_datastore_records=attach_datastore_records,
199
- )
200
-
201
- @classmethod
202
- def from_task_class(
203
- cls,
204
- task_class: type[PipelineTask],
205
- config: Config | None = None,
206
- label: str | None = None,
207
- *,
208
- where: str = "",
209
- bind: Mapping[str, Any] | None = None,
210
- butler: Butler,
211
- resources: ExecutionResources | None = None,
212
- raise_on_partial_outputs: bool = True,
213
- attach_datastore_records: bool = False,
214
- ) -> SimplePipelineExecutor:
215
- """Create an executor by building a QuantumGraph from a pipeline
216
- containing a single task.
217
-
218
- Parameters
219
- ----------
220
- task_class : `type`
221
- A concrete `~lsst.pipe.base.PipelineTask` subclass.
222
- config : `~lsst.pex.config.Config`, optional
223
- Configuration for the task. If not provided, task-level defaults
224
- will be used (no per-instrument overrides).
225
- label : `str`, optional
226
- Label for the task in its pipeline; defaults to
227
- ``task_class._DefaultName``.
228
- where : `str`, optional
229
- Data ID query expression that constraints the quanta generated.
230
- bind : `~collections.abc.Mapping`, optional
231
- Mapping containing literal values that should be injected into the
232
- ``where`` expression, keyed by the identifiers they replace.
233
- butler : `~lsst.daf.butler.Butler`
234
- Butler that manages all I/O. `prep_butler` can be used to create
235
- one.
236
- resources : `~lsst.pipe.base.ExecutionResources`
237
- The resources available to each quantum being executed.
238
- raise_on_partial_outputs : `bool`, optional
239
- If `True` raise exceptions chained by
240
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead
241
- of considering the partial result a success and continuing to run
242
- downstream tasks.
243
- attach_datastore_records : `bool`, optional
244
- Whether to attach datastore records to the quantum graph. This is
245
- usually unnecessary, unless the executor is used to test behavior
246
- that depends on datastore records.
247
-
248
- Returns
249
- -------
250
- executor : `SimplePipelineExecutor`
251
- An executor instance containing the constructed
252
- `~lsst.pipe.base.QuantumGraph` and `~lsst.daf.butler.Butler`, ready
253
- for `run` to be called.
254
- """
255
- if config is None:
256
- config = task_class.ConfigClass()
257
- if label is None:
258
- label = task_class._DefaultName
259
- if not isinstance(config, task_class.ConfigClass):
260
- raise TypeError(
261
- f"Invalid config class type: expected {task_class.ConfigClass.__name__}, "
262
- f"got {type(config).__name__}."
263
- )
264
- pipeline_graph = PipelineGraph()
265
- pipeline_graph.add_task(label=label, task_class=task_class, config=config)
266
- return cls.from_pipeline_graph(
267
- pipeline_graph,
268
- butler=butler,
269
- where=where,
270
- bind=bind,
271
- resources=resources,
272
- raise_on_partial_outputs=raise_on_partial_outputs,
273
- attach_datastore_records=attach_datastore_records,
274
- )
275
-
276
- @classmethod
277
- def from_pipeline(
278
- cls,
279
- pipeline: Pipeline,
280
- *,
281
- where: str = "",
282
- bind: Mapping[str, Any] | None = None,
283
- butler: Butler,
284
- resources: ExecutionResources | None = None,
285
- raise_on_partial_outputs: bool = True,
286
- attach_datastore_records: bool = False,
287
- ) -> SimplePipelineExecutor:
288
- """Create an executor by building a QuantumGraph from an in-memory
289
- pipeline.
290
-
291
- Parameters
292
- ----------
293
- pipeline : `~lsst.pipe.base.Pipeline` or \
294
- `~collections.abc.Iterable` [ `~lsst.pipe.base.TaskDef` ]
295
- A Python object describing the tasks to run, along with their
296
- labels and configuration.
297
- where : `str`, optional
298
- Data ID query expression that constraints the quanta generated.
299
- bind : `~collections.abc.Mapping`, optional
300
- Mapping containing literal values that should be injected into the
301
- ``where`` expression, keyed by the identifiers they replace.
302
- butler : `~lsst.daf.butler.Butler`
303
- Butler that manages all I/O. `prep_butler` can be used to create
304
- one.
305
- resources : `~lsst.pipe.base.ExecutionResources`
306
- The resources available to each quantum being executed.
307
- raise_on_partial_outputs : `bool`, optional
308
- If `True` raise exceptions chained by
309
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead
310
- of considering the partial result a success and continuing to run
311
- downstream tasks.
312
- attach_datastore_records : `bool`, optional
313
- Whether to attach datastore records to the quantum graph. This is
314
- usually unnecessary, unless the executor is used to test behavior
315
- that depends on datastore records.
316
-
317
- Returns
318
- -------
319
- executor : `SimplePipelineExecutor`
320
- An executor instance containing the constructed
321
- `~lsst.pipe.base.QuantumGraph` and `~lsst.daf.butler.Butler`, ready
322
- for `run` to be called.
323
- """
324
- pipeline_graph = pipeline.to_graph()
325
- return cls.from_pipeline_graph(
326
- pipeline_graph,
327
- where=where,
328
- bind=bind,
329
- butler=butler,
330
- resources=resources,
331
- raise_on_partial_outputs=raise_on_partial_outputs,
332
- attach_datastore_records=attach_datastore_records,
333
- )
334
-
335
- @classmethod
336
- def from_pipeline_graph(
337
- cls,
338
- pipeline_graph: PipelineGraph,
339
- *,
340
- where: str = "",
341
- bind: Mapping[str, Any] | None = None,
342
- butler: Butler,
343
- resources: ExecutionResources | None = None,
344
- raise_on_partial_outputs: bool = True,
345
- attach_datastore_records: bool = False,
346
- ) -> SimplePipelineExecutor:
347
- """Create an executor by building a QuantumGraph from an in-memory
348
- pipeline graph.
349
-
350
- Parameters
351
- ----------
352
- pipeline_graph : `~lsst.pipe.base.PipelineGraph`
353
- A Python object describing the tasks to run, along with their
354
- labels and configuration, in graph form. Will be resolved against
355
- the given ``butler``, with any existing resolutions ignored.
356
- where : `str`, optional
357
- Data ID query expression that constraints the quanta generated.
358
- bind : `~collections.abc.Mapping`, optional
359
- Mapping containing literal values that should be injected into the
360
- ``where`` expression, keyed by the identifiers they replace.
361
- butler : `~lsst.daf.butler.Butler`
362
- Butler that manages all I/O. `prep_butler` can be used to create
363
- one. Must have its `~Butler.run` and
364
- `~Butler.collections.defaults` not empty and not `None`.
365
- resources : `~lsst.pipe.base.ExecutionResources`
366
- The resources available to each quantum being executed.
367
- raise_on_partial_outputs : `bool`, optional
368
- If `True` raise exceptions chained by
369
- `lsst.pipe.base.AnnotatedPartialOutputError` immediately, instead
370
- of considering the partial result a success and continuing to run
371
- downstream tasks.
372
- attach_datastore_records : `bool`, optional
373
- Whether to attach datastore records to the quantum graph. This is
374
- usually unnecessary, unless the executor is used to test behavior
375
- that depends on datastore records.
376
-
377
- Returns
378
- -------
379
- executor : `SimplePipelineExecutor`
380
- An executor instance containing the constructed
381
- `~lsst.pipe.base.QuantumGraph` and `~lsst.daf.butler.Butler`, ready
382
- for `run` to be called.
383
- """
384
- quantum_graph_builder = AllDimensionsQuantumGraphBuilder(
385
- pipeline_graph, butler, where=where, bind=bind
386
- )
387
- metadata = {
388
- "input": list(butler.collections.defaults),
389
- "output_run": butler.run,
390
- "skip_existing_in": [],
391
- "skip_existing": False,
392
- "data_query": where,
393
- "user": getpass.getuser(),
394
- "time": str(datetime.datetime.now()),
395
- }
396
- quantum_graph = quantum_graph_builder.build(
397
- metadata=metadata, attach_datastore_records=attach_datastore_records
398
- )
399
- return cls(
400
- quantum_graph=quantum_graph,
401
- butler=butler,
402
- resources=resources,
403
- raise_on_partial_outputs=raise_on_partial_outputs,
404
- )
405
-
406
- def run(self, register_dataset_types: bool = False, save_versions: bool = True) -> list[Quantum]:
407
- """Run all the quanta in the `~lsst.pipe.base.QuantumGraph` in
408
- topological order.
409
-
410
- Use this method to run all quanta in the graph. Use
411
- `as_generator` to get a generator to run the quanta one at
412
- a time.
413
-
414
- Parameters
415
- ----------
416
- register_dataset_types : `bool`, optional
417
- If `True`, register all output dataset types before executing any
418
- quanta.
419
- save_versions : `bool`, optional
420
- If `True` (default), save a package versions dataset.
421
-
422
- Returns
423
- -------
424
- quanta : `list` [ `~lsst.daf.butler.Quantum` ]
425
- Executed quanta.
426
-
427
- Notes
428
- -----
429
- A topological ordering is not in general unique, but no other
430
- guarantees are made about the order in which quanta are processed.
431
- """
432
- return list(
433
- self.as_generator(register_dataset_types=register_dataset_types, save_versions=save_versions)
434
- )
435
-
436
- def as_generator(
437
- self, register_dataset_types: bool = False, save_versions: bool = True
438
- ) -> Iterator[Quantum]:
439
- """Yield quanta in the `~lsst.pipe.base.QuantumGraph` in topological
440
- order.
441
-
442
- These quanta will be run as the returned generator is iterated
443
- over. Use this method to run the quanta one at a time.
444
- Use `run` to run all quanta in the graph.
30
+ from deprecated.sphinx import deprecated
445
31
 
446
- Parameters
447
- ----------
448
- register_dataset_types : `bool`, optional
449
- If `True`, register all output dataset types before executing any
450
- quanta.
451
- save_versions : `bool`, optional
452
- If `True` (default), save a package versions dataset.
32
+ import lsst.pipe.base.simple_pipeline_executor
453
33
 
454
- Returns
455
- -------
456
- quanta : `~collections.abc.Iterator` [ `~lsst.daf.butler.Quantum` ]
457
- Executed quanta.
34
+ # TODO[DM-51962]: Remove this module.
458
35
 
459
- Notes
460
- -----
461
- Global initialization steps (see `PreExecInit`) are performed
462
- immediately when this method is called, but individual quanta are not
463
- actually executed until the returned iterator is iterated over.
464
36
 
465
- A topological ordering is not in general unique, but no other
466
- guarantees are made about the order in which quanta are processed.
467
- """
468
- task_factory = TaskFactory()
469
- pre_exec_init = PreExecInit(self.butler, task_factory)
470
- pre_exec_init.initialize(
471
- graph=self.quantum_graph, registerDatasetTypes=register_dataset_types, saveVersions=save_versions
472
- )
473
- single_quantum_executor = SingleQuantumExecutor(
474
- self.butler,
475
- task_factory,
476
- resources=self.resources,
477
- raise_on_partial_outputs=self.raise_on_partial_outputs,
478
- )
479
- # Important that this returns a generator expression rather than being
480
- # a generator itself; that is what makes the PreExecInit stuff above
481
- # happen immediately instead of when the first quanta is executed,
482
- # which might be useful for callers who want to check the state of the
483
- # repo in between.
484
- return (
485
- single_quantum_executor.execute(qnode.task_node, qnode.quantum)[0] for qnode in self.quantum_graph
486
- )
37
+ @deprecated(
38
+ "The SimplePipelineExecutor class has moved to lsst.pipe.base.simple_pipeline_executor. "
39
+ "This forwarding shim will be removed after v30.",
40
+ version="v30",
41
+ category=FutureWarning,
42
+ )
43
+ class SimplePipelineExecutor(lsst.pipe.base.simple_pipeline_executor.SimplePipelineExecutor): # noqa: D101
44
+ pass