lsst-pipe-base 29.2025.1400__tar.gz → 29.2025.1600__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.
Files changed (145) hide show
  1. {lsst_pipe_base-29.2025.1400/python/lsst_pipe_base.egg-info → lsst_pipe_base-29.2025.1600}/PKG-INFO +2 -1
  2. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/working-with-pipeline-graphs.rst +99 -0
  3. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/pyproject.toml +3 -0
  4. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/all_dimensions_quantum_graph_builder.py +17 -0
  5. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/_loadHelpers.py +4 -0
  6. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/graph.py +2 -2
  7. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline.py +1 -1
  8. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipelineIR.py +10 -1
  9. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/__main__.py +1 -0
  10. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_exceptions.py +7 -0
  11. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_pipeline_graph.py +360 -11
  12. lsst_pipe_base-29.2025.1600/python/lsst/pipe/base/pipeline_graph/expressions.py +271 -0
  13. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/__init__.py +1 -0
  14. lsst_pipe_base-29.2025.1600/python/lsst/pipe/base/pipeline_graph/visualization/_formatting.py +529 -0
  15. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_mermaid.py +17 -25
  16. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_options.py +11 -3
  17. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_show.py +23 -3
  18. lsst_pipe_base-29.2025.1600/python/lsst/pipe/base/pipeline_graph/visualization/_status_annotator.py +250 -0
  19. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/quantum_provenance_graph.py +28 -0
  20. lsst_pipe_base-29.2025.1600/python/lsst/pipe/base/version.py +2 -0
  21. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600/python/lsst_pipe_base.egg-info}/PKG-INFO +2 -1
  22. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/SOURCES.txt +3 -0
  23. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/requires.txt +1 -0
  24. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_pipeline.py +22 -0
  25. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_pipelineIR.py +32 -32
  26. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_pipeline_graph.py +119 -0
  27. lsst_pipe_base-29.2025.1600/tests/test_pipeline_graph_expressions.py +127 -0
  28. lsst_pipe_base-29.2025.1400/python/lsst/pipe/base/pipeline_graph/visualization/_formatting.py +0 -234
  29. lsst_pipe_base-29.2025.1400/python/lsst/pipe/base/version.py +0 -2
  30. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/COPYRIGHT +0 -0
  31. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/LICENSE +0 -0
  32. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/MANIFEST.in +0 -0
  33. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/README.md +0 -0
  34. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/bsd_license.txt +0 -0
  35. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/CHANGES.rst +0 -0
  36. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/creating-a-pipeline.rst +0 -0
  37. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/creating-a-pipelinetask.rst +0 -0
  38. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/creating-a-task.rst +0 -0
  39. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/index.rst +0 -0
  40. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/task-framework-overview.rst +0 -0
  41. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/task-retargeting-howto.rst +0 -0
  42. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/testing-a-pipeline-task.rst +0 -0
  43. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/doc/lsst.pipe.base/testing-pipelines-with-mocks.rst +0 -0
  44. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/gpl-v3.0.txt +0 -0
  45. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/__init__.py +0 -0
  46. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/__init__.py +0 -0
  47. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/__init__.py +0 -0
  48. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_datasetQueryConstraints.py +0 -0
  49. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_dataset_handle.py +0 -0
  50. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_instrument.py +0 -0
  51. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_observation_dimension_packer.py +0 -0
  52. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_quantumContext.py +0 -0
  53. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_status.py +0 -0
  54. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/_task_metadata.py +0 -0
  55. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/automatic_connection_constants.py +0 -0
  56. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/caching_limited_butler.py +0 -0
  57. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/__init__.py +0 -0
  58. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/_get_cli_subcommands.py +0 -0
  59. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/cmd/__init__.py +0 -0
  60. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/cmd/commands.py +0 -0
  61. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/opt/__init__.py +0 -0
  62. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/opt/arguments.py +0 -0
  63. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/cli/opt/options.py +0 -0
  64. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/config.py +0 -0
  65. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/configOverrides.py +0 -0
  66. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/connectionTypes.py +0 -0
  67. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/connections.py +0 -0
  68. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/dot_tools.py +0 -0
  69. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/executionButlerBuilder.py +0 -0
  70. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/execution_reports.py +0 -0
  71. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/formatters/__init__.py +0 -0
  72. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/formatters/pexConfig.py +0 -0
  73. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/__init__.py +0 -0
  74. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/_implDetails.py +0 -0
  75. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/_versionDeserializers.py +0 -0
  76. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/graphSummary.py +0 -0
  77. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/graph/quantumNode.py +0 -0
  78. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/mermaid_tools.py +0 -0
  79. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipelineTask.py +0 -0
  80. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/__init__.py +0 -0
  81. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_dataset_types.py +0 -0
  82. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_edges.py +0 -0
  83. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_mapping_views.py +0 -0
  84. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_nodes.py +0 -0
  85. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_task_subsets.py +0 -0
  86. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/_tasks.py +0 -0
  87. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/io.py +0 -0
  88. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_dot.py +0 -0
  89. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_layout.py +0 -0
  90. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_merge.py +0 -0
  91. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/pipeline_graph/visualization/_printer.py +0 -0
  92. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/prerequisite_helpers.py +0 -0
  93. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/py.typed +0 -0
  94. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/quantum_graph_builder.py +0 -0
  95. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/quantum_graph_skeleton.py +0 -0
  96. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/script/__init__.py +0 -0
  97. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/script/register_instrument.py +0 -0
  98. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/script/retrieve_artifacts_for_quanta.py +0 -0
  99. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/script/transfer_from_graph.py +0 -0
  100. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/script/zip_from_graph.py +0 -0
  101. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/struct.py +0 -0
  102. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/task.py +0 -0
  103. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/taskFactory.py +0 -0
  104. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/testUtils.py +0 -0
  105. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/__init__.py +0 -0
  106. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/mocks/__init__.py +0 -0
  107. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/mocks/_data_id_match.py +0 -0
  108. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/mocks/_pipeline_task.py +0 -0
  109. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/mocks/_storage_class.py +0 -0
  110. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/no_dimensions.py +0 -0
  111. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/pipelineStepTester.py +0 -0
  112. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/simpleQGraph.py +0 -0
  113. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/tests/util.py +0 -0
  114. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst/pipe/base/utils.py +0 -0
  115. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/dependency_links.txt +0 -0
  116. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/entry_points.txt +0 -0
  117. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/top_level.txt +0 -0
  118. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/python/lsst_pipe_base.egg-info/zip-safe +0 -0
  119. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/setup.cfg +0 -0
  120. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_adjust_all_quanta.py +0 -0
  121. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_caching_limited_butler.py +0 -0
  122. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_cliCmdRegisterInstrument.py +0 -0
  123. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_configOverrides.py +0 -0
  124. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_config_formatter.py +0 -0
  125. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_connections.py +0 -0
  126. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_dataid_match.py +0 -0
  127. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_dataset_handle.py +0 -0
  128. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_dot_tools.py +0 -0
  129. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_dynamic_connections.py +0 -0
  130. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_executionButler.py +0 -0
  131. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_execution_reports.py +0 -0
  132. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_graphBuilder.py +0 -0
  133. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_init_output_run.py +0 -0
  134. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_instrument.py +0 -0
  135. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_mermaid.py +0 -0
  136. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_pipelineLoadSubset.py +0 -0
  137. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_pipelineTask.py +0 -0
  138. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_quantumGraph.py +0 -0
  139. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_quantum_provenance_graph.py +0 -0
  140. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_quantum_success_caveats.py +0 -0
  141. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_struct.py +0 -0
  142. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_task.py +0 -0
  143. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_taskmetadata.py +0 -0
  144. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_testUtils.py +0 -0
  145. {lsst_pipe_base-29.2025.1400 → lsst_pipe_base-29.2025.1600}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-pipe-base
3
- Version: 29.2025.1400
3
+ Version: 29.2025.1600
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: BSD 3-Clause License
@@ -27,6 +27,7 @@ Requires-Dist: lsst-pex-config
27
27
  Requires-Dist: astropy
28
28
  Requires-Dist: pydantic<3.0,>=2
29
29
  Requires-Dist: networkx
30
+ Requires-Dist: wcwidth
30
31
  Requires-Dist: pyyaml>=5.1
31
32
  Requires-Dist: numpy>=1.17
32
33
  Requires-Dist: frozendict
@@ -86,3 +86,102 @@ The export methods include:
86
86
  This is a `networkx.DiGraph`, because all dataset types that connect a pair of tasks are rolled into one edge, and edges have no state.
87
87
  - `~PipelineGraph.make_dataset_type_graph` exports just dataset type nodes; it is one "bipartite projection" of the full graph.
88
88
  This is a `networkx.DiGraph`, because all tasks that connect a pair of dataset types are rolled into one edge, and edges have no state.
89
+
90
+ .. _pipeline-graph-subset-expressions:
91
+
92
+ Pipeline graph subset expressions
93
+ ---------------------------------
94
+
95
+ The `PipelineGraph.select` and `PipelineGraph.select_tasks` methods utilize a boolean expression language to select a subset of the tasks in a `PipelineGraph`.
96
+ The language uses familiar set operators for union (``|``), intersection (``&``), and set-inversion (``~``), with the operands any of the following:
97
+
98
+ - a task label
99
+ - a task subset label
100
+ - a dataset type name (resolves to the label of the producing task, or an empty set for overall inputs; may not be an init-output)
101
+ - an ancestor or descendant search, starting from a task label or dataset type name (see below)
102
+ - a nested expression.
103
+
104
+ Parentheses may be used for grouping.
105
+
106
+ Task labels, task subset labels, and dataset type names all appear as regular unquoted strings.
107
+ In cases where dataset type name is the same as a task or task subset label, a prefix can be added to disambiguate: ``T:`` for task, ``D:`` for dataset type, and ``S:`` for task subset.
108
+
109
+ An ancestor or descendant search uses ``<``, ``<=``, ``>``, and ``>=`` as *unary* operators, with the operands being task labels or dataset type names (which may be qualified with ``T:`` or ``D:``, respectively, as described above).
110
+ For tasks these searches are straightforward:
111
+
112
+ - ``<`` and ``<=`` select all tasks whose outputs are consumed by the operand task, recursively, with the operand task itself included only for ``<=``.
113
+
114
+ - ``>`` and ``>=`` select all tasks that consume the outputs of the operand task, rescursively, with the operand task itself included only for ``>=``.
115
+
116
+ Because the expressions are logically set operations on tasks, ancestor and descendant searches on dataset types work differently and are not quite symmetric:
117
+
118
+ - ``<`` and ``<=`` act like an ancestor search on the task that produces the operand dataset type.
119
+ For overall inputs they yield empty sets.
120
+ Init-outputs are not permitted.
121
+
122
+ - ``>`` and ``>=`` act like a union of descendant searches on all tasks that consume the operand dataset type.
123
+ This includes tasks that consume the operand dataset type as an init-input (this is the only context in which init-output dataset types can appear in expressions).
124
+ For ``>=`` only, the task that produces the operand dataset type is also included, but in this case it is an error for the operand to be an init-output.
125
+
126
+ Note that these ancestor and descendant searches are not the only useful way to define the subset of a pipeline that is "before" or "after" a task; the ancestors ``<a`` of a task ``a`` are those that *must* be run before ``a``, while the inverse of the descendants ``~>=a`` are the tasks that *can* be run before ``a``.
127
+ Similarly, the descendants ``>a`` of ``a`` are the tasks that can only be run after ``a``, while the inverse of the ancestors ``~<=a`` are all tasks that can be run after ``a``.
128
+
129
+ Examples
130
+ ^^^^^^^^
131
+
132
+ All tasks in subset ``s`` except task ``b``:
133
+
134
+ .. code-block:: text
135
+
136
+ s & ~b
137
+
138
+ All tasks in either subset ``r`` or subset ``s`` that would need to be re-run to pick up a change in the behavior of task ``a``:
139
+
140
+ .. code-block:: text
141
+
142
+ (r | s) & >=a
143
+
144
+ All tasks in subset ``s`` that need to be run to accept failures in task ``c`` as unrecoverable, after a previous run left some quanta of those tasks blocked:
145
+
146
+ .. code-block:: text
147
+
148
+ s & >a
149
+
150
+ All tasks needed to produce dataset type ``d`` or dataset type ``e``:
151
+
152
+ .. code-block:: text
153
+
154
+ <d | <e
155
+
156
+ All tasks except task ``a`` that can be run without producing dataset type ``f``:
157
+
158
+ .. code-block:: text
159
+
160
+ ~a & ~>=f
161
+
162
+
163
+ Formal grammar
164
+ ^^^^^^^^^^^^^^
165
+
166
+ .. code-block:: bnf
167
+
168
+ <expression> ::= ~ <expression>
169
+ | <expression> | <expression>
170
+ | <expression> & <expression>
171
+ | (<expression>)
172
+ | S:<subset-label>
173
+ | <subset-label>
174
+ | < <node>
175
+ | <= <node>
176
+ | > <node>
177
+ | <= <node>
178
+ | <node>
179
+
180
+ <node> ::= T:<task-label>
181
+ | <task-label>
182
+ | D:<dataset-type-name>
183
+ | <dataset-type-name>
184
+
185
+ Whitespace is ignored, but is not permitted before or after the ``:`` in qualified identifiers.
186
+
187
+ The operator precedence in the absence of parenthesis is ``~``, ``&``, ``|`` ( highest to lowest).
@@ -30,6 +30,7 @@ dependencies = [
30
30
  "astropy",
31
31
  "pydantic >=2,<3.0",
32
32
  "networkx",
33
+ "wcwidth",
33
34
  "pyyaml >= 5.1",
34
35
  "numpy >= 1.17",
35
36
  "frozendict",
@@ -205,4 +206,6 @@ exclude = [
205
206
  "^test_.*", # Do not test docstrings in test code.
206
207
  '^commands\.', # Click docstrings, not numpydoc
207
208
  '\._[a-zA-Z_]+$', # Private methods.
209
+ '_ParserLex\.', # Docstrings are not numpydoc
210
+ '_ParserYacc\.', # Docstrings are not numpydoc
208
211
  ]
@@ -39,6 +39,8 @@ from collections import defaultdict
39
39
  from collections.abc import Iterable, Mapping
40
40
  from typing import TYPE_CHECKING, Any, TypeAlias, final
41
41
 
42
+ import astropy.table
43
+
42
44
  from lsst.daf.butler import (
43
45
  Butler,
44
46
  DataCoordinate,
@@ -85,6 +87,11 @@ class AllDimensionsQuantumGraphBuilder(QuantumGraphBuilder):
85
87
  (sometimes catastrophically bad) query plan.
86
88
  bind : `~collections.abc.Mapping`, optional
87
89
  Variable substitutions for the ``where`` expression.
90
+ data_id_tables : `~collections.abc.Iterable` [ `astropy.table.Table` ],\
91
+ optional
92
+ Tables of data IDs to join in as constraints. Missing dimensions that
93
+ are constrained by the ``where`` argument or pipeline data ID will be
94
+ filled in automatically.
88
95
  **kwargs
89
96
  Additional keyword arguments forwarded to `QuantumGraphBuilder`.
90
97
 
@@ -113,6 +120,7 @@ class AllDimensionsQuantumGraphBuilder(QuantumGraphBuilder):
113
120
  where: str = "",
114
121
  dataset_query_constraint: DatasetQueryConstraintVariant = DatasetQueryConstraintVariant.ALL,
115
122
  bind: Mapping[str, Any] | None = None,
123
+ data_id_tables: Iterable[astropy.table.Table] = (),
116
124
  **kwargs: Any,
117
125
  ):
118
126
  super().__init__(pipeline_graph, butler, **kwargs)
@@ -120,6 +128,7 @@ class AllDimensionsQuantumGraphBuilder(QuantumGraphBuilder):
120
128
  self.where = where
121
129
  self.dataset_query_constraint = dataset_query_constraint
122
130
  self.bind = bind
131
+ self.data_id_tables = list(data_id_tables)
123
132
 
124
133
  @timeMethod
125
134
  def process_subgraph(self, subgraph: PipelineGraph) -> QuantumGraphSkeleton:
@@ -194,6 +203,14 @@ class AllDimensionsQuantumGraphBuilder(QuantumGraphBuilder):
194
203
  f"{self.where!r}, bind={self.bind!r})"
195
204
  )
196
205
  query = query.where(tree.subgraph.data_id, self.where, bind=self.bind)
206
+ # It's important for tables to be joined in last, so data IDs from
207
+ # pipeline and where can be used to fill in missing columns.
208
+ for table in self.data_id_tables:
209
+ # If this is from ctrl_mpexec's pipetask, it'll have added
210
+ # a filename to the metadata for us.
211
+ table_name = table.meta.get("filename", "unknown")
212
+ query_cmd.append(f" query = query.join_data_coordinate_table(<{table_name}>)")
213
+ query = query.join_data_coordinate_table(table)
197
214
  self.log.verbose("Querying for data IDs via: %s", "\n".join(query_cmd))
198
215
  # Allow duplicates from common skypix overlaps to make some queries
199
216
  # run faster.
@@ -65,6 +65,7 @@ class LoadHelper(AbstractContextManager["LoadHelper"]):
65
65
  to upgrade them to the latest format before they can be used in
66
66
  production.
67
67
  """
68
+ fullRead: bool = False
68
69
 
69
70
  def __post_init__(self) -> None:
70
71
  self._resourceHandle: ResourceHandleProtocol | None = None
@@ -261,6 +262,9 @@ class LoadHelper(AbstractContextManager["LoadHelper"]):
261
262
  def __enter__(self) -> LoadHelper:
262
263
  if isinstance(self.uri, BinaryIO | BytesIO | BufferedRandom):
263
264
  self._resourceHandle = self.uri
265
+ elif self.fullRead:
266
+ local = self._exitStack.enter_context(self.uri.as_local())
267
+ self._resourceHandle = self._exitStack.enter_context(local.open("rb"))
264
268
  else:
265
269
  self._resourceHandle = self._exitStack.enter_context(self.uri.open("rb"))
266
270
  self._initialize()
@@ -963,7 +963,7 @@ class QuantumGraph:
963
963
  """
964
964
  uri = ResourcePath(uri)
965
965
  if uri.getExtension() in {".qgraph"}:
966
- with LoadHelper(uri, minimumVersion) as loader:
966
+ with LoadHelper(uri, minimumVersion, fullRead=(nodes is None)) as loader:
967
967
  qgraph = loader.load(universe, nodes, graphID)
968
968
  else:
969
969
  raise ValueError(f"Only know how to handle files saved as `.qgraph`, not {uri}")
@@ -1230,7 +1230,7 @@ class QuantumGraph:
1230
1230
  being loaded or if the supplied uri does not point at a valid
1231
1231
  `QuantumGraph` save file.
1232
1232
  """
1233
- with LoadHelper(file, minimumVersion) as loader:
1233
+ with LoadHelper(file, minimumVersion, fullRead=(nodes is None)) as loader:
1234
1234
  qgraph = loader.load(universe, nodes, graphID)
1235
1235
  if not isinstance(qgraph, QuantumGraph):
1236
1236
  raise TypeError(f"QuantumGraph file contains unexpected object type: {type(qgraph)}")
@@ -427,7 +427,7 @@ class Pipeline:
427
427
  if "," in label_subset:
428
428
  if ".." in label_subset:
429
429
  raise ValueError(
430
- "Can only specify a list of labels or a rangewhen loading a Pipline not both"
430
+ "Can only specify a list of labels or a range when loading a Pipeline, not both."
431
431
  )
432
432
  args = {"labels": set(label_subset.split(","))}
433
433
  # labels supplied as a range
@@ -980,10 +980,19 @@ class PipelineIR:
980
980
  if extraTaskLabels := (labeled_subset.subset - pipeline.tasks.keys()):
981
981
  match subsetCtrl:
982
982
  case PipelineSubsetCtrl.DROP:
983
- pipeline.labeled_subsets.pop(label)
983
+ del pipeline.labeled_subsets[label]
984
984
  case PipelineSubsetCtrl.EDIT:
985
985
  for extra in extraTaskLabels:
986
986
  labeled_subset.subset.discard(extra)
987
+ elif subsetCtrl is PipelineSubsetCtrl.DROP and not labeled_subset.subset:
988
+ # When mode is DROP, also drop any subsets that were already
989
+ # empty. This ensures we drop steps that were emptied-out by
990
+ # (earlier) imports with exclude in EDIT mode. Note that we
991
+ # don't want to drop those steps when they're first excluded
992
+ # down to nothing, because the pipeline might be about to add
993
+ # new tasks back into them, and then we'd want to preserve the
994
+ # step definitions.
995
+ del pipeline.labeled_subsets[label]
987
996
 
988
997
  # remove any steps that correspond to removed subsets
989
998
  new_steps = []
@@ -334,6 +334,7 @@ class DisplayArguments:
334
334
  dimensions=args.dimensions,
335
335
  task_classes=args.task_classes,
336
336
  storage_classes=args.storage_classes,
337
+ status=None,
337
338
  ),
338
339
  merge_input_trees=args.merge_input_trees,
339
340
  merge_output_trees=args.merge_output_trees,
@@ -31,6 +31,7 @@ __all__ = (
31
31
  "DuplicateOutputError",
32
32
  "EdgesChangedError",
33
33
  "IncompatibleDatasetTypeError",
34
+ "InvalidExpressionError",
34
35
  "InvalidStepsError",
35
36
  "PipelineDataCycleError",
36
37
  "PipelineGraphError",
@@ -102,5 +103,11 @@ class PipelineGraphExceptionSafetyError(PipelineGraphError):
102
103
  """
103
104
 
104
105
 
106
+ class InvalidExpressionError(PipelineGraphError):
107
+ """Exception raised when a pipeline subset expression could not be parsed
108
+ or applied.
109
+ """
110
+
111
+
105
112
  class InvalidStepsError(PipelineGraphError):
106
113
  """Exception raised when the step definitions are invalid."""