lsst-pipe-base 30.0.0rc1__tar.gz → 30.0.0rc3__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.0rc1/python/lsst_pipe_base.egg-info → lsst_pipe_base-30.0.0rc3}/PKG-INFO +1 -1
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/CHANGES.rst +66 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_instrument.py +6 -5
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/log_capture.py +39 -79
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/log_on_close.py +79 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/mp_graph_executor.py +51 -15
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/_common.py +4 -3
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/_multiblock.py +6 -16
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/_predicted.py +106 -12
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/_provenance.py +657 -6
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/_communicators.py +18 -50
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/quantum_graph/aggregator/_scanner.py +317 -0
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/quantum_graph/aggregator/_structs.py +67 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/_supervisor.py +10 -5
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/quantum_graph/aggregator/_writer.py +184 -0
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/quantum_graph/formatter.py +101 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph_builder.py +12 -1
- lsst_pipe_base-30.0.0rc3/python/lsst/pipe/base/quantum_graph_executor.py +229 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph_skeleton.py +1 -7
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/separable_pipeline_executor.py +18 -2
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/single_quantum_executor.py +53 -35
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/version.py +1 -1
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3/python/lsst_pipe_base.egg-info}/PKG-INFO +1 -1
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/SOURCES.txt +2 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_separable_pipeline_executor.py +101 -13
- lsst_pipe_base-30.0.0rc1/python/lsst/pipe/base/quantum_graph/aggregator/_scanner.py +0 -511
- lsst_pipe_base-30.0.0rc1/python/lsst/pipe/base/quantum_graph/aggregator/_structs.py +0 -177
- lsst_pipe_base-30.0.0rc1/python/lsst/pipe/base/quantum_graph/aggregator/_writer.py +0 -501
- lsst_pipe_base-30.0.0rc1/python/lsst/pipe/base/quantum_graph_executor.py +0 -126
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/COPYRIGHT +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/LICENSE +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/MANIFEST.in +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/README.md +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/bsd_license.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/creating-a-pipeline.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/creating-a-pipelinetask.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/creating-a-task.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/index.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/task-framework-overview.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/task-retargeting-howto.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/testing-a-pipeline-task.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/testing-pipelines-with-mocks.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/doc/lsst.pipe.base/working-with-pipeline-graphs.rst +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/gpl-v3.0.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/pyproject.toml +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_datasetQueryConstraints.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_dataset_handle.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_observation_dimension_packer.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_quantumContext.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_status.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/_task_metadata.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/all_dimensions_quantum_graph_builder.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/automatic_connection_constants.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/caching_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/_get_cli_subcommands.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/cmd/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/cmd/commands.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/opt/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/opt/arguments.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/cli/opt/options.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/config.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/configOverrides.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/connectionTypes.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/connections.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/dot_tools.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/exec_fixup_data_id.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/execution_graph_fixup.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/execution_reports.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/formatters/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/formatters/pexConfig.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/_implDetails.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/_loadHelpers.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/_versionDeserializers.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/graphSummary.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph/quantumNode.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/graph_walker.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/mermaid_tools.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipelineIR.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipelineTask.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/__main__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_dataset_types.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_edges.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_exceptions.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_mapping_views.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_nodes.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_pipeline_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_task_subsets.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/_tasks.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/expressions.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/io.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_dot.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_formatting.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_layout.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_merge.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_mermaid.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_options.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_printer.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_show.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/pipeline_graph/visualization/_status_annotator.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/prerequisite_helpers.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/py.typed +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/_config.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/_ingester.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/aggregator/_progress.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/visualization.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_provenance_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_reports.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/resource_usage.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/register_instrument.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/retrieve_artifacts_for_quanta.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/transfer_from_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/utils.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/script/zip_from_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/simple_pipeline_executor.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/struct.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/task.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/taskFactory.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/testUtils.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/in_memory_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/mocks/__init__.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/mocks/_data_id_match.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/mocks/_pipeline_task.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/mocks/_repo.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/mocks/_storage_class.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/no_dimensions.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/pipelineStepTester.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/simpleQGraph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/tests/util.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/utils.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/dependency_links.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/entry_points.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/requires.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/top_level.txt +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst_pipe_base.egg-info/zip-safe +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/setup.cfg +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_adjust_all_quanta.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_aggregator.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_caching_limited_butler.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_cliCmdRegisterInstrument.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_configOverrides.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_config_formatter.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_connections.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_dataid_match.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_dataset_handle.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_deferredDatasetRef.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_dot_tools.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_dynamic_connections.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_execution_reports.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_execution_storage_class_conversion.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_graphBuilder.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_graph_walker.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_init_output_run.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_instrument.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_mermaid.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_mp_graph_executor.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipeline.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipelineIR.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipelineLoadSubset.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipelineTask.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipeline_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_pipeline_graph_expressions.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_predicted_qg.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_qg_builder_dimensions.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_quantumGraph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_quantum_provenance_graph.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_quantum_reports.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_quantum_success_caveats.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_script_utils.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_simple_pipeline_executor.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_single_quantum_executor.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_struct.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_task.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_task_factory.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_taskmetadata.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_testUtils.py +0 -0
- {lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/tests/test_utils.py +0 -0
{lsst_pipe_base-30.0.0rc1/python/lsst_pipe_base.egg-info → lsst_pipe_base-30.0.0rc3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-pipe-base
|
|
3
|
-
Version: 30.0.
|
|
3
|
+
Version: 30.0.0rc3
|
|
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,3 +1,69 @@
|
|
|
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
|
+
|
|
1
67
|
lsst-pipe-base v29.1.0 (2025-06-13)
|
|
2
68
|
===================================
|
|
3
69
|
|
|
@@ -31,7 +31,6 @@ __all__ = ("Instrument",)
|
|
|
31
31
|
|
|
32
32
|
import contextlib
|
|
33
33
|
import datetime
|
|
34
|
-
import os.path
|
|
35
34
|
from abc import ABCMeta, abstractmethod
|
|
36
35
|
from collections.abc import Sequence
|
|
37
36
|
from typing import TYPE_CHECKING, Any, Self, cast, final
|
|
@@ -39,6 +38,7 @@ from typing import TYPE_CHECKING, Any, Self, cast, final
|
|
|
39
38
|
from lsst.daf.butler import DataCoordinate, DataId, DimensionPacker, DimensionRecord, Formatter
|
|
40
39
|
from lsst.daf.butler.registry import DataIdError
|
|
41
40
|
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[ResourcePathExpression] = ()
|
|
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,9 +366,10 @@ 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
|
-
|
|
369
|
+
resource = ResourcePath(root, forceDirectory=True, forceAbsolute=True)
|
|
370
|
+
uri = resource.join(f"{name}.py", forceDirectory=False)
|
|
371
|
+
if uri.exists():
|
|
372
|
+
config.load(uri)
|
|
372
373
|
|
|
373
374
|
@staticmethod
|
|
374
375
|
def formatCollectionTimestamp(timestamp: str | datetime.datetime) -> str:
|
|
@@ -31,17 +31,15 @@ __all__ = ["LogCapture"]
|
|
|
31
31
|
|
|
32
32
|
import dataclasses
|
|
33
33
|
import logging
|
|
34
|
-
import os
|
|
35
|
-
import shutil
|
|
36
|
-
import tempfile
|
|
37
34
|
import uuid
|
|
38
35
|
from collections.abc import Iterator
|
|
39
|
-
from contextlib import contextmanager
|
|
36
|
+
from contextlib import contextmanager
|
|
40
37
|
from logging import FileHandler
|
|
41
38
|
|
|
42
39
|
import pydantic
|
|
43
40
|
|
|
44
|
-
from lsst.daf.butler import Butler,
|
|
41
|
+
from lsst.daf.butler import Butler, LimitedButler, Quantum
|
|
42
|
+
from lsst.daf.butler._rubin.temporary_for_ingest import TemporaryForIngest
|
|
45
43
|
from lsst.daf.butler.logging import (
|
|
46
44
|
ButlerLogRecord,
|
|
47
45
|
ButlerLogRecordHandler,
|
|
@@ -165,7 +163,9 @@ class LogCapture:
|
|
|
165
163
|
return cls(butler, butler)
|
|
166
164
|
|
|
167
165
|
@contextmanager
|
|
168
|
-
def capture_logging(
|
|
166
|
+
def capture_logging(
|
|
167
|
+
self, task_node: TaskNode, /, quantum: Quantum, records: ButlerLogRecords | None = None
|
|
168
|
+
) -> Iterator[_LogCaptureContext]:
|
|
169
169
|
"""Configure logging system to capture logs for execution of this task.
|
|
170
170
|
|
|
171
171
|
Parameters
|
|
@@ -174,6 +174,9 @@ 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).
|
|
177
180
|
|
|
178
181
|
Notes
|
|
179
182
|
-----
|
|
@@ -205,44 +208,40 @@ class LogCapture:
|
|
|
205
208
|
|
|
206
209
|
# Add a handler to the root logger to capture execution log output.
|
|
207
210
|
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
|
|
208
219
|
# Either accumulate into ButlerLogRecords or stream JSON records to
|
|
209
220
|
# file and ingest that (ingest is possible only with full butler).
|
|
210
|
-
if self.stream_json_logs and self.full_butler is not None:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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)
|
|
221
|
+
if self.stream_json_logs and self.full_butler is not None and records is None:
|
|
222
|
+
with TemporaryForIngest(self.full_butler, ref) as temporary:
|
|
223
|
+
log_handler_file = FileHandler(temporary.ospath)
|
|
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(temporary.ospath, "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
|
+
temporary.ingest()
|
|
243
242
|
|
|
244
243
|
else:
|
|
245
|
-
log_handler_memory = ButlerLogRecordHandler()
|
|
244
|
+
log_handler_memory = ButlerLogRecordHandler(records)
|
|
246
245
|
logging.getLogger().addHandler(log_handler_memory)
|
|
247
246
|
|
|
248
247
|
try:
|
|
@@ -261,7 +260,6 @@ class LogCapture:
|
|
|
261
260
|
logging.getLogger().removeHandler(log_handler_memory)
|
|
262
261
|
if ctx.store:
|
|
263
262
|
self._store_log_records(quantum, log_dataset_name, log_handler_memory)
|
|
264
|
-
log_handler_memory.records.clear()
|
|
265
263
|
|
|
266
264
|
else:
|
|
267
265
|
with ButlerMDC.set_mdc(mdc):
|
|
@@ -281,41 +279,3 @@ class LogCapture:
|
|
|
281
279
|
) from exc
|
|
282
280
|
|
|
283
281
|
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)
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
# (http://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 <http://www.gnu.org/licenses/>.
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
__all__ = ("LogOnClose",)
|
|
31
|
+
|
|
32
|
+
from collections.abc import Callable, Iterator
|
|
33
|
+
from contextlib import AbstractContextManager, contextmanager
|
|
34
|
+
from typing import TypeVar
|
|
35
|
+
|
|
36
|
+
from lsst.utils.logging import VERBOSE
|
|
37
|
+
|
|
38
|
+
_T = TypeVar("_T")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class LogOnClose:
|
|
42
|
+
"""A factory for context manager wrappers that emit a log message when
|
|
43
|
+
they are closed.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
log_func : `~collections.abc.Callable` [ `int`, `str` ]
|
|
48
|
+
Callable that takes an integer log level and a string message and emits
|
|
49
|
+
a log message. Note that placeholder formatting is not supported.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, log_func: Callable[[int, str], None]):
|
|
53
|
+
self.log_func = log_func
|
|
54
|
+
|
|
55
|
+
def wrap(
|
|
56
|
+
self,
|
|
57
|
+
cm: AbstractContextManager[_T],
|
|
58
|
+
msg: str,
|
|
59
|
+
level: int = VERBOSE,
|
|
60
|
+
) -> AbstractContextManager[_T]:
|
|
61
|
+
"""Wrap a context manager to log when it is exited.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
cm : `contextlib.AbstractContextManager`
|
|
66
|
+
Context manager to wrap.
|
|
67
|
+
msg : `str`
|
|
68
|
+
Log message.
|
|
69
|
+
level : `int`, optional
|
|
70
|
+
Log level.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
@contextmanager
|
|
74
|
+
def wrapper() -> Iterator[_T]:
|
|
75
|
+
with cm as result:
|
|
76
|
+
yield result
|
|
77
|
+
self.log_func(level, msg)
|
|
78
|
+
|
|
79
|
+
return wrapper()
|
{lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/mp_graph_executor.py
RENAMED
|
@@ -39,20 +39,24 @@ import sys
|
|
|
39
39
|
import threading
|
|
40
40
|
import time
|
|
41
41
|
import uuid
|
|
42
|
+
from contextlib import ExitStack
|
|
42
43
|
from typing import Literal, cast
|
|
43
44
|
|
|
44
45
|
import networkx
|
|
45
46
|
|
|
46
47
|
from lsst.daf.butler import DataCoordinate, Quantum
|
|
47
48
|
from lsst.daf.butler.cli.cliLog import CliLog
|
|
49
|
+
from lsst.daf.butler.logging import ButlerLogRecords
|
|
48
50
|
from lsst.utils.threads import disable_implicit_threading
|
|
49
51
|
|
|
50
52
|
from ._status import InvalidQuantumError, RepeatableQuantumError
|
|
53
|
+
from ._task_metadata import TaskMetadata
|
|
51
54
|
from .execution_graph_fixup import ExecutionGraphFixup
|
|
52
55
|
from .graph import QuantumGraph
|
|
53
56
|
from .graph_walker import GraphWalker
|
|
57
|
+
from .log_on_close import LogOnClose
|
|
54
58
|
from .pipeline_graph import TaskNode
|
|
55
|
-
from .quantum_graph import PredictedQuantumGraph, PredictedQuantumInfo
|
|
59
|
+
from .quantum_graph import PredictedQuantumGraph, PredictedQuantumInfo, ProvenanceQuantumGraphWriter
|
|
56
60
|
from .quantum_graph_executor import QuantumExecutor, QuantumGraphExecutor
|
|
57
61
|
from .quantum_reports import ExecutionStatus, QuantumReport, Report
|
|
58
62
|
|
|
@@ -515,7 +519,9 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
515
519
|
start_method = "spawn"
|
|
516
520
|
self._start_method = start_method
|
|
517
521
|
|
|
518
|
-
def execute(
|
|
522
|
+
def execute(
|
|
523
|
+
self, graph: QuantumGraph | PredictedQuantumGraph, *, provenance_graph_file: str | None = None
|
|
524
|
+
) -> None:
|
|
519
525
|
# Docstring inherited from QuantumGraphExecutor.execute
|
|
520
526
|
old_graph: QuantumGraph | None = None
|
|
521
527
|
if isinstance(graph, QuantumGraph):
|
|
@@ -525,14 +531,31 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
525
531
|
new_graph = graph
|
|
526
532
|
xgraph = self._make_xgraph(new_graph, old_graph)
|
|
527
533
|
self._report = Report(qgraphSummary=new_graph._make_summary())
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
534
|
+
with ExitStack() as exit_stack:
|
|
535
|
+
provenance_writer: ProvenanceQuantumGraphWriter | None = None
|
|
536
|
+
if provenance_graph_file is not None:
|
|
537
|
+
if provenance_graph_file is not None and self._num_proc > 1:
|
|
538
|
+
raise NotImplementedError(
|
|
539
|
+
"Provenance writing is not implemented for multiprocess execution."
|
|
540
|
+
)
|
|
541
|
+
provenance_writer = ProvenanceQuantumGraphWriter(
|
|
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)
|
|
536
559
|
|
|
537
560
|
def _make_xgraph(
|
|
538
561
|
self, new_graph: PredictedQuantumGraph, old_graph: QuantumGraph | None
|
|
@@ -576,7 +599,9 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
576
599
|
raise MPGraphExecutorError("Updated execution graph has dependency cycle.")
|
|
577
600
|
return xgraph
|
|
578
601
|
|
|
579
|
-
def _execute_quanta_in_process(
|
|
602
|
+
def _execute_quanta_in_process(
|
|
603
|
+
self, xgraph: networkx.DiGraph, report: Report, provenance_writer: ProvenanceQuantumGraphWriter | None
|
|
604
|
+
) -> None:
|
|
580
605
|
"""Execute all Quanta in current process.
|
|
581
606
|
|
|
582
607
|
Parameters
|
|
@@ -589,6 +614,9 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
589
614
|
`.quantum_graph.PredictedQuantumGraph.quantum_only_xgraph`.
|
|
590
615
|
report : `Report`
|
|
591
616
|
Object for reporting execution status.
|
|
617
|
+
provenance_writer : `.quantum_graph.ProvenanceQuantumGraphWriter` or \
|
|
618
|
+
`None`
|
|
619
|
+
Object for recording provenance.
|
|
592
620
|
"""
|
|
593
621
|
|
|
594
622
|
def tiebreaker_sort_key(quantum_id: uuid.UUID) -> tuple:
|
|
@@ -606,16 +634,19 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
606
634
|
|
|
607
635
|
_LOG.debug("Executing %s (%s@%s)", quantum_id, task_node.label, data_id)
|
|
608
636
|
fail_exit_code: int | None = None
|
|
637
|
+
task_metadata: TaskMetadata | None = None
|
|
638
|
+
task_logs = ButlerLogRecords([])
|
|
609
639
|
try:
|
|
610
640
|
# For some exception types we want to exit immediately with
|
|
611
641
|
# exception-specific exit code, but we still want to start
|
|
612
642
|
# debugger before exiting if debugging is enabled.
|
|
613
643
|
try:
|
|
614
|
-
|
|
615
|
-
task_node, quantum, quantum_id=quantum_id
|
|
644
|
+
execution_result = self._quantum_executor.execute(
|
|
645
|
+
task_node, quantum, quantum_id=quantum_id, log_records=task_logs
|
|
616
646
|
)
|
|
617
|
-
if
|
|
618
|
-
report.quantaReports.append(
|
|
647
|
+
if execution_result.report:
|
|
648
|
+
report.quantaReports.append(execution_result.report)
|
|
649
|
+
task_metadata = execution_result.task_metadata
|
|
619
650
|
success_count += 1
|
|
620
651
|
walker.finish(quantum_id)
|
|
621
652
|
except RepeatableQuantumError as exc:
|
|
@@ -701,6 +732,11 @@ class MPGraphExecutor(QuantumGraphExecutor):
|
|
|
701
732
|
)
|
|
702
733
|
failed_count += 1
|
|
703
734
|
|
|
735
|
+
if provenance_writer is not None:
|
|
736
|
+
provenance_writer.write_quantum_provenance(
|
|
737
|
+
quantum_id, metadata=task_metadata, logs=task_logs
|
|
738
|
+
)
|
|
739
|
+
|
|
704
740
|
_LOG.info(
|
|
705
741
|
"Executed %d quanta successfully, %d failed and %d remain out of total %d quanta.",
|
|
706
742
|
success_count,
|
{lsst_pipe_base-30.0.0rc1 → lsst_pipe_base-30.0.0rc3}/python/lsst/pipe/base/quantum_graph/_common.py
RENAMED
|
@@ -448,14 +448,15 @@ class BaseQuantumGraphWriter:
|
|
|
448
448
|
uri: ResourcePathExpression,
|
|
449
449
|
header: HeaderModel,
|
|
450
450
|
pipeline_graph: PipelineGraph,
|
|
451
|
-
indices: dict[uuid.UUID, int],
|
|
452
451
|
*,
|
|
453
452
|
address_filename: str,
|
|
454
|
-
compressor: Compressor,
|
|
455
453
|
cdict_data: bytes | None = None,
|
|
454
|
+
zstd_level: int = 10,
|
|
456
455
|
) -> Iterator[Self]:
|
|
457
456
|
uri = ResourcePath(uri)
|
|
458
|
-
address_writer = AddressWriter(
|
|
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)
|
|
459
460
|
with uri.open(mode="wb") as stream:
|
|
460
461
|
with zipfile.ZipFile(stream, mode="w", compression=zipfile.ZIP_STORED) as zf:
|
|
461
462
|
self = cls(zf, compressor, address_writer, header.int_size)
|
|
@@ -205,13 +205,6 @@ 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
|
-
|
|
215
208
|
addresses: list[dict[uuid.UUID, Address]] = dataclasses.field(default_factory=list)
|
|
216
209
|
"""Addresses to store with each UUID.
|
|
217
210
|
|
|
@@ -229,18 +222,15 @@ class AddressWriter:
|
|
|
229
222
|
int_size : `int`
|
|
230
223
|
Number of bytes to use for all integers.
|
|
231
224
|
"""
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
)
|
|
225
|
+
indices: set[uuid.UUID] = set()
|
|
226
|
+
for address_map in self.addresses:
|
|
227
|
+
indices.update(address_map.keys())
|
|
238
228
|
stream.write(int_size.to_bytes(1))
|
|
239
|
-
stream.write(len(
|
|
229
|
+
stream.write(len(indices).to_bytes(int_size))
|
|
240
230
|
stream.write(len(self.addresses).to_bytes(int_size))
|
|
241
231
|
empty_address = Address()
|
|
242
|
-
for key in sorted(
|
|
243
|
-
row = AddressRow(key,
|
|
232
|
+
for n, key in enumerate(sorted(indices, key=attrgetter("int"))):
|
|
233
|
+
row = AddressRow(key, n, [m.get(key, empty_address) for m in self.addresses])
|
|
244
234
|
_LOG.debug("Wrote address %s.", row)
|
|
245
235
|
row.write(stream, int_size)
|
|
246
236
|
|