Coverage for tests / test_separable_pipeline_executor.py: 12%
659 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-27 01:20 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-27 01:20 -0800
1# This file is part of pipe_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <https://www.gnu.org/licenses/>.
29import os
30import tempfile
31import unittest
33import lsst.daf.butler
34import lsst.daf.butler.tests as butlerTests
35import lsst.pex.config
36import lsst.utils.tests
37from lsst.daf.butler.registry import RegistryDefaults
38from lsst.pipe.base import (
39 Instrument,
40 Pipeline,
41 PipelineGraph,
42 QuantumAttemptStatus,
43 QuantumGraph,
44 TaskMetadata,
45)
46from lsst.pipe.base.all_dimensions_quantum_graph_builder import AllDimensionsQuantumGraphBuilder
47from lsst.pipe.base.automatic_connection_constants import PACKAGES_INIT_OUTPUT_NAME
48from lsst.pipe.base.quantum_graph_builder import OutputExistsError
49from lsst.pipe.base.separable_pipeline_executor import SeparablePipelineExecutor
50from lsst.resources import ResourcePath
51from lsst.utils.packages import Packages
53TESTDIR = os.path.abspath(os.path.dirname(__file__))
56class SeparablePipelineExecutorTests(lsst.utils.tests.TestCase):
57 """Test the SeparablePipelineExecutor API with a trivial task."""
59 pipeline_file = os.path.join(TESTDIR, "pipelines", "pipeline_separable.yaml")
61 def setUp(self):
62 repodir = tempfile.TemporaryDirectory()
63 # TemporaryDirectory warns on leaks; addCleanup also keeps it from
64 # getting garbage-collected.
65 self.addCleanup(tempfile.TemporaryDirectory.cleanup, repodir)
67 # standalone parameter forces the returned config to also include
68 # the information from the search paths.
69 config = lsst.daf.butler.Butler.makeRepo(
70 repodir.name, standalone=True, searchPaths=[os.path.join(TESTDIR, "config")]
71 )
72 butler = lsst.daf.butler.Butler.from_config(config, writeable=True)
73 self.enterContext(butler)
74 output = "fake"
75 output_run = f"{output}/{Instrument.makeCollectionTimestamp()}"
76 butler.registry.registerCollection(output_run, lsst.daf.butler.CollectionType.RUN)
77 butler.registry.registerCollection(output, lsst.daf.butler.CollectionType.CHAINED)
78 butler.registry.setCollectionChain(output, [output_run])
79 butler.registry.defaults = RegistryDefaults(collections=[output], run=output_run)
80 self.butler = butler
82 butlerTests.addDatasetType(self.butler, "input", set(), "StructuredDataDict")
83 butlerTests.addDatasetType(self.butler, "intermediate", set(), "StructuredDataDict")
84 butlerTests.addDatasetType(self.butler, "a_log", set(), "ButlerLogRecords")
85 butlerTests.addDatasetType(self.butler, "a_metadata", set(), "TaskMetadata")
86 butlerTests.addDatasetType(self.butler, "a_config", set(), "Config")
87 provenance_dataset_type = butlerTests.addDatasetType(
88 self.butler, "run_provenance", set(), "ProvenanceQuantumGraph"
89 )
90 self.provenance_ref = lsst.daf.butler.DatasetRef(
91 provenance_dataset_type,
92 lsst.daf.butler.DataCoordinate.make_empty(self.butler.dimensions),
93 run=butler.run,
94 )
96 def build_empty_quantum_graph(self) -> None:
97 pipeline_graph = PipelineGraph(universe=self.butler.dimensions)
98 pipeline_graph.resolve(self.butler.registry)
99 builder = AllDimensionsQuantumGraphBuilder(pipeline_graph, self.butler)
100 return builder.finish(attach_datastore_records=False).assemble()
102 def check_provenance_fullgraph(self):
103 provenance_qg = self.butler.get(self.provenance_ref)
104 empty_data_id = lsst.daf.butler.DataCoordinate.make_empty(self.butler.dimensions)
105 self.assertCountEqual(provenance_qg.quanta_by_task.keys(), {"a", "b"})
106 self.assertCountEqual(
107 provenance_qg.datasets_by_type.keys(),
108 {
109 "input",
110 "intermediate",
111 "output",
112 "a_config",
113 "b_config",
114 "a_metadata",
115 "b_metadata",
116 "a_log",
117 "b_log",
118 },
119 )
120 a_id = provenance_qg.quanta_by_task["a"][empty_data_id]
121 b_id = provenance_qg.quanta_by_task["b"][empty_data_id]
122 input_id = provenance_qg.datasets_by_type["input"][empty_data_id]
123 intermediate_id = provenance_qg.datasets_by_type["intermediate"][empty_data_id]
124 output_id = provenance_qg.datasets_by_type["output"][empty_data_id]
125 a_metadata_id = provenance_qg.datasets_by_type["a_metadata"][empty_data_id]
126 a_log_id = provenance_qg.datasets_by_type["a_log"][empty_data_id]
127 b_metadata_id = provenance_qg.datasets_by_type["b_metadata"][empty_data_id]
128 b_log_id = provenance_qg.datasets_by_type["b_log"][empty_data_id]
129 self.assertEqual(
130 provenance_qg.bipartite_xgraph.nodes[a_id]["status"], QuantumAttemptStatus.SUCCESSFUL
131 )
132 self.assertEqual(
133 provenance_qg.bipartite_xgraph.nodes[b_id]["status"], QuantumAttemptStatus.SUCCESSFUL
134 )
135 self.assertEqual(list(provenance_qg.bipartite_xgraph.predecessors(a_id)), [input_id])
136 self.assertEqual(
137 list(provenance_qg.bipartite_xgraph.successors(a_id)), [intermediate_id, a_metadata_id, a_log_id]
138 )
139 self.assertEqual(list(provenance_qg.bipartite_xgraph.predecessors(b_id)), [intermediate_id])
140 self.assertEqual(
141 list(provenance_qg.bipartite_xgraph.successors(b_id)), [output_id, b_metadata_id, b_log_id]
142 )
143 for datasets_by_data_id in provenance_qg.datasets_by_type.values():
144 for dataset_id in datasets_by_data_id.values():
145 self.assertTrue(provenance_qg.bipartite_xgraph.nodes[dataset_id]["produced"])
146 logs_pqg = self.butler.get(
147 self.provenance_ref.makeComponentRef("logs"),
148 parameters={"quanta": (a_id,), "datasets": (b_log_id,)},
149 )
150 self.assertEqual(list(logs_pqg[a_id][-1]), list(self.butler.get("a_log", empty_data_id)))
151 self.assertEqual(list(logs_pqg[b_log_id][-1]), list(self.butler.get("b_log", empty_data_id)))
152 metadata_pqg = self.butler.get(
153 self.provenance_ref.makeComponentRef("metadata"),
154 parameters={"quanta": (b_id,), "datasets": (a_metadata_id,)},
155 )
156 self.assertEqual(metadata_pqg[a_metadata_id][-1], self.butler.get("a_metadata", empty_data_id))
157 self.assertEqual(metadata_pqg[b_id][-1], self.butler.get("b_metadata", empty_data_id))
158 self.assertIsInstance(self.butler.get("run_provenance.packages"), Packages)
160 def check_provenance_emptygraph(self):
161 provenance_qg = self.butler.get(self.provenance_ref)
162 self.assertFalse(provenance_qg.bipartite_xgraph)
163 self.assertFalse(any(provenance_qg.quanta_by_task.values()))
164 self.assertFalse(any(provenance_qg.datasets_by_type.values()))
165 self.assertIsInstance(self.butler.get("run_provenance.packages"), Packages)
167 def test_pre_execute_qgraph_old(self):
168 # Too hard to make a quantum graph from scratch.
169 executor = SeparablePipelineExecutor(self.butler)
170 pipeline = Pipeline.fromFile(self.pipeline_file)
171 self.butler.put({"zero": 0}, "input")
172 graph = executor.make_quantum_graph(pipeline)
174 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
175 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
176 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
177 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
178 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
180 executor.pre_execute_qgraph(
181 graph,
182 register_dataset_types=False,
183 save_init_outputs=False,
184 save_versions=False,
185 )
186 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
187 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
189 def test_pre_execute_qgraph(self):
190 # Too hard to make a quantum graph from scratch.
191 executor = SeparablePipelineExecutor(self.butler)
192 pipeline = Pipeline.fromFile(self.pipeline_file)
193 self.butler.put({"zero": 0}, "input")
194 graph = executor.build_quantum_graph(pipeline)
196 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
197 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
198 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
199 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
200 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
202 executor.pre_execute_qgraph(
203 graph,
204 register_dataset_types=False,
205 save_init_outputs=False,
206 save_versions=False,
207 )
208 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
209 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
211 def test_pre_execute_qgraph_unconnected_old(self):
212 # Unconnected graph; see
213 # test_make_quantum_graph_nowhere_skippartial_clobber.
214 executor = SeparablePipelineExecutor(
215 self.butler,
216 skip_existing_in=[self.butler.run],
217 clobber_output=True,
218 )
219 pipeline = Pipeline.fromFile(self.pipeline_file)
220 self.butler.put({"zero": 0}, "input")
221 self.butler.put({"zero": 0}, "intermediate")
222 graph = executor.make_quantum_graph(pipeline)
224 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
225 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
226 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
227 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
228 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
230 executor.pre_execute_qgraph(
231 graph,
232 register_dataset_types=False,
233 save_init_outputs=False,
234 save_versions=False,
235 )
236 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
237 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
239 def test_pre_execute_qgraph_unconnected(self):
240 # Unconnected graph; see
241 # test_make_quantum_graph_nowhere_skippartial_clobber.
242 executor = SeparablePipelineExecutor(
243 self.butler,
244 skip_existing_in=[self.butler.run],
245 clobber_output=True,
246 )
247 pipeline = Pipeline.fromFile(self.pipeline_file)
248 self.butler.put({"zero": 0}, "input")
249 self.butler.put({"zero": 0}, "intermediate")
250 graph = executor.build_quantum_graph(pipeline)
252 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
253 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
254 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
255 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
256 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
258 executor.pre_execute_qgraph(
259 graph,
260 register_dataset_types=False,
261 save_init_outputs=False,
262 save_versions=False,
263 )
264 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
265 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
267 def test_pre_execute_qgraph_empty_old(self):
268 executor = SeparablePipelineExecutor(self.butler)
269 graph = QuantumGraph({}, universe=self.butler.dimensions)
271 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
272 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
273 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
274 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
275 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
277 executor.pre_execute_qgraph(
278 graph,
279 register_dataset_types=False,
280 save_init_outputs=False,
281 save_versions=False,
282 )
283 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
284 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
286 def test_pre_execute_qgraph_empty(self):
287 executor = SeparablePipelineExecutor(self.butler)
288 graph = self.build_empty_quantum_graph()
290 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
291 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
292 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
293 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
294 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
296 executor.pre_execute_qgraph(
297 graph,
298 register_dataset_types=False,
299 save_init_outputs=False,
300 save_versions=False,
301 )
302 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
303 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
305 def test_pre_execute_qgraph_register_old(self):
306 executor = SeparablePipelineExecutor(self.butler)
307 pipeline = Pipeline.fromFile(self.pipeline_file)
308 self.butler.put({"zero": 0}, "input")
309 graph = executor.make_quantum_graph(pipeline)
311 executor.pre_execute_qgraph(
312 graph,
313 register_dataset_types=True,
314 save_init_outputs=False,
315 save_versions=False,
316 )
317 self.assertEqual({d.name for d in self.butler.registry.queryDatasetTypes("output")}, {"output"})
318 self.assertEqual(
319 {d.name for d in self.butler.registry.queryDatasetTypes("b_*")},
320 {"b_config", "b_log", "b_metadata"},
321 )
322 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
323 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
325 def test_pre_execute_qgraph_register(self):
326 executor = SeparablePipelineExecutor(self.butler)
327 pipeline = Pipeline.fromFile(self.pipeline_file)
328 self.butler.put({"zero": 0}, "input")
329 graph = executor.build_quantum_graph(pipeline)
331 executor.pre_execute_qgraph(
332 graph,
333 register_dataset_types=True,
334 save_init_outputs=False,
335 save_versions=False,
336 )
337 self.assertEqual({d.name for d in self.butler.registry.queryDatasetTypes("output")}, {"output"})
338 self.assertEqual(
339 {d.name for d in self.butler.registry.queryDatasetTypes("b_*")},
340 {"b_config", "b_log", "b_metadata"},
341 )
342 self.assertFalse(self.butler.exists("a_config", {}, collections=[self.butler.run]))
343 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
345 def test_pre_execute_qgraph_init_outputs_old(self):
346 # Too hard to make a quantum graph from scratch.
347 executor = SeparablePipelineExecutor(self.butler)
348 pipeline = Pipeline.fromFile(self.pipeline_file)
349 self.butler.put({"zero": 0}, "input")
350 graph = executor.make_quantum_graph(pipeline)
352 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
353 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
354 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
355 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
356 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
358 executor.pre_execute_qgraph(
359 graph,
360 register_dataset_types=False,
361 save_init_outputs=True,
362 save_versions=False,
363 )
364 self.assertTrue(self.butler.exists("a_config", {}, collections=[self.butler.run]))
365 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
367 def test_pre_execute_qgraph_init_outputs(self):
368 # Too hard to make a quantum graph from scratch.
369 executor = SeparablePipelineExecutor(self.butler)
370 pipeline = Pipeline.fromFile(self.pipeline_file)
371 self.butler.put({"zero": 0}, "input")
372 graph = executor.build_quantum_graph(pipeline)
374 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
375 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
376 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
377 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
378 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
380 executor.pre_execute_qgraph(
381 graph,
382 register_dataset_types=False,
383 save_init_outputs=True,
384 save_versions=False,
385 )
386 self.assertTrue(self.butler.exists("a_config", {}, collections=[self.butler.run]))
387 self.assertFalse(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
389 def test_pre_execute_qgraph_versions_old(self):
390 executor = SeparablePipelineExecutor(self.butler)
391 pipeline = Pipeline.fromFile(self.pipeline_file)
392 self.butler.put({"zero": 0}, "input")
393 graph = executor.make_quantum_graph(pipeline)
395 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
396 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
397 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
398 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
399 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
401 executor.pre_execute_qgraph(
402 graph,
403 register_dataset_types=False,
404 save_init_outputs=True,
405 save_versions=True,
406 )
407 self.assertTrue(self.butler.exists("a_config", {}, collections=[self.butler.run]))
408 self.assertTrue(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
410 def test_pre_execute_qgraph_versions(self):
411 executor = SeparablePipelineExecutor(self.butler)
412 pipeline = Pipeline.fromFile(self.pipeline_file)
413 self.butler.put({"zero": 0}, "input")
414 graph = executor.build_quantum_graph(pipeline)
416 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
417 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
418 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
419 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
420 butlerTests.addDatasetType(self.butler, PACKAGES_INIT_OUTPUT_NAME, set(), "Packages")
422 executor.pre_execute_qgraph(
423 graph,
424 register_dataset_types=False,
425 save_init_outputs=True,
426 save_versions=True,
427 )
428 self.assertTrue(self.butler.exists("a_config", {}, collections=[self.butler.run]))
429 self.assertTrue(self.butler.exists(PACKAGES_INIT_OUTPUT_NAME, {}))
431 def test_init_badinput(self):
432 with lsst.daf.butler.Butler.from_config(butler=self.butler, collections=[], run="foo") as butler:
433 with self.assertRaises(ValueError):
434 SeparablePipelineExecutor(butler)
436 def test_init_badoutput(self):
437 with lsst.daf.butler.Butler.from_config(butler=self.butler, collections=["foo"]) as butler:
438 with self.assertRaises(ValueError):
439 SeparablePipelineExecutor(butler)
441 def test_make_pipeline_full(self):
442 executor = SeparablePipelineExecutor(self.butler)
443 for uri in [
444 self.pipeline_file,
445 ResourcePath(self.pipeline_file),
446 ResourcePath(self.pipeline_file).geturl(),
447 ]:
448 pipeline_graph = executor.make_pipeline(uri).to_graph()
449 self.assertEqual(set(pipeline_graph.tasks), {"a", "b"})
451 def test_make_pipeline_subset(self):
452 executor = SeparablePipelineExecutor(self.butler)
453 path = self.pipeline_file + "#a"
454 for uri in [
455 path,
456 ResourcePath(path),
457 ResourcePath(path).geturl(),
458 ]:
459 pipeline_graph = executor.make_pipeline(uri).to_graph()
460 self.assertEqual(set(pipeline_graph.tasks), {"a"})
462 def test_build_quantum_graph_nowhere_noskip_noclobber(self):
463 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
464 pipeline = Pipeline.fromFile(self.pipeline_file)
466 self.butler.put({"zero": 0}, "input")
468 graph = executor.make_quantum_graph(pipeline)
469 self.assertTrue(graph.isConnected)
470 self.assertEqual(len(graph), 2)
471 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"a"})
472 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
474 def test_make_quantum_graph_nowhere_noskip_noclobber(self):
475 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
476 pipeline = Pipeline.fromFile(self.pipeline_file)
478 self.butler.put({"zero": 0}, "input")
480 graph = executor.build_quantum_graph(pipeline)
481 self.assertEqual(len(graph), 2)
482 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
484 def test_make_quantum_graph_nowhere_noskip_noclobber_conflict(self):
485 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
486 pipeline = Pipeline.fromFile(self.pipeline_file)
488 self.butler.put({"zero": 0}, "input")
489 self.butler.put({"zero": 0}, "intermediate")
490 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
491 self.butler.put(TaskMetadata(), "a_metadata")
493 with self.assertRaises(OutputExistsError):
494 executor.build_quantum_graph(pipeline)
496 # TODO: need more complex task and Butler to test
497 # make_quantum_graph(where=...)
499 def test_build_quantum_graph_nowhere_skipnone_noclobber(self):
500 executor = SeparablePipelineExecutor(
501 self.butler,
502 skip_existing_in=[self.butler.run],
503 clobber_output=False,
504 )
505 pipeline = Pipeline.fromFile(self.pipeline_file)
507 self.butler.put({"zero": 0}, "input")
509 graph = executor.make_quantum_graph(pipeline)
510 self.assertTrue(graph.isConnected)
511 self.assertEqual(len(graph), 2)
512 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"a"})
513 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
515 def test_make_quantum_graph_nowhere_skipnone_noclobber(self):
516 executor = SeparablePipelineExecutor(
517 self.butler,
518 skip_existing_in=[self.butler.run],
519 clobber_output=False,
520 )
521 pipeline = Pipeline.fromFile(self.pipeline_file)
522 self.butler.put({"zero": 0}, "input")
523 graph = executor.build_quantum_graph(pipeline)
524 self.assertEqual(len(graph), 2)
525 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
527 def test_build_quantum_graph_nowhere_skiptotal_noclobber(self):
528 executor = SeparablePipelineExecutor(
529 self.butler,
530 skip_existing_in=[self.butler.run],
531 clobber_output=False,
532 )
533 pipeline = Pipeline.fromFile(self.pipeline_file)
535 self.butler.put({"zero": 0}, "input")
536 self.butler.put({"zero": 0}, "intermediate")
537 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
538 self.butler.put(TaskMetadata(), "a_metadata")
539 self.butler.put(lsst.pex.config.Config(), "a_config")
541 graph = executor.make_quantum_graph(pipeline)
542 self.assertTrue(graph.isConnected)
543 self.assertEqual(len(graph), 1)
544 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"b"})
545 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
547 def test_make_quantum_graph_nowhere_skiptotal_noclobber(self):
548 executor = SeparablePipelineExecutor(
549 self.butler,
550 skip_existing_in=[self.butler.run],
551 clobber_output=False,
552 )
553 pipeline = Pipeline.fromFile(self.pipeline_file)
555 self.butler.put({"zero": 0}, "input")
556 self.butler.put({"zero": 0}, "intermediate")
557 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
558 self.butler.put(TaskMetadata(), "a_metadata")
559 self.butler.put(lsst.pex.config.Config(), "a_config")
561 graph = executor.build_quantum_graph(pipeline)
562 self.assertEqual(len(graph), 1)
563 self.assertEqual(graph.header.n_task_quanta["a"], 0)
564 self.assertEqual(graph.header.n_task_quanta["b"], 1)
566 def test_make_quantum_graph_nowhere_skippartial_noclobber(self):
567 executor = SeparablePipelineExecutor(
568 self.butler,
569 skip_existing_in=[self.butler.run],
570 clobber_output=False,
571 )
572 pipeline = Pipeline.fromFile(self.pipeline_file)
574 self.butler.put({"zero": 0}, "input")
575 self.butler.put({"zero": 0}, "intermediate")
577 with self.assertRaises(OutputExistsError):
578 executor.build_quantum_graph(pipeline)
580 def test_build_quantum_graph_nowhere_noskip_clobber(self):
581 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
582 pipeline = Pipeline.fromFile(self.pipeline_file)
584 self.butler.put({"zero": 0}, "input")
586 graph = executor.make_quantum_graph(pipeline)
587 self.assertTrue(graph.isConnected)
588 self.assertEqual(len(graph), 2)
589 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"a"})
590 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
592 def test_make_quantum_graph_nowhere_noskip_clobber(self):
593 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
594 pipeline = Pipeline.fromFile(self.pipeline_file)
595 self.butler.put({"zero": 0}, "input")
596 graph = executor.build_quantum_graph(pipeline)
597 self.assertEqual(len(graph), 2)
598 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
600 def test_build_quantum_graph_nowhere_noskip_clobber_conflict(self):
601 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
602 pipeline = Pipeline.fromFile(self.pipeline_file)
604 self.butler.put({"zero": 0}, "input")
605 self.butler.put({"zero": 0}, "intermediate")
606 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
607 self.butler.put(TaskMetadata(), "a_metadata")
609 graph = executor.make_quantum_graph(pipeline)
610 self.assertTrue(graph.isConnected)
611 self.assertEqual(len(graph), 2)
612 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"a"})
613 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
615 def test_make_quantum_graph_nowhere_noskip_clobber_conflict(self):
616 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
617 pipeline = Pipeline.fromFile(self.pipeline_file)
618 self.butler.put({"zero": 0}, "input")
619 self.butler.put({"zero": 0}, "intermediate")
620 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
621 self.butler.put(TaskMetadata(), "a_metadata")
622 graph = executor.build_quantum_graph(pipeline)
623 self.assertEqual(len(graph), 2)
624 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
626 def test_build_quantum_graph_nowhere_skipnone_clobber(self):
627 executor = SeparablePipelineExecutor(
628 self.butler,
629 skip_existing_in=[self.butler.run],
630 clobber_output=True,
631 )
632 pipeline = Pipeline.fromFile(self.pipeline_file)
634 self.butler.put({"zero": 0}, "input")
636 graph = executor.make_quantum_graph(pipeline)
637 self.assertTrue(graph.isConnected)
638 self.assertEqual(len(graph), 2)
639 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"a"})
640 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
642 def test_make_quantum_graph_nowhere_skipnone_clobber(self):
643 executor = SeparablePipelineExecutor(
644 self.butler,
645 skip_existing_in=[self.butler.run],
646 clobber_output=True,
647 )
648 pipeline = Pipeline.fromFile(self.pipeline_file)
649 self.butler.put({"zero": 0}, "input")
650 graph = executor.build_quantum_graph(pipeline)
651 self.assertEqual(len(graph), 2)
652 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
654 def test_make_quantum_graph_nowhere_skiptotal_clobber(self):
655 executor = SeparablePipelineExecutor(
656 self.butler,
657 skip_existing_in=[self.butler.run],
658 clobber_output=True,
659 )
660 pipeline = Pipeline.fromFile(self.pipeline_file)
662 self.butler.put({"zero": 0}, "input")
663 self.butler.put({"zero": 0}, "intermediate")
664 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
665 self.butler.put(TaskMetadata(), "a_metadata")
666 self.butler.put(lsst.pex.config.Config(), "a_config")
668 graph = executor.make_quantum_graph(pipeline)
669 self.assertTrue(graph.isConnected)
670 self.assertEqual(len(graph), 1)
671 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"b"})
672 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
674 def test_build_quantum_graph_nowhere_skiptotal_clobber(self):
675 executor = SeparablePipelineExecutor(
676 self.butler,
677 skip_existing_in=[self.butler.run],
678 clobber_output=True,
679 )
680 pipeline = Pipeline.fromFile(self.pipeline_file)
682 self.butler.put({"zero": 0}, "input")
683 self.butler.put({"zero": 0}, "intermediate")
684 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
685 self.butler.put(TaskMetadata(), "a_metadata")
686 self.butler.put(lsst.pex.config.Config(), "a_config")
688 graph = executor.make_quantum_graph(pipeline)
689 self.assertTrue(graph.isConnected)
690 self.assertEqual(len(graph), 1)
691 self.assertEqual({q.taskDef.label for q in graph.inputQuanta}, {"b"})
692 self.assertEqual({q.taskDef.label for q in graph.outputQuanta}, {"b"})
694 def test_make_quantum_graph_nowhere_skippartial_clobber(self):
695 executor = SeparablePipelineExecutor(
696 self.butler,
697 skip_existing_in=[self.butler.run],
698 clobber_output=True,
699 )
700 pipeline = Pipeline.fromFile(self.pipeline_file)
701 self.butler.put({"zero": 0}, "input")
702 self.butler.put({"zero": 0}, "intermediate")
703 graph = executor.build_quantum_graph(pipeline)
704 self.assertEqual(len(graph), 2)
705 self.assertEqual(graph.quanta_by_task.keys(), {"a", "b"})
707 def test_make_quantum_graph_noinput(self):
708 executor = SeparablePipelineExecutor(self.butler)
709 pipeline = Pipeline.fromFile(self.pipeline_file)
711 graph = executor.make_quantum_graph(pipeline)
712 self.assertEqual(len(graph), 0)
714 def test_build_quantum_graph_noinput(self):
715 executor = SeparablePipelineExecutor(self.butler)
716 pipeline = Pipeline.fromFile(self.pipeline_file)
718 graph = executor.build_quantum_graph(pipeline)
719 self.assertEqual(len(graph), 0)
721 def test_make_quantum_graph_alloutput_skip(self):
722 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=[self.butler.run])
723 pipeline = Pipeline.fromFile(self.pipeline_file)
725 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
726 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
727 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
728 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
730 self.butler.put({"zero": 0}, "input")
731 self.butler.put({"zero": 0}, "intermediate")
732 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
733 self.butler.put(TaskMetadata(), "a_metadata")
734 self.butler.put({"zero": 0}, "output")
735 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "b_log")
736 self.butler.put(TaskMetadata(), "b_metadata")
737 self.butler.put(lsst.pex.config.Config(), "a_config")
738 self.butler.put(lsst.pex.config.Config(), "b_config")
740 graph = executor.make_quantum_graph(pipeline)
741 self.assertEqual(len(graph), 0)
743 def test_build_quantum_graph_alloutput_skip(self):
744 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=[self.butler.run])
745 pipeline = Pipeline.fromFile(self.pipeline_file)
747 butlerTests.addDatasetType(self.butler, "output", set(), "StructuredDataDict")
748 butlerTests.addDatasetType(self.butler, "b_log", set(), "ButlerLogRecords")
749 butlerTests.addDatasetType(self.butler, "b_metadata", set(), "TaskMetadata")
750 butlerTests.addDatasetType(self.butler, "b_config", set(), "Config")
752 self.butler.put({"zero": 0}, "input")
753 self.butler.put({"zero": 0}, "intermediate")
754 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
755 self.butler.put(TaskMetadata(), "a_metadata")
756 self.butler.put({"zero": 0}, "output")
757 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "b_log")
758 self.butler.put(TaskMetadata(), "b_metadata")
759 self.butler.put(lsst.pex.config.Config(), "a_config")
760 self.butler.put(lsst.pex.config.Config(), "b_config")
762 graph = executor.build_quantum_graph(pipeline)
763 self.assertEqual(len(graph), 0)
765 def test_run_pipeline_noskip_noclobber_fullgraph(self):
766 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
767 pipeline = Pipeline.fromFile(self.pipeline_file)
768 self.butler.put({"zero": 0}, "input")
769 graph = executor.make_quantum_graph(pipeline)
770 executor.pre_execute_qgraph(
771 graph,
772 register_dataset_types=True,
773 save_init_outputs=True,
774 save_versions=False,
775 )
777 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
778 self.butler.registry.refresh()
779 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
780 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
781 self.check_provenance_fullgraph()
783 def test_run_pipeline_noskip_noclobber_fullgraph_old(self):
784 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
785 pipeline = Pipeline.fromFile(self.pipeline_file)
786 self.butler.put({"zero": 0}, "input")
787 graph = executor.build_quantum_graph(pipeline)
788 executor.pre_execute_qgraph(
789 graph,
790 register_dataset_types=True,
791 save_init_outputs=True,
792 save_versions=False,
793 )
795 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
796 self.butler.registry.refresh()
797 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
798 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
799 self.check_provenance_fullgraph()
801 def test_run_pipeline_noskip_noclobber_emptygraph_old(self):
802 old_repo_size = self.butler.registry.queryDatasets(...).count()
804 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
805 graph = QuantumGraph({}, universe=self.butler.dimensions)
806 executor.pre_execute_qgraph(
807 graph,
808 register_dataset_types=True,
809 save_init_outputs=True,
810 save_versions=False,
811 )
813 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
814 self.butler.registry.refresh()
815 # Empty graph execution should do nothing but write provenance.
816 self.assertEqual(self.butler.registry.queryDatasets(...).count(), old_repo_size + 1)
817 self.check_provenance_emptygraph()
819 def test_run_pipeline_noskip_noclobber_emptygraph(self):
820 old_repo_size = self.butler.registry.queryDatasets(...).count()
822 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=False)
823 graph = self.build_empty_quantum_graph()
824 executor.pre_execute_qgraph(
825 graph,
826 register_dataset_types=True,
827 save_init_outputs=True,
828 save_versions=False,
829 )
831 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
832 self.butler.registry.refresh()
833 # Empty graph execution should do nothing but write provenance.
834 self.assertEqual(self.butler.registry.queryDatasets(...).count(), old_repo_size + 1)
835 self.check_provenance_emptygraph()
837 def test_run_pipeline_skipnone_noclobber_old(self):
838 executor = SeparablePipelineExecutor(
839 self.butler,
840 skip_existing_in=[self.butler.run],
841 clobber_output=False,
842 )
843 pipeline = Pipeline.fromFile(self.pipeline_file)
844 self.butler.put({"zero": 0}, "input")
845 graph = executor.make_quantum_graph(pipeline)
846 executor.pre_execute_qgraph(
847 graph,
848 register_dataset_types=True,
849 save_init_outputs=True,
850 save_versions=False,
851 )
853 executor.run_pipeline(graph)
854 self.butler.registry.refresh()
855 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
856 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
858 def test_run_pipeline_skipnone_noclobber(self):
859 executor = SeparablePipelineExecutor(
860 self.butler,
861 skip_existing_in=[self.butler.run],
862 clobber_output=False,
863 )
864 pipeline = Pipeline.fromFile(self.pipeline_file)
865 self.butler.put({"zero": 0}, "input")
866 graph = executor.build_quantum_graph(pipeline)
867 executor.pre_execute_qgraph(
868 graph,
869 register_dataset_types=True,
870 save_init_outputs=True,
871 save_versions=False,
872 )
874 executor.run_pipeline(graph)
875 self.butler.registry.refresh()
876 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
877 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
879 def test_run_pipeline_skiptotal_noclobber_old(self):
880 executor = SeparablePipelineExecutor(
881 self.butler,
882 skip_existing_in=[self.butler.run],
883 clobber_output=False,
884 )
885 pipeline = Pipeline.fromFile(self.pipeline_file)
886 self.butler.put({"zero": 0}, "input")
887 self.butler.put({"zero": 0}, "intermediate")
888 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
889 self.butler.put(TaskMetadata(), "a_metadata")
890 self.butler.put(lsst.pex.config.Config(), "a_config")
891 graph = executor.make_quantum_graph(pipeline)
892 executor.pre_execute_qgraph(
893 graph,
894 register_dataset_types=True,
895 save_init_outputs=True,
896 save_versions=False,
897 )
899 executor.run_pipeline(graph)
900 self.butler.registry.refresh()
901 self.assertEqual(self.butler.get("output"), {"zero": 0, "two": 2})
903 def test_run_pipeline_skiptotal_noclobber(self):
904 executor = SeparablePipelineExecutor(
905 self.butler,
906 skip_existing_in=[self.butler.run],
907 clobber_output=False,
908 )
909 pipeline = Pipeline.fromFile(self.pipeline_file)
910 self.butler.put({"zero": 0}, "input")
911 self.butler.put({"zero": 0}, "intermediate")
912 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
913 self.butler.put(TaskMetadata(), "a_metadata")
914 self.butler.put(lsst.pex.config.Config(), "a_config")
915 graph = executor.build_quantum_graph(pipeline)
916 executor.pre_execute_qgraph(
917 graph,
918 register_dataset_types=True,
919 save_init_outputs=True,
920 save_versions=False,
921 )
923 executor.run_pipeline(graph)
924 self.butler.registry.refresh()
925 self.assertEqual(self.butler.get("output"), {"zero": 0, "two": 2})
927 def test_run_pipeline_noskip_clobber_connected_old(self):
928 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
929 pipeline = Pipeline.fromFile(self.pipeline_file)
930 self.butler.put({"zero": 0}, "input")
931 graph = executor.make_quantum_graph(pipeline)
932 executor.pre_execute_qgraph(
933 graph,
934 register_dataset_types=True,
935 save_init_outputs=True,
936 save_versions=False,
937 )
939 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
940 self.butler.registry.refresh()
941 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
942 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
943 self.check_provenance_fullgraph()
945 def test_run_pipeline_noskip_clobber_connected(self):
946 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
947 pipeline = Pipeline.fromFile(self.pipeline_file)
948 self.butler.put({"zero": 0}, "input")
949 graph = executor.build_quantum_graph(pipeline)
950 executor.pre_execute_qgraph(
951 graph,
952 register_dataset_types=True,
953 save_init_outputs=True,
954 save_versions=False,
955 )
957 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
958 self.butler.registry.refresh()
959 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
960 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
961 self.check_provenance_fullgraph()
963 def test_run_pipeline_noskip_clobber_unconnected_old(self):
964 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
965 pipeline = Pipeline.fromFile(self.pipeline_file)
966 self.butler.put({"zero": 0}, "input")
967 self.butler.put({"zero": 0}, "intermediate")
968 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
969 self.butler.put(TaskMetadata(), "a_metadata")
970 graph = executor.make_quantum_graph(pipeline)
971 executor.pre_execute_qgraph(
972 graph,
973 register_dataset_types=True,
974 save_init_outputs=True,
975 save_versions=False,
976 )
978 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
979 self.butler.registry.refresh()
980 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
981 # The value of output is undefined; it depends on which task ran first.
982 self.assertTrue(self.butler.exists("output", {}))
984 def test_run_pipeline_noskip_clobber_unconnected(self):
985 executor = SeparablePipelineExecutor(self.butler, skip_existing_in=None, clobber_output=True)
986 pipeline = Pipeline.fromFile(self.pipeline_file)
987 self.butler.put({"zero": 0}, "input")
988 self.butler.put({"zero": 0}, "intermediate")
989 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
990 self.butler.put(TaskMetadata(), "a_metadata")
991 graph = executor.build_quantum_graph(pipeline)
992 executor.pre_execute_qgraph(
993 graph,
994 register_dataset_types=True,
995 save_init_outputs=True,
996 save_versions=False,
997 )
999 executor.run_pipeline(graph, provenance_dataset_ref=self.provenance_ref)
1000 self.butler.registry.refresh()
1001 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
1002 # The value of output is undefined; it depends on which task ran first.
1003 self.assertTrue(self.butler.exists("output", {}))
1004 self.check_provenance_fullgraph()
1006 def test_run_pipeline_skipnone_clobber_old(self):
1007 executor = SeparablePipelineExecutor(
1008 self.butler,
1009 skip_existing_in=[self.butler.run],
1010 clobber_output=True,
1011 )
1012 pipeline = Pipeline.fromFile(self.pipeline_file)
1013 self.butler.put({"zero": 0}, "input")
1014 graph = executor.make_quantum_graph(pipeline)
1015 executor.pre_execute_qgraph(
1016 graph,
1017 register_dataset_types=True,
1018 save_init_outputs=True,
1019 save_versions=False,
1020 )
1022 executor.run_pipeline(graph)
1023 self.butler.registry.refresh()
1024 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
1025 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
1027 def test_run_pipeline_skipnone_clobber(self):
1028 executor = SeparablePipelineExecutor(
1029 self.butler,
1030 skip_existing_in=[self.butler.run],
1031 clobber_output=True,
1032 )
1033 pipeline = Pipeline.fromFile(self.pipeline_file)
1034 self.butler.put({"zero": 0}, "input")
1035 graph = executor.build_quantum_graph(pipeline)
1036 executor.pre_execute_qgraph(
1037 graph,
1038 register_dataset_types=True,
1039 save_init_outputs=True,
1040 save_versions=False,
1041 )
1043 executor.run_pipeline(graph)
1044 self.butler.registry.refresh()
1045 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
1046 self.assertEqual(self.butler.get("output"), {"zero": 0, "one": 1, "two": 2})
1048 def test_run_pipeline_skiptotal_clobber_connected_old(self):
1049 executor = SeparablePipelineExecutor(
1050 self.butler,
1051 skip_existing_in=[self.butler.run],
1052 clobber_output=True,
1053 )
1054 pipeline = Pipeline.fromFile(self.pipeline_file)
1055 self.butler.put({"zero": 0}, "input")
1056 self.butler.put({"zero": 0}, "intermediate")
1057 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
1058 self.butler.put(TaskMetadata(), "a_metadata")
1059 self.butler.put(lsst.pex.config.Config(), "a_config")
1060 graph = executor.make_quantum_graph(pipeline)
1061 executor.pre_execute_qgraph(
1062 graph,
1063 register_dataset_types=True,
1064 save_init_outputs=True,
1065 save_versions=False,
1066 )
1068 executor.run_pipeline(graph)
1069 self.butler.registry.refresh()
1070 self.assertEqual(self.butler.get("output"), {"zero": 0, "two": 2})
1072 def test_run_pipeline_skiptotal_clobber_connected(self):
1073 executor = SeparablePipelineExecutor(
1074 self.butler,
1075 skip_existing_in=[self.butler.run],
1076 clobber_output=True,
1077 )
1078 pipeline = Pipeline.fromFile(self.pipeline_file)
1079 self.butler.put({"zero": 0}, "input")
1080 self.butler.put({"zero": 0}, "intermediate")
1081 self.butler.put(lsst.daf.butler.ButlerLogRecords.from_records([]), "a_log")
1082 self.butler.put(TaskMetadata(), "a_metadata")
1083 self.butler.put(lsst.pex.config.Config(), "a_config")
1084 graph = executor.build_quantum_graph(pipeline)
1085 executor.pre_execute_qgraph(
1086 graph,
1087 register_dataset_types=True,
1088 save_init_outputs=True,
1089 save_versions=False,
1090 )
1092 executor.run_pipeline(graph)
1093 self.butler.registry.refresh()
1094 self.assertEqual(self.butler.get("output"), {"zero": 0, "two": 2})
1096 def test_run_pipeline_skippartial_clobber_unconnected_old(self):
1097 executor = SeparablePipelineExecutor(
1098 self.butler,
1099 skip_existing_in=[self.butler.run],
1100 clobber_output=True,
1101 )
1102 pipeline = Pipeline.fromFile(self.pipeline_file)
1103 self.butler.put({"zero": 0}, "input")
1104 self.butler.put({"zero": 0}, "intermediate")
1105 graph = executor.make_quantum_graph(pipeline)
1106 executor.pre_execute_qgraph(
1107 graph,
1108 register_dataset_types=True,
1109 save_init_outputs=True,
1110 save_versions=False,
1111 )
1113 executor.run_pipeline(graph)
1114 self.butler.registry.refresh()
1115 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
1116 # The value of output is undefined; it depends on which task ran first.
1117 self.assertTrue(self.butler.exists("output", {}))
1119 def test_run_pipeline_skippartial_clobber_unconnected(self):
1120 executor = SeparablePipelineExecutor(
1121 self.butler,
1122 skip_existing_in=[self.butler.run],
1123 clobber_output=True,
1124 )
1125 pipeline = Pipeline.fromFile(self.pipeline_file)
1126 self.butler.put({"zero": 0}, "input")
1127 self.butler.put({"zero": 0}, "intermediate")
1128 graph = executor.build_quantum_graph(pipeline)
1129 executor.pre_execute_qgraph(
1130 graph,
1131 register_dataset_types=True,
1132 save_init_outputs=True,
1133 save_versions=False,
1134 )
1135 executor.run_pipeline(graph)
1136 self.butler.registry.refresh()
1137 self.assertEqual(self.butler.get("intermediate"), {"zero": 0, "one": 1})
1138 # The value of output is undefined; it depends on which task ran first.
1139 self.assertTrue(self.butler.exists("output", {}))
1142class MemoryTester(lsst.utils.tests.MemoryTestCase):
1143 """Generic test for file leaks."""
1146def setup_module(module):
1147 """Set up the module for pytest.
1149 Parameters
1150 ----------
1151 module : `~types.ModuleType`
1152 Module to set up.
1153 """
1154 lsst.utils.tests.init()
1157if __name__ == "__main__":
1158 lsst.utils.tests.init()
1159 unittest.main()