lsst-pipe-base 30.0.0__tar.gz → 30.0.0rc2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lsst_pipe_base-30.0.0/python/lsst_pipe_base.egg-info → lsst_pipe_base-30.0.0rc2}/PKG-INFO +1 -1
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/CHANGES.rst +0 -66
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_instrument.py +5 -6
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/log_capture.py +79 -39
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/mp_graph_executor.py +15 -51
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_common.py +3 -4
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_multiblock.py +16 -6
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_predicted.py +12 -106
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_provenance.py +6 -657
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/_communicators.py +50 -18
- lsst_pipe_base-30.0.0rc2/python/lsst/pipe/base/quantum_graph/aggregator/_scanner.py +511 -0
- lsst_pipe_base-30.0.0rc2/python/lsst/pipe/base/quantum_graph/aggregator/_structs.py +177 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/_supervisor.py +5 -10
- lsst_pipe_base-30.0.0rc2/python/lsst/pipe/base/quantum_graph/aggregator/_writer.py +501 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph_builder.py +1 -12
- lsst_pipe_base-30.0.0rc2/python/lsst/pipe/base/quantum_graph_executor.py +126 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph_skeleton.py +7 -1
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/separable_pipeline_executor.py +2 -18
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/single_quantum_executor.py +35 -53
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/version.py +1 -1
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2/python/lsst_pipe_base.egg-info}/PKG-INFO +1 -1
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/SOURCES.txt +0 -2
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_separable_pipeline_executor.py +13 -101
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/log_on_close.py +0 -79
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/quantum_graph/aggregator/_scanner.py +0 -317
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/quantum_graph/aggregator/_structs.py +0 -67
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/quantum_graph/aggregator/_writer.py +0 -184
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/quantum_graph/formatter.py +0 -101
- lsst_pipe_base-30.0.0/python/lsst/pipe/base/quantum_graph_executor.py +0 -229
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/COPYRIGHT +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/LICENSE +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/MANIFEST.in +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/README.md +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/bsd_license.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/creating-a-pipeline.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/creating-a-pipelinetask.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/creating-a-task.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/index.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/task-framework-overview.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/task-retargeting-howto.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/testing-a-pipeline-task.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/testing-pipelines-with-mocks.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/doc/lsst.pipe.base/working-with-pipeline-graphs.rst +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/gpl-v3.0.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/pyproject.toml +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_datasetQueryConstraints.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_dataset_handle.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_observation_dimension_packer.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_quantumContext.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_status.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/_task_metadata.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/all_dimensions_quantum_graph_builder.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/automatic_connection_constants.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/caching_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/_get_cli_subcommands.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/cmd/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/cmd/commands.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/opt/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/opt/arguments.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/cli/opt/options.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/config.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/configOverrides.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/connectionTypes.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/connections.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/dot_tools.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/exec_fixup_data_id.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/execution_graph_fixup.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/execution_reports.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/formatters/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/formatters/pexConfig.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/_implDetails.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/_loadHelpers.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/_versionDeserializers.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/graphSummary.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph/quantumNode.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/graph_walker.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/mermaid_tools.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipelineIR.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipelineTask.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/__main__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_dataset_types.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_edges.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_exceptions.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_mapping_views.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_nodes.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_pipeline_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_task_subsets.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/_tasks.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/expressions.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/io.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_dot.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_formatting.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_layout.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_merge.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_mermaid.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_options.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_printer.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_show.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/pipeline_graph/visualization/_status_annotator.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/prerequisite_helpers.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/py.typed +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/_config.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/_ingester.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/aggregator/_progress.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/visualization.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_provenance_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_reports.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/resource_usage.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/register_instrument.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/retrieve_artifacts_for_quanta.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/transfer_from_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/utils.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/script/zip_from_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/simple_pipeline_executor.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/struct.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/task.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/taskFactory.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/testUtils.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/in_memory_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/mocks/__init__.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/mocks/_data_id_match.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/mocks/_pipeline_task.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/mocks/_repo.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/mocks/_storage_class.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/no_dimensions.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/pipelineStepTester.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/simpleQGraph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/tests/util.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/utils.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/dependency_links.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/entry_points.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/requires.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/top_level.txt +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst_pipe_base.egg-info/zip-safe +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/setup.cfg +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_adjust_all_quanta.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_aggregator.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_caching_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_cliCmdRegisterInstrument.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_configOverrides.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_config_formatter.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_connections.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_dataid_match.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_dataset_handle.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_deferredDatasetRef.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_dot_tools.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_dynamic_connections.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_execution_reports.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_execution_storage_class_conversion.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_graphBuilder.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_graph_walker.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_init_output_run.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_instrument.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_mermaid.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_mp_graph_executor.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipeline.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipelineIR.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipelineLoadSubset.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipelineTask.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipeline_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_pipeline_graph_expressions.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_predicted_qg.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_qg_builder_dimensions.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_quantumGraph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_quantum_provenance_graph.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_quantum_reports.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_quantum_success_caveats.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_script_utils.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_simple_pipeline_executor.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_single_quantum_executor.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_struct.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_task.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_task_factory.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_taskmetadata.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_testUtils.py +0 -0
- {lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-pipe-base
|
|
3
|
-
Version: 30.0.
|
|
3
|
+
Version: 30.0.0rc2
|
|
4
4
|
Summary: Pipeline infrastructure for the Rubin Science Pipelines.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License-Expression: BSD-3-Clause OR GPL-3.0-or-later
|
|
@@ -1,69 +1,3 @@
|
|
|
1
|
-
lsst-pipe-base v30.0.0 (2026-01-16)
|
|
2
|
-
===================================
|
|
3
|
-
|
|
4
|
-
New Features
|
|
5
|
-
------------
|
|
6
|
-
|
|
7
|
-
- Added support for healpix (and other non-database dimensions) in quantum graph builder. (`DM-51176 <https://rubinobs.atlassian.net/browse/DM-51176>`_)
|
|
8
|
-
- Added filtering out dataset refs that the destination butler already knows in ``transfer_from_graph`` as well as dividing the transfer into smaller chunks to speed up restarts. (`DM-51273 <https://rubinobs.atlassian.net/browse/DM-51273>`_)
|
|
9
|
-
- Added handling of ``PrerequisiteInput`` in ``QuantaAdjuster``, with a corresponding unit test. (`DM-51509 <https://rubinobs.atlassian.net/browse/DM-51509>`_)
|
|
10
|
-
- Added ``PredictedQuantumGraph``, a replacement for the ``QuantumGraph`` class with more efficient I/O (via a new file format and more partial-read flexibility).
|
|
11
|
-
|
|
12
|
-
The new ``PredictedQuantumGraph`` is now the default in most tooling, and the new format can be opted into via the ``.qg`` (instead of ``.qgraph``) file extension.
|
|
13
|
-
New files can be read with the old class and vice versa.
|
|
14
|
-
|
|
15
|
-
The ``QuantumGraph`` class will eventually be deprecated along with much of the current provenance reporting tooling, but only when the new provenance ecosystem is fully in place. (`DM-51850 <https://rubinobs.atlassian.net/browse/DM-51850>`_)
|
|
16
|
-
- Added a ``rename`` dict in ``ImportIR`` to support renaming task labels, with corresponding unit tests. (`DM-52168 <https://rubinobs.atlassian.net/browse/DM-52168>`_)
|
|
17
|
-
- Added the new ``ProvenanceQuantumGraph`` class and the ``aggregate-graph`` tool (a replacement for ``transfer-from-graph``) that writes it at the end of batch runs. (`DM-52360 <https://rubinobs.atlassian.net/browse/DM-52360>`_)
|
|
18
|
-
- Improved provenance tracking for failed quanta and retries.
|
|
19
|
-
|
|
20
|
-
By storing extra information in the log datasets written during execution,
|
|
21
|
-
we can record caught exceptions, track which other quanta have
|
|
22
|
-
already executed in the same process, and keep track of previous attempts to
|
|
23
|
-
run the same quantum. (`DM-53019 <https://rubinobs.atlassian.net/browse/DM-53019>`_)
|
|
24
|
-
- Added provenance writing support to ``MPGraphExecutor`` and ``SeparablePipelineExecutor``. (`DM-53622 <https://rubinobs.atlassian.net/browse/DM-53622>`_)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
API Changes
|
|
28
|
-
-----------
|
|
29
|
-
|
|
30
|
-
- Moved pipeline executors and their support code here, from ``lsst.ctrl.mpexec``.
|
|
31
|
-
|
|
32
|
-
This included minor API changes for ``SingleQuantumExecutor`` as well: consistent snake-case naming, keyword-only arguments for construction, and a switch to private instance attributes. (`DM-48980 <https://rubinobs.atlassian.net/browse/DM-48980>`_)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Bug Fixes
|
|
36
|
-
---------
|
|
37
|
-
|
|
38
|
-
- Fixed ``transfer-from-graph`` to update chain when asked and output run collection exists even if didn't transfer any datasets. (`DM-51821 <https://rubinobs.atlassian.net/browse/DM-51821>`_)
|
|
39
|
-
- Fixed bug in ``transfer_from_graph`` where the input collections were not flattened before adding to a new output chain. (`DM-52004 <https://rubinobs.atlassian.net/browse/DM-52004>`_)
|
|
40
|
-
- Fixed bug where the log's ``MDC.RUN`` was the empty string when using a quantum-backed butler. (`DM-52676 <https://rubinobs.atlassian.net/browse/DM-52676>`_)
|
|
41
|
-
- Fixed a bug that caused ``PipelineGraph`` objects to be marked as unresolved when loaded from disk. (`DM-52787 <https://rubinobs.atlassian.net/browse/DM-52787>`_)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Other Changes and Additions
|
|
45
|
-
---------------------------
|
|
46
|
-
|
|
47
|
-
- The ``Instrument.configPaths`` property can now refer to ``lsst.resources.ResourcePath`` URIs as well as strings (paths or URI strings). (`DM-33226 <https://rubinobs.atlassian.net/browse/DM-33226>`_)
|
|
48
|
-
- Updated pipe_base code to use the constants defined in ``automatic_connection_constants.py``. (`DM-52676 <https://rubinobs.atlassian.net/browse/DM-52676>`_)
|
|
49
|
-
- Uses UUIDs instead of internal integer IDs in new quantum graph storage.
|
|
50
|
-
|
|
51
|
-
This includes backwards compatibility read support for predicted quantum graphs, but not provenance quantum graphs, because those are still experimental anyway.
|
|
52
|
-
|
|
53
|
-
This increases the size of the files by ~6%, but it simplifies the codebase and will make consolidating multiple small provenance quantum graphs (as we
|
|
54
|
-
currently anticipate doing for prompt processing) much more efficient. (`DM-53174 <https://rubinobs.atlassian.net/browse/DM-53174>`_)
|
|
55
|
-
- Used context managers to ensure that database resources are freed. (`DM-53370 <https://rubinobs.atlassian.net/browse/DM-53370>`_)
|
|
56
|
-
- Added more logging for the later steps of QG building. (`DM-53636 <https://rubinobs.atlassian.net/browse/DM-53636>`_)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
An API Removal or Deprecation
|
|
60
|
-
-----------------------------
|
|
61
|
-
|
|
62
|
-
- Removes the ``buildExecutionButler`` function and all supporting code.
|
|
63
|
-
|
|
64
|
-
Execution butlers (read-only SQLite databases used for batch execution) have been fully superseded by ``lsst.daf.butler.QuantumBackedButler``. (`DM-52044 <https://rubinobs.atlassian.net/browse/DM-52044>`_)
|
|
65
|
-
|
|
66
|
-
|
|
67
1
|
lsst-pipe-base v29.1.0 (2025-06-13)
|
|
68
2
|
===================================
|
|
69
3
|
|
|
@@ -31,6 +31,7 @@ __all__ = ("Instrument",)
|
|
|
31
31
|
|
|
32
32
|
import contextlib
|
|
33
33
|
import datetime
|
|
34
|
+
import os.path
|
|
34
35
|
from abc import ABCMeta, abstractmethod
|
|
35
36
|
from collections.abc import Sequence
|
|
36
37
|
from typing import TYPE_CHECKING, Any, Self, cast, final
|
|
@@ -38,7 +39,6 @@ from typing import TYPE_CHECKING, Any, Self, cast, final
|
|
|
38
39
|
from lsst.daf.butler import DataCoordinate, DataId, DimensionPacker, DimensionRecord, Formatter
|
|
39
40
|
from lsst.daf.butler.registry import DataIdError
|
|
40
41
|
from lsst.pex.config import Config, RegistryField
|
|
41
|
-
from lsst.resources import ResourcePath, ResourcePathExpression
|
|
42
42
|
from lsst.utils import doImportType
|
|
43
43
|
from lsst.utils.introspection import get_full_type_name
|
|
44
44
|
|
|
@@ -65,7 +65,7 @@ class Instrument(metaclass=ABCMeta):
|
|
|
65
65
|
the base class.
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
|
-
configPaths: Sequence[
|
|
68
|
+
configPaths: Sequence[str] = ()
|
|
69
69
|
"""Paths to config files to read for specific Tasks.
|
|
70
70
|
|
|
71
71
|
The paths in this list should contain files of the form `task.py`, for
|
|
@@ -366,10 +366,9 @@ class Instrument(metaclass=ABCMeta):
|
|
|
366
366
|
Config instance to which overrides should be applied.
|
|
367
367
|
"""
|
|
368
368
|
for root in self.configPaths:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
config.load(uri)
|
|
369
|
+
path = os.path.join(root, f"{name}.py")
|
|
370
|
+
if os.path.exists(path):
|
|
371
|
+
config.load(path)
|
|
373
372
|
|
|
374
373
|
@staticmethod
|
|
375
374
|
def formatCollectionTimestamp(timestamp: str | datetime.datetime) -> str:
|
|
@@ -31,15 +31,17 @@ __all__ = ["LogCapture"]
|
|
|
31
31
|
|
|
32
32
|
import dataclasses
|
|
33
33
|
import logging
|
|
34
|
+
import os
|
|
35
|
+
import shutil
|
|
36
|
+
import tempfile
|
|
34
37
|
import uuid
|
|
35
38
|
from collections.abc import Iterator
|
|
36
|
-
from contextlib import contextmanager
|
|
39
|
+
from contextlib import contextmanager, suppress
|
|
37
40
|
from logging import FileHandler
|
|
38
41
|
|
|
39
42
|
import pydantic
|
|
40
43
|
|
|
41
|
-
from lsst.daf.butler import Butler, LimitedButler, Quantum
|
|
42
|
-
from lsst.daf.butler._rubin.temporary_for_ingest import TemporaryForIngest
|
|
44
|
+
from lsst.daf.butler import Butler, FileDataset, LimitedButler, Quantum
|
|
43
45
|
from lsst.daf.butler.logging import (
|
|
44
46
|
ButlerLogRecord,
|
|
45
47
|
ButlerLogRecordHandler,
|
|
@@ -163,9 +165,7 @@ class LogCapture:
|
|
|
163
165
|
return cls(butler, butler)
|
|
164
166
|
|
|
165
167
|
@contextmanager
|
|
166
|
-
def capture_logging(
|
|
167
|
-
self, task_node: TaskNode, /, quantum: Quantum, records: ButlerLogRecords | None = None
|
|
168
|
-
) -> Iterator[_LogCaptureContext]:
|
|
168
|
+
def capture_logging(self, task_node: TaskNode, /, quantum: Quantum) -> Iterator[_LogCaptureContext]:
|
|
169
169
|
"""Configure logging system to capture logs for execution of this task.
|
|
170
170
|
|
|
171
171
|
Parameters
|
|
@@ -174,9 +174,6 @@ class LogCapture:
|
|
|
174
174
|
The task definition.
|
|
175
175
|
quantum : `~lsst.daf.butler.Quantum`
|
|
176
176
|
Single Quantum instance.
|
|
177
|
-
records : `lsst.daf.butler.logging.ButlerLogRecords`, optional
|
|
178
|
-
Log record container to append to and save. If provided, streaming
|
|
179
|
-
mode is disabled (since we'll be saving logs in memory anyway).
|
|
180
177
|
|
|
181
178
|
Notes
|
|
182
179
|
-----
|
|
@@ -208,40 +205,44 @@ class LogCapture:
|
|
|
208
205
|
|
|
209
206
|
# Add a handler to the root logger to capture execution log output.
|
|
210
207
|
if log_dataset_name is not None:
|
|
211
|
-
try:
|
|
212
|
-
[ref] = quantum.outputs[log_dataset_name]
|
|
213
|
-
except LookupError as exc:
|
|
214
|
-
raise InvalidQuantumError(
|
|
215
|
-
f"Quantum outputs is missing log output dataset type {log_dataset_name};"
|
|
216
|
-
" this could happen due to inconsistent options between QuantumGraph generation"
|
|
217
|
-
" and execution"
|
|
218
|
-
) from exc
|
|
219
208
|
# Either accumulate into ButlerLogRecords or stream JSON records to
|
|
220
209
|
# file and ingest that (ingest is possible only with full butler).
|
|
221
|
-
if self.stream_json_logs and self.full_butler is not None
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
210
|
+
if self.stream_json_logs and self.full_butler is not None:
|
|
211
|
+
# Create the log file in a temporary directory rather than
|
|
212
|
+
# creating a temporary file. This is necessary because
|
|
213
|
+
# temporary files are created with restrictive permissions
|
|
214
|
+
# and during file ingest these permissions persist in the
|
|
215
|
+
# datastore. Using a temp directory allows us to create
|
|
216
|
+
# a file with umask default permissions.
|
|
217
|
+
tmpdir = tempfile.mkdtemp(prefix="butler-temp-logs-")
|
|
218
|
+
|
|
219
|
+
# Construct a file to receive the log records and "touch" it.
|
|
220
|
+
log_file = os.path.join(tmpdir, f"butler-log-{task_node.label}.json")
|
|
221
|
+
with open(log_file, "w"):
|
|
222
|
+
pass
|
|
223
|
+
log_handler_file = FileHandler(log_file)
|
|
224
|
+
log_handler_file.setFormatter(JsonLogFormatter())
|
|
225
|
+
logging.getLogger().addHandler(log_handler_file)
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
with ButlerMDC.set_mdc(mdc):
|
|
229
|
+
yield ctx
|
|
230
|
+
finally:
|
|
231
|
+
# Ensure that the logs are stored in butler.
|
|
232
|
+
logging.getLogger().removeHandler(log_handler_file)
|
|
233
|
+
log_handler_file.close()
|
|
234
|
+
if ctx.extra:
|
|
235
|
+
with open(log_file, "a") as log_stream:
|
|
236
|
+
ButlerLogRecords.write_streaming_extra(
|
|
237
|
+
log_stream,
|
|
238
|
+
ctx.extra.model_dump_json(exclude_unset=True, exclude_defaults=True),
|
|
239
|
+
)
|
|
240
|
+
if ctx.store:
|
|
241
|
+
self._ingest_log_records(quantum, log_dataset_name, log_file)
|
|
242
|
+
shutil.rmtree(tmpdir, ignore_errors=True)
|
|
242
243
|
|
|
243
244
|
else:
|
|
244
|
-
log_handler_memory = ButlerLogRecordHandler(
|
|
245
|
+
log_handler_memory = ButlerLogRecordHandler()
|
|
245
246
|
logging.getLogger().addHandler(log_handler_memory)
|
|
246
247
|
|
|
247
248
|
try:
|
|
@@ -260,6 +261,7 @@ class LogCapture:
|
|
|
260
261
|
logging.getLogger().removeHandler(log_handler_memory)
|
|
261
262
|
if ctx.store:
|
|
262
263
|
self._store_log_records(quantum, log_dataset_name, log_handler_memory)
|
|
264
|
+
log_handler_memory.records.clear()
|
|
263
265
|
|
|
264
266
|
else:
|
|
265
267
|
with ButlerMDC.set_mdc(mdc):
|
|
@@ -279,3 +281,41 @@ class LogCapture:
|
|
|
279
281
|
) from exc
|
|
280
282
|
|
|
281
283
|
self.butler.put(log_handler.records, ref)
|
|
284
|
+
|
|
285
|
+
def _ingest_log_records(self, quantum: Quantum, dataset_type: str, filename: str) -> None:
|
|
286
|
+
# If we are logging to an external file we must always try to
|
|
287
|
+
# close it.
|
|
288
|
+
assert self.full_butler is not None, "Expected to have full butler for ingest"
|
|
289
|
+
ingested = False
|
|
290
|
+
try:
|
|
291
|
+
# DatasetRef has to be in the Quantum outputs, can lookup by name.
|
|
292
|
+
try:
|
|
293
|
+
[ref] = quantum.outputs[dataset_type]
|
|
294
|
+
except LookupError as exc:
|
|
295
|
+
raise InvalidQuantumError(
|
|
296
|
+
f"Quantum outputs is missing log output dataset type {dataset_type};"
|
|
297
|
+
" this could happen due to inconsistent options between QuantumGraph generation"
|
|
298
|
+
" and execution"
|
|
299
|
+
) from exc
|
|
300
|
+
|
|
301
|
+
# Need to ingest this file directly into butler.
|
|
302
|
+
dataset = FileDataset(path=filename, refs=ref)
|
|
303
|
+
try:
|
|
304
|
+
self.full_butler.ingest(dataset, transfer="move")
|
|
305
|
+
ingested = True
|
|
306
|
+
except NotImplementedError:
|
|
307
|
+
# Some datastores can't receive files (e.g. in-memory datastore
|
|
308
|
+
# when testing), we store empty list for those just to have a
|
|
309
|
+
# dataset. Alternative is to read the file as a
|
|
310
|
+
# ButlerLogRecords object and put it.
|
|
311
|
+
_LOG.info(
|
|
312
|
+
"Log records could not be stored in this butler because the"
|
|
313
|
+
" datastore can not ingest files, empty record list is stored instead."
|
|
314
|
+
)
|
|
315
|
+
records = ButlerLogRecords.from_records([])
|
|
316
|
+
self.full_butler.put(records, ref)
|
|
317
|
+
finally:
|
|
318
|
+
# remove file if it is not ingested
|
|
319
|
+
if not ingested:
|
|
320
|
+
with suppress(OSError):
|
|
321
|
+
os.remove(filename)
|
{lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/mp_graph_executor.py
RENAMED
|
@@ -39,24 +39,20 @@ import sys
|
|
|
39
39
|
import threading
|
|
40
40
|
import time
|
|
41
41
|
import uuid
|
|
42
|
-
from contextlib import ExitStack
|
|
43
42
|
from typing import Literal, cast
|
|
44
43
|
|
|
45
44
|
import networkx
|
|
46
45
|
|
|
47
46
|
from lsst.daf.butler import DataCoordinate, Quantum
|
|
48
47
|
from lsst.daf.butler.cli.cliLog import CliLog
|
|
49
|
-
from lsst.daf.butler.logging import ButlerLogRecords
|
|
50
48
|
from lsst.utils.threads import disable_implicit_threading
|
|
51
49
|
|
|
52
50
|
from ._status import InvalidQuantumError, RepeatableQuantumError
|
|
53
|
-
from ._task_metadata import TaskMetadata
|
|
54
51
|
from .execution_graph_fixup import ExecutionGraphFixup
|
|
55
52
|
from .graph import QuantumGraph
|
|
56
53
|
from .graph_walker import GraphWalker
|
|
57
|
-
from .log_on_close import LogOnClose
|
|
58
54
|
from .pipeline_graph import TaskNode
|
|
59
|
-
from .quantum_graph import PredictedQuantumGraph, PredictedQuantumInfo
|
|
55
|
+
from .quantum_graph import PredictedQuantumGraph, PredictedQuantumInfo
|
|
60
56
|
from .quantum_graph_executor import QuantumExecutor, QuantumGraphExecutor
|
|
61
57
|
from .quantum_reports import ExecutionStatus, QuantumReport, Report
|
|
62
58
|
|
|
@@ -519,9 +515,7 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
519
515
|
start_method = "spawn"
|
|
520
516
|
self._start_method = start_method
|
|
521
517
|
|
|
522
|
-
def execute(
|
|
523
|
-
self, graph: QuantumGraph | PredictedQuantumGraph, *, provenance_graph_file: str | None = None
|
|
524
|
-
) -> None:
|
|
518
|
+
def execute(self, graph: QuantumGraph | PredictedQuantumGraph) -> None:
|
|
525
519
|
# Docstring inherited from QuantumGraphExecutor.execute
|
|
526
520
|
old_graph: QuantumGraph | None = None
|
|
527
521
|
if isinstance(graph, QuantumGraph):
|
|
@@ -531,31 +525,14 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
531
525
|
new_graph = graph
|
|
532
526
|
xgraph = self._make_xgraph(new_graph, old_graph)
|
|
533
527
|
self._report = Report(qgraphSummary=new_graph._make_summary())
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
provenance_graph_file,
|
|
543
|
-
exit_stack=exit_stack,
|
|
544
|
-
log_on_close=LogOnClose(_LOG.log),
|
|
545
|
-
predicted=new_graph,
|
|
546
|
-
)
|
|
547
|
-
try:
|
|
548
|
-
if self._num_proc > 1:
|
|
549
|
-
self._execute_quanta_mp(xgraph, self._report)
|
|
550
|
-
else:
|
|
551
|
-
self._execute_quanta_in_process(xgraph, self._report, provenance_writer)
|
|
552
|
-
except Exception as exc:
|
|
553
|
-
self._report.set_exception(exc)
|
|
554
|
-
raise
|
|
555
|
-
if provenance_writer is not None:
|
|
556
|
-
provenance_writer.write_overall_inputs()
|
|
557
|
-
provenance_writer.write_packages()
|
|
558
|
-
provenance_writer.write_init_outputs(assume_existence=True)
|
|
528
|
+
try:
|
|
529
|
+
if self._num_proc > 1:
|
|
530
|
+
self._execute_quanta_mp(xgraph, self._report)
|
|
531
|
+
else:
|
|
532
|
+
self._execute_quanta_in_process(xgraph, self._report)
|
|
533
|
+
except Exception as exc:
|
|
534
|
+
self._report.set_exception(exc)
|
|
535
|
+
raise
|
|
559
536
|
|
|
560
537
|
def _make_xgraph(
|
|
561
538
|
self, new_graph: PredictedQuantumGraph, old_graph: QuantumGraph | None
|
|
@@ -599,9 +576,7 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
599
576
|
raise MPGraphExecutorError("Updated execution graph has dependency cycle.")
|
|
600
577
|
return xgraph
|
|
601
578
|
|
|
602
|
-
def _execute_quanta_in_process(
|
|
603
|
-
self, xgraph: networkx.DiGraph, report: Report, provenance_writer: ProvenanceQuantumGraphWriter | None
|
|
604
|
-
) -> None:
|
|
579
|
+
def _execute_quanta_in_process(self, xgraph: networkx.DiGraph, report: Report) -> None:
|
|
605
580
|
"""Execute all Quanta in current process.
|
|
606
581
|
|
|
607
582
|
Parameters
|
|
@@ -614,9 +589,6 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
614
589
|
`.quantum_graph.PredictedQuantumGraph.quantum_only_xgraph`.
|
|
615
590
|
report : `Report`
|
|
616
591
|
Object for reporting execution status.
|
|
617
|
-
provenance_writer : `.quantum_graph.ProvenanceQuantumGraphWriter` or \
|
|
618
|
-
`None`
|
|
619
|
-
Object for recording provenance.
|
|
620
592
|
"""
|
|
621
593
|
|
|
622
594
|
def tiebreaker_sort_key(quantum_id: uuid.UUID) -> tuple:
|
|
@@ -634,19 +606,16 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
634
606
|
|
|
635
607
|
_LOG.debug("Executing %s (%s@%s)", quantum_id, task_node.label, data_id)
|
|
636
608
|
fail_exit_code: int | None = None
|
|
637
|
-
task_metadata: TaskMetadata | None = None
|
|
638
|
-
task_logs = ButlerLogRecords([])
|
|
639
609
|
try:
|
|
640
610
|
# For some exception types we want to exit immediately with
|
|
641
611
|
# exception-specific exit code, but we still want to start
|
|
642
612
|
# debugger before exiting if debugging is enabled.
|
|
643
613
|
try:
|
|
644
|
-
|
|
645
|
-
task_node, quantum, quantum_id=quantum_id
|
|
614
|
+
_, quantum_report = self._quantum_executor.execute(
|
|
615
|
+
task_node, quantum, quantum_id=quantum_id
|
|
646
616
|
)
|
|
647
|
-
if
|
|
648
|
-
report.quantaReports.append(
|
|
649
|
-
task_metadata = execution_result.task_metadata
|
|
617
|
+
if quantum_report:
|
|
618
|
+
report.quantaReports.append(quantum_report)
|
|
650
619
|
success_count += 1
|
|
651
620
|
walker.finish(quantum_id)
|
|
652
621
|
except RepeatableQuantumError as exc:
|
|
@@ -732,11 +701,6 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
732
701
|
)
|
|
733
702
|
failed_count += 1
|
|
734
703
|
|
|
735
|
-
if provenance_writer is not None:
|
|
736
|
-
provenance_writer.write_quantum_provenance(
|
|
737
|
-
quantum_id, metadata=task_metadata, logs=task_logs
|
|
738
|
-
)
|
|
739
|
-
|
|
740
704
|
_LOG.info(
|
|
741
705
|
"Executed %d quanta successfully, %d failed and %d remain out of total %d quanta.",
|
|
742
706
|
success_count,
|
{lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_common.py
RENAMED
|
@@ -448,15 +448,14 @@ class BaseQuantumGraphWriter:
|
|
|
448
448
|
uri: ResourcePathExpression,
|
|
449
449
|
header: HeaderModel,
|
|
450
450
|
pipeline_graph: PipelineGraph,
|
|
451
|
+
indices: dict[uuid.UUID, int],
|
|
451
452
|
*,
|
|
452
453
|
address_filename: str,
|
|
454
|
+
compressor: Compressor,
|
|
453
455
|
cdict_data: bytes | None = None,
|
|
454
|
-
zstd_level: int = 10,
|
|
455
456
|
) -> Iterator[Self]:
|
|
456
457
|
uri = ResourcePath(uri)
|
|
457
|
-
address_writer = AddressWriter()
|
|
458
|
-
cdict = zstandard.ZstdCompressionDict(cdict_data) if cdict_data is not None else None
|
|
459
|
-
compressor = zstandard.ZstdCompressor(level=zstd_level, dict_data=cdict)
|
|
458
|
+
address_writer = AddressWriter(indices)
|
|
460
459
|
with uri.open(mode="wb") as stream:
|
|
461
460
|
with zipfile.ZipFile(stream, mode="w", compression=zipfile.ZIP_STORED) as zf:
|
|
462
461
|
self = cls(zf, compressor, address_writer, header.int_size)
|
|
@@ -205,6 +205,13 @@ class AddressRow:
|
|
|
205
205
|
class AddressWriter:
|
|
206
206
|
"""A helper object for writing address files for multi-block files."""
|
|
207
207
|
|
|
208
|
+
indices: dict[uuid.UUID, int] = dataclasses.field(default_factory=dict)
|
|
209
|
+
"""Mapping from UUID to internal integer ID.
|
|
210
|
+
|
|
211
|
+
The internal integer ID must always correspond to the index into the
|
|
212
|
+
sorted list of all UUIDs, but this `dict` need not be sorted itself.
|
|
213
|
+
"""
|
|
214
|
+
|
|
208
215
|
addresses: list[dict[uuid.UUID, Address]] = dataclasses.field(default_factory=list)
|
|
209
216
|
"""Addresses to store with each UUID.
|
|
210
217
|
|
|
@@ -222,15 +229,18 @@ class AddressWriter:
|
|
|
222
229
|
int_size : `int`
|
|
223
230
|
Number of bytes to use for all integers.
|
|
224
231
|
"""
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
for n, address_map in enumerate(self.addresses):
|
|
233
|
+
if not self.indices.keys() >= address_map.keys():
|
|
234
|
+
raise AssertionError(
|
|
235
|
+
f"Logic bug in quantum graph I/O: address map {n} of {len(self.addresses)} has IDs "
|
|
236
|
+
f"{address_map.keys() - self.indices.keys()} not in the index map."
|
|
237
|
+
)
|
|
228
238
|
stream.write(int_size.to_bytes(1))
|
|
229
|
-
stream.write(len(indices).to_bytes(int_size))
|
|
239
|
+
stream.write(len(self.indices).to_bytes(int_size))
|
|
230
240
|
stream.write(len(self.addresses).to_bytes(int_size))
|
|
231
241
|
empty_address = Address()
|
|
232
|
-
for
|
|
233
|
-
row = AddressRow(key,
|
|
242
|
+
for key in sorted(self.indices.keys(), key=attrgetter("int")):
|
|
243
|
+
row = AddressRow(key, self.indices[key], [m.get(key, empty_address) for m in self.addresses])
|
|
234
244
|
_LOG.debug("Wrote address %s.", row)
|
|
235
245
|
row.write(stream, int_size)
|
|
236
246
|
|
{lsst_pipe_base-30.0.0 → lsst_pipe_base-30.0.0rc2}/python/lsst/pipe/base/quantum_graph/_predicted.py
RENAMED
|
@@ -66,7 +66,6 @@ from lsst.daf.butler import (
|
|
|
66
66
|
DimensionDataExtractor,
|
|
67
67
|
DimensionGroup,
|
|
68
68
|
DimensionRecordSetDeserializer,
|
|
69
|
-
DimensionUniverse,
|
|
70
69
|
LimitedButler,
|
|
71
70
|
Quantum,
|
|
72
71
|
QuantumBackedButler,
|
|
@@ -199,10 +198,10 @@ class _PredictedThinGraphModelV0(pydantic.BaseModel):
|
|
|
199
198
|
def _upgraded(self, address_rows: Mapping[uuid.UUID, AddressRow]) -> PredictedThinGraphModel:
|
|
200
199
|
"""Convert to the v1+ model."""
|
|
201
200
|
uuid_by_index = {v.index: k for k, v in address_rows.items()}
|
|
202
|
-
return PredictedThinGraphModel
|
|
201
|
+
return PredictedThinGraphModel(
|
|
203
202
|
quanta={
|
|
204
203
|
task_label: [
|
|
205
|
-
PredictedThinQuantumModel
|
|
204
|
+
PredictedThinQuantumModel(
|
|
206
205
|
quantum_id=uuid_by_index[q.quantum_index], data_coordinate=q.data_coordinate
|
|
207
206
|
)
|
|
208
207
|
for q in quanta
|
|
@@ -878,49 +877,6 @@ class PredictedQuantumGraph(BaseQuantumGraph):
|
|
|
878
877
|
page_size=page_size,
|
|
879
878
|
).assemble()
|
|
880
879
|
|
|
881
|
-
@classmethod
|
|
882
|
-
def make_empty(
|
|
883
|
-
cls,
|
|
884
|
-
universe: DimensionUniverse,
|
|
885
|
-
*,
|
|
886
|
-
output_run: str,
|
|
887
|
-
inputs: Iterable[str] = (),
|
|
888
|
-
output: str | None = None,
|
|
889
|
-
add_packages: bool = True,
|
|
890
|
-
) -> PredictedQuantumGraph:
|
|
891
|
-
"""Make an empty quantum graph with no tasks.
|
|
892
|
-
|
|
893
|
-
Parameters
|
|
894
|
-
----------
|
|
895
|
-
universe : `lsst.daf.butler.DimensionUniverse`
|
|
896
|
-
Definitions for all butler dimensions.
|
|
897
|
-
output_run : `str`
|
|
898
|
-
Output run collection.
|
|
899
|
-
inputs : `~collections.abc.Iterable` [`str`], optional
|
|
900
|
-
Iterable of input collection names.
|
|
901
|
-
output : `str` or `None`, optional
|
|
902
|
-
Output chained collection.
|
|
903
|
-
add_packages : `bool`, optional
|
|
904
|
-
Whether to add the special init quantum that writes the 'packages'
|
|
905
|
-
dataset. The default (`True`) is consistent with
|
|
906
|
-
`~..quantum_graph_builder.QuantumGraphBuilder` behavior when there
|
|
907
|
-
are no regular quanta generated.
|
|
908
|
-
|
|
909
|
-
Returns
|
|
910
|
-
-------
|
|
911
|
-
quantum_graph : `PredictedQuantumGraph`
|
|
912
|
-
An empty quantum graph.
|
|
913
|
-
"""
|
|
914
|
-
return cls(
|
|
915
|
-
PredictedQuantumGraphComponents.make_empty(
|
|
916
|
-
universe,
|
|
917
|
-
output_run=output_run,
|
|
918
|
-
inputs=inputs,
|
|
919
|
-
output=output,
|
|
920
|
-
add_packages=add_packages,
|
|
921
|
-
)
|
|
922
|
-
)
|
|
923
|
-
|
|
924
880
|
@property
|
|
925
881
|
def quanta_by_task(self) -> Mapping[str, Mapping[DataCoordinate, uuid.UUID]]:
|
|
926
882
|
"""A nested mapping of all quanta, keyed first by task name and then by
|
|
@@ -1585,63 +1541,6 @@ class PredictedQuantumGraphComponents:
|
|
|
1585
1541
|
This does not include special "init" quanta.
|
|
1586
1542
|
"""
|
|
1587
1543
|
|
|
1588
|
-
@classmethod
|
|
1589
|
-
def make_empty(
|
|
1590
|
-
cls,
|
|
1591
|
-
universe: DimensionUniverse,
|
|
1592
|
-
*,
|
|
1593
|
-
output_run: str,
|
|
1594
|
-
inputs: Iterable[str] = (),
|
|
1595
|
-
output: str | None = None,
|
|
1596
|
-
add_packages: bool = True,
|
|
1597
|
-
) -> PredictedQuantumGraphComponents:
|
|
1598
|
-
"""Make components for an empty quantum graph with no tasks.
|
|
1599
|
-
|
|
1600
|
-
Parameters
|
|
1601
|
-
----------
|
|
1602
|
-
universe : `lsst.daf.butler.DimensionUniverse`
|
|
1603
|
-
Definitions for all butler dimensions.
|
|
1604
|
-
output_run : `str`
|
|
1605
|
-
Output run collection.
|
|
1606
|
-
inputs : `~collections.abc.Iterable` [`str`], optional
|
|
1607
|
-
Iterable of input collection names.
|
|
1608
|
-
output : `str` or `None`, optional
|
|
1609
|
-
Output chained collection.
|
|
1610
|
-
add_packages : `bool`, optional
|
|
1611
|
-
Whether to add the special init quantum that writes the 'packages'
|
|
1612
|
-
dataset. The default (`True`) is consistent with
|
|
1613
|
-
`~..quantum_graph_builder.QuantumGraphBuilder` behavior when there
|
|
1614
|
-
are no regular quanta generated.
|
|
1615
|
-
|
|
1616
|
-
Returns
|
|
1617
|
-
-------
|
|
1618
|
-
components : `PredictedQuantumGraphComponents`
|
|
1619
|
-
Components that can be used to build or write an empty quantum
|
|
1620
|
-
graph.
|
|
1621
|
-
"""
|
|
1622
|
-
components = cls(pipeline_graph=PipelineGraph(universe=universe))
|
|
1623
|
-
components.header.inputs = list(inputs)
|
|
1624
|
-
components.header.output_run = output_run
|
|
1625
|
-
components.header.output = output
|
|
1626
|
-
if add_packages:
|
|
1627
|
-
components.init_quanta.root = [
|
|
1628
|
-
PredictedQuantumDatasetsModel.model_construct(
|
|
1629
|
-
quantum_id=generate_uuidv7(),
|
|
1630
|
-
task_label="",
|
|
1631
|
-
outputs={
|
|
1632
|
-
acc.PACKAGES_INIT_OUTPUT_NAME: [
|
|
1633
|
-
PredictedDatasetModel(
|
|
1634
|
-
dataset_id=generate_uuidv7(),
|
|
1635
|
-
dataset_type_name=acc.PACKAGES_INIT_OUTPUT_NAME,
|
|
1636
|
-
data_coordinate=[],
|
|
1637
|
-
run=output_run,
|
|
1638
|
-
)
|
|
1639
|
-
]
|
|
1640
|
-
},
|
|
1641
|
-
)
|
|
1642
|
-
]
|
|
1643
|
-
return components
|
|
1644
|
-
|
|
1645
1544
|
def make_dataset_ref(self, predicted: PredictedDatasetModel) -> DatasetRef:
|
|
1646
1545
|
"""Make a `lsst.daf.butler.DatasetRef` from information in the
|
|
1647
1546
|
predicted quantum graph.
|
|
@@ -1894,6 +1793,7 @@ class PredictedQuantumGraphComponents:
|
|
|
1894
1793
|
f"Unsupported extension {ext!r} for quantum graph; "
|
|
1895
1794
|
"expected '.qg' (or '.qgraph' to force the old format)."
|
|
1896
1795
|
)
|
|
1796
|
+
cdict: zstandard.ZstdCompressionDict | None = None
|
|
1897
1797
|
cdict_data: bytes | None = None
|
|
1898
1798
|
quantum_datasets_json: dict[uuid.UUID, bytes] = {}
|
|
1899
1799
|
if len(self.quantum_datasets) < zstd_dict_n_inputs:
|
|
@@ -1907,20 +1807,26 @@ class PredictedQuantumGraphComponents:
|
|
|
1907
1807
|
for quantum_model in itertools.islice(self.quantum_datasets.values(), zstd_dict_n_inputs)
|
|
1908
1808
|
}
|
|
1909
1809
|
try:
|
|
1910
|
-
|
|
1810
|
+
cdict = zstandard.train_dictionary(
|
|
1911
1811
|
zstd_dict_size,
|
|
1912
1812
|
list(quantum_datasets_json.values()),
|
|
1913
1813
|
level=zstd_level,
|
|
1914
|
-
)
|
|
1814
|
+
)
|
|
1915
1815
|
except zstandard.ZstdError as err:
|
|
1916
1816
|
warnings.warn(f"Not using a compression dictionary: {err}.")
|
|
1817
|
+
cdict = None
|
|
1818
|
+
else:
|
|
1819
|
+
cdict_data = cdict.as_bytes()
|
|
1820
|
+
compressor = zstandard.ZstdCompressor(level=zstd_level, dict_data=cdict)
|
|
1821
|
+
indices = {quantum_id: n for n, quantum_id in enumerate(sorted(self.quantum_datasets.keys()))}
|
|
1917
1822
|
with BaseQuantumGraphWriter.open(
|
|
1918
1823
|
uri,
|
|
1919
1824
|
header=self.header,
|
|
1920
1825
|
pipeline_graph=self.pipeline_graph,
|
|
1826
|
+
indices=indices,
|
|
1921
1827
|
address_filename="quanta",
|
|
1828
|
+
compressor=compressor,
|
|
1922
1829
|
cdict_data=cdict_data,
|
|
1923
|
-
zstd_level=zstd_level,
|
|
1924
1830
|
) as writer:
|
|
1925
1831
|
writer.write_single_model("thin_graph", self.thin_graph)
|
|
1926
1832
|
if self.dimension_data is None:
|