dkist-processing-common 12.1.0rc1__tar.gz → 12.2.0__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 (149) hide show
  1. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/CHANGELOG.rst +35 -0
  2. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/PKG-INFO +2 -2
  3. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/constants.py +14 -8
  4. dkist_processing_common-12.2.0/dkist_processing_common/models/extras.py +35 -0
  5. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/tags.py +13 -0
  6. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/id_bud.py +7 -4
  7. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/l1_output_data.py +23 -14
  8. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/output_data_base.py +25 -4
  9. dkist_processing_common-12.2.0/dkist_processing_common/tasks/write_extra.py +333 -0
  10. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/write_l1.py +2 -55
  11. dkist_processing_common-12.2.0/dkist_processing_common/tasks/write_l1_base.py +67 -0
  12. dkist_processing_common-12.2.0/dkist_processing_common/tests/test_construct_dataset_extras.py +224 -0
  13. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_output_data_base.py +24 -2
  14. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_transfer_l1_output_data.py +1 -0
  15. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_trial_catalog.py +2 -0
  16. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_write_l1.py +0 -1
  17. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common.egg-info/PKG-INFO +2 -2
  18. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common.egg-info/SOURCES.txt +4 -8
  19. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common.egg-info/requires.txt +1 -1
  20. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/pyproject.toml +1 -1
  21. dkist_processing_common-12.1.0rc1/changelog/280.misc.rst +0 -1
  22. dkist_processing_common-12.1.0rc1/changelog/282.feature.2.rst +0 -2
  23. dkist_processing_common-12.1.0rc1/changelog/282.feature.rst +0 -2
  24. dkist_processing_common-12.1.0rc1/changelog/284.feature.rst +0 -1
  25. dkist_processing_common-12.1.0rc1/changelog/285.feature.rst +0 -2
  26. dkist_processing_common-12.1.0rc1/changelog/285.misc.rst +0 -2
  27. dkist_processing_common-12.1.0rc1/changelog/286.feature.rst +0 -2
  28. dkist_processing_common-12.1.0rc1/changelog/287.misc.rst +0 -1
  29. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/.gitignore +0 -0
  30. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/.pre-commit-config.yaml +0 -0
  31. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/.readthedocs.yml +0 -0
  32. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/.snyk +0 -0
  33. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/README.rst +0 -0
  34. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/bitbucket-pipelines.yml +0 -0
  35. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/changelog/.gitempty +0 -0
  36. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/__init__.py +0 -0
  37. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/_util/__init__.py +0 -0
  38. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/_util/constants.py +0 -0
  39. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/_util/graphql.py +0 -0
  40. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/_util/scratch.py +0 -0
  41. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/_util/tags.py +0 -0
  42. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/__init__.py +0 -0
  43. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/array.py +0 -0
  44. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/asdf.py +0 -0
  45. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/basemodel.py +0 -0
  46. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/bytes.py +0 -0
  47. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/fits.py +0 -0
  48. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/iobase.py +0 -0
  49. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/json.py +0 -0
  50. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/path.py +0 -0
  51. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/quality.py +0 -0
  52. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/codecs/str.py +0 -0
  53. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/config.py +0 -0
  54. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
  55. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/fonts/__init__.py +0 -0
  56. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/manual.py +0 -0
  57. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/__init__.py +0 -0
  58. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/dkist_location.py +0 -0
  59. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/fits_access.py +0 -0
  60. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/flower_pot.py +0 -0
  61. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/fried_parameter.py +0 -0
  62. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/graphql.py +0 -0
  63. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/input_dataset.py +0 -0
  64. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/message.py +0 -0
  65. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/message_queue_binding.py +0 -0
  66. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/metric_code.py +0 -0
  67. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/parameters.py +0 -0
  68. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/quality.py +0 -0
  69. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/task_name.py +0 -0
  70. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/telemetry.py +0 -0
  71. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/models/wavelength.py +0 -0
  72. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/__init__.py +0 -0
  73. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/average_bud.py +0 -0
  74. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/cs_step.py +0 -0
  75. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
  76. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
  77. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/l0_fits_access.py +0 -0
  78. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/l1_fits_access.py +0 -0
  79. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/lookup_bud.py +0 -0
  80. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/near_bud.py +0 -0
  81. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/observing_program_id_bud.py +0 -0
  82. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
  83. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/quality.py +0 -0
  84. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/retarder.py +0 -0
  85. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
  86. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/task.py +0 -0
  87. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/time.py +0 -0
  88. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/unique_bud.py +0 -0
  89. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/parsers/wavelength.py +0 -0
  90. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/__init__.py +0 -0
  91. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/assemble_movie.py +0 -0
  92. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/base.py +0 -0
  93. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
  94. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/globus.py +0 -0
  95. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
  96. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
  97. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
  98. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
  99. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -0
  100. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/mixin/quality/_metrics.py +0 -0
  101. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/parse_l0_input_data.py +0 -0
  102. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/quality_metrics.py +0 -0
  103. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/teardown.py +0 -0
  104. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/transfer_input_data.py +0 -0
  105. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/trial_catalog.py +0 -0
  106. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tasks/trial_output_data.py +0 -0
  107. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/__init__.py +0 -0
  108. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/conftest.py +0 -0
  109. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/mock_metadata_store.py +0 -0
  110. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
  111. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_assemble_quality.py +0 -0
  112. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_base.py +0 -0
  113. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_codecs.py +0 -0
  114. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_constants.py +0 -0
  115. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_cs_step.py +0 -0
  116. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_dkist_location.py +0 -0
  117. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_fits_access.py +0 -0
  118. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_flower_pot.py +0 -0
  119. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_fried_parameter.py +0 -0
  120. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_input_dataset.py +0 -0
  121. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
  122. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
  123. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_manual_processing.py +0 -0
  124. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_parameters.py +0 -0
  125. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_parse_l0_input_data.py +0 -0
  126. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
  127. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_quality.py +0 -0
  128. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_quality_mixin.py +0 -0
  129. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_scratch.py +0 -0
  130. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_stems.py +0 -0
  131. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
  132. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_tags.py +0 -0
  133. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_task_name.py +0 -0
  134. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_task_parsing.py +0 -0
  135. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_teardown.py +0 -0
  136. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
  137. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
  138. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common/tests/test_workflow_task_base.py +0 -0
  139. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
  140. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/dkist_processing_common.egg-info/top_level.txt +0 -0
  141. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/Makefile +0 -0
  142. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/changelog.rst +0 -0
  143. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/conf.py +0 -0
  144. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/index.rst +0 -0
  145. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/landing_page.rst +0 -0
  146. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/make.bat +0 -0
  147. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/docs/requirements.txt +0 -0
  148. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/licenses/LICENSE.rst +0 -0
  149. {dkist_processing_common-12.1.0rc1 → dkist_processing_common-12.2.0}/setup.cfg +0 -0
@@ -1,3 +1,38 @@
1
+ v12.2.0 (2026-01-30)
2
+ ====================
3
+
4
+ Features
5
+ --------
6
+
7
+ - Add the framework for using Dataset Extras, that is, other data that can be included with the L1 FITS files generated by the regular pipeline. A new abstract class, WriteL1DatasetExtras, provides helper functionality for use in the instrument pipelines. (`#272 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/272>`__)
8
+
9
+
10
+ v12.1.0 (2026-01-26)
11
+ ====================
12
+
13
+ Features
14
+ --------
15
+
16
+ - Add `ListStem` base class for huge speedup in cases where the keys don't matter and the `getter` logic only depends on the
17
+ list of values computed by `setter`. This is the case for most (all?) "Buds". (`#282 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/282>`__)
18
+ - Add `SetStem` base class that has all the benefits of `ListStem` but also gets a speedup by storing values in a `set` for
19
+ cases where repeated values don't need to be tracked. (`#282 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/282>`__)
20
+ - Speed up parsing of the `*CadenceBud`, `TaskDateBeginBud`, and `[Task]NearFloatBud` by basing these buds on `ListStem`. (`#284 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/284>`__)
21
+ - Speed up `NumCSStepBud`, `[Task]UniqueBud`, `[Task]ContributingIdsBud`, and `TaskRoundTimeBudBase` parsing by basing
22
+ these buds on `SetStem`. (`#285 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/285>`__)
23
+ - Speed up `CSStepFlower` parsing by using an internal set to keep track of the unique `CSStep` objects. This removes the
24
+ need to compute the unique set when computing the tag for each file. (`#286 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/286>`__)
25
+
26
+
27
+ Misc
28
+ ----
29
+
30
+ - Speed up the reading of INPUT files in Parse tasks by turning off image decompression and checksum checks. (`#280 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/280>`__)
31
+ - Update `RetarderNameBud` to drop "clear" values (i.e., the retarder is out of the beam) in the `setter` instead of the `getter`.
32
+ This brings it in line with standard Bud-practice. (`#285 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/285>`__)
33
+ - Convert the TimeLookupBud to be a SetStem constant. (`#287 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/287>`__)
34
+
35
+
1
36
  v12.0.0 (2026-01-22)
2
37
  ====================
3
38
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-common
3
- Version: 12.1.0rc1
3
+ Version: 12.2.0
4
4
  Summary: Common task classes used by the DKIST science data processing pipelines
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -16,7 +16,7 @@ Description-Content-Type: text/x-rst
16
16
  Requires-Dist: asdf<4.0.0,>=3.5.0
17
17
  Requires-Dist: astropy>=7.0.0
18
18
  Requires-Dist: dkist-fits-specifications<5.0,>=4.0.0
19
- Requires-Dist: dkist-header-validator<6.0,>=5.0.0
19
+ Requires-Dist: dkist-header-validator<6.0,>=5.3.0
20
20
  Requires-Dist: dkist-processing-core==7.0.1
21
21
  Requires-Dist: dkist-processing-pac<4.0,>=3.1
22
22
  Requires-Dist: dkist-service-configuration<5.0,>=4.2.0
@@ -285,18 +285,24 @@ class ConstantsBase:
285
285
  def dark_observing_program_execution_ids(self) -> list[str]:
286
286
  """Return the observing program execution ids constant for the dark task."""
287
287
  observing_programs = self._db_dict[BudName.dark_observing_program_execution_ids]
288
+ if isinstance(observing_programs, str):
289
+ observing_programs = [observing_programs]
288
290
  return list(observing_programs)
289
291
 
290
292
  @property
291
293
  def solar_gain_observing_program_execution_ids(self) -> list[str]:
292
294
  """Return the observing program execution ids constant for the solar_gain task."""
293
295
  observing_programs = self._db_dict[BudName.solar_gain_observing_program_execution_ids]
296
+ if isinstance(observing_programs, str):
297
+ observing_programs = [observing_programs]
294
298
  return list(observing_programs)
295
299
 
296
300
  @property
297
301
  def polcal_observing_program_execution_ids(self) -> list[str]:
298
302
  """Return the observing program execution ids constant."""
299
303
  observing_programs = self._db_dict[BudName.polcal_observing_program_execution_ids]
304
+ if isinstance(observing_programs, str):
305
+ observing_programs = [observing_programs]
300
306
  return list(observing_programs)
301
307
 
302
308
  @property
@@ -467,14 +473,14 @@ class ConstantsBase:
467
473
  return self._db_dict[BudName.solar_gain_gos_polarizer_status]
468
474
 
469
475
  @property
470
- def dark_gos_polarizer_angle(self) -> float:
476
+ def dark_gos_polarizer_angle(self) -> str:
471
477
  """Return the gos polarizer angle constant for the dark task."""
472
- return self._db_dict[BudName.dark_gos_polarizer_angle]
478
+ return str(self._db_dict[BudName.dark_gos_polarizer_angle])
473
479
 
474
480
  @property
475
- def solar_gain_gos_polarizer_angle(self) -> float:
481
+ def solar_gain_gos_polarizer_angle(self) -> str:
476
482
  """Return the gos polarizer angle constant for the solar gain task."""
477
- return self._db_dict[BudName.solar_gain_gos_polarizer_angle]
483
+ return str(self._db_dict[BudName.solar_gain_gos_polarizer_angle])
478
484
 
479
485
  @property
480
486
  def dark_gos_retarder_status(self) -> str:
@@ -487,14 +493,14 @@ class ConstantsBase:
487
493
  return self._db_dict[BudName.solar_gain_gos_retarder_status]
488
494
 
489
495
  @property
490
- def dark_gos_retarder_angle(self) -> float:
496
+ def dark_gos_retarder_angle(self) -> str:
491
497
  """Return the gos retarder angle constant for the dark task."""
492
- return self._db_dict[BudName.dark_gos_retarder_angle]
498
+ return str(self._db_dict[BudName.dark_gos_retarder_angle])
493
499
 
494
500
  @property
495
- def solar_gain_gos_retarder_angle(self) -> float:
501
+ def solar_gain_gos_retarder_angle(self) -> str:
496
502
  """Return the gos retarder angle constant for the solar gain task."""
497
- return self._db_dict[BudName.solar_gain_gos_retarder_angle]
503
+ return str(self._db_dict[BudName.solar_gain_gos_retarder_angle])
498
504
 
499
505
  @property
500
506
  def dark_gos_level0_status(self) -> str:
@@ -0,0 +1,35 @@
1
+ """Autocomplete access to dataset extra header sections."""
2
+
3
+ from enum import StrEnum
4
+
5
+
6
+ class DatasetExtraHeaderSection(StrEnum):
7
+ """Enum defining the possible header sections for dataset extras."""
8
+
9
+ common = "common"
10
+ aggregate = "aggregate"
11
+ iptask = "iptask"
12
+ gos = "gos"
13
+ wavecal = "wavecal"
14
+ atlas = "atlas"
15
+ test = "test"
16
+
17
+
18
+ class DatasetExtraType(StrEnum):
19
+ """Enum defining options for dataset extra names."""
20
+
21
+ dark = "DARK"
22
+ background_light = "BACKGROUND LIGHT"
23
+ solar_gain = "SOLAR GAIN"
24
+ characteristic_spectra = "CHARACTERISTIC SPECTRA"
25
+ modulation_state_offsets = "MODULATION STATE OFFSETS"
26
+ beam_angles = "BEAM ANGLES"
27
+ spectral_curvature_shifts = "SPECTRAL CURVATURE SHIFTS"
28
+ wavelength_calibration_input_spectrum = "WAVELENGTH CALIBRATION INPUT SPECTRUM"
29
+ wavelength_calibration_reference_spectrum = "WAVELENGTH CALIBRATION REFERENCE SPECTRUM"
30
+ reference_wavelength_vector = "REFERENCE WAVELENGTH VECTOR"
31
+ demodulation_matrices = "DEMODULATION MATRICES"
32
+ polcal_as_science = "POLCAL AS SCIENCE"
33
+ bad_pixel_map = "BAD PIXEL MAP"
34
+ beam_offsets = "BEAM OFFSETS"
35
+ spectral_curvature_scales = "SPECTRAL CURVATURE SCALES"
@@ -38,6 +38,8 @@ class StemName(StrEnum):
38
38
  dataset_inventory = "DATASET_INVENTORY"
39
39
  asdf = "ASDF"
40
40
  quality_report = "QUALITY_REPORT"
41
+ # Dataset extras
42
+ extra = "EXTRA"
41
43
 
42
44
 
43
45
  class Tag:
@@ -450,3 +452,14 @@ class Tag:
450
452
  An asdf tag
451
453
  """
452
454
  return cls.format_tag(StemName.asdf)
455
+
456
+ @classmethod
457
+ def extra(cls) -> str:
458
+ """
459
+ Return a dataset extra tag.
460
+
461
+ Returns
462
+ -------
463
+ A dataset extra tag
464
+ """
465
+ return cls.format_tag(StemName.extra)
@@ -1,16 +1,17 @@
1
1
  """Base classes for ID bud parsing."""
2
2
 
3
+ from collections import Counter
3
4
  from enum import StrEnum
4
5
  from typing import Callable
5
6
  from typing import Type
6
7
 
7
- from dkist_processing_common.models.flower_pot import SetStem
8
+ from dkist_processing_common.models.flower_pot import ListStem
8
9
  from dkist_processing_common.models.flower_pot import SpilledDirt
9
10
  from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
10
11
  from dkist_processing_common.parsers.task import passthrough_header_ip_task
11
12
 
12
13
 
13
- class ContributingIdsBud(SetStem):
14
+ class ContributingIdsBud(ListStem):
14
15
  """Base class for contributing ID buds."""
15
16
 
16
17
  def __init__(self, constant_name: str, metadata_key: str | StrEnum):
@@ -35,13 +36,15 @@ class ContributingIdsBud(SetStem):
35
36
 
36
37
  def getter(self) -> tuple[str, ...]:
37
38
  """
38
- Get all ids seen for any type of frame.
39
+ Get all ids seen for any type of frame, sorted by the number of appearances of that ID.
39
40
 
40
41
  Returns
41
42
  -------
42
43
  IDs from all types of frames
43
44
  """
44
- return tuple(self.value_set)
45
+ counts = Counter(self.value_list) # Count the number of appearances of each ID
46
+ sorted_ids = tuple(str(item) for item, count in counts.most_common())
47
+ return sorted_ids
45
48
 
46
49
 
47
50
  class TaskContributingIdsBud(ContributingIdsBud):
@@ -2,18 +2,14 @@
2
2
 
3
3
  import logging
4
4
  from abc import ABC
5
- from itertools import chain
6
5
  from pathlib import Path
7
6
  from typing import Iterable
8
7
 
9
- from dkist_processing_common.codecs.quality import quality_data_decoder
10
8
  from dkist_processing_common.codecs.quality import quality_data_encoder
11
9
  from dkist_processing_common.models.message import CatalogFrameMessage
12
10
  from dkist_processing_common.models.message import CatalogFrameMessageBody
13
11
  from dkist_processing_common.models.message import CatalogObjectMessage
14
12
  from dkist_processing_common.models.message import CatalogObjectMessageBody
15
- from dkist_processing_common.models.message import CreateQualityReportMessage
16
- from dkist_processing_common.models.message import CreateQualityReportMessageBody
17
13
  from dkist_processing_common.models.tags import Tag
18
14
  from dkist_processing_common.tasks.mixin.globus import GlobusMixin
19
15
  from dkist_processing_common.tasks.mixin.interservice_bus import InterserviceBusMixin
@@ -62,15 +58,19 @@ class TransferL1Data(TransferDataBase, GlobusMixin):
62
58
  with self.telemetry_span("Upload quality data"):
63
59
  self.transfer_quality_data()
64
60
 
65
- with self.telemetry_span("Upload science frames"):
61
+ with self.telemetry_span("Upload output frames"):
66
62
  self.transfer_output_frames()
67
63
 
68
64
  def transfer_output_frames(self):
69
- """Create a Globus transfer for all output data."""
70
- transfer_items = self.build_output_frame_transfer_list()
65
+ """Create a Globus transfer for all output data, as well as any available dataset extras."""
66
+ output_transfer_items = self.build_output_frame_transfer_list()
67
+ dataset_extra_transfer_items = self.build_dataset_extra_transfer_list()
68
+ transfer_items = output_transfer_items + dataset_extra_transfer_items
71
69
 
72
70
  logger.info(
73
71
  f"Preparing globus transfer {len(transfer_items)} items: "
72
+ f"{len(output_transfer_items)} output frames. "
73
+ f"{len(dataset_extra_transfer_items)} dataset extras. "
74
74
  f"recipe_run_id={self.recipe_run_id}. "
75
75
  f"transfer_items={transfer_items[:3]}..."
76
76
  )
@@ -189,7 +189,9 @@ class SubmitDatasetMetadata(L1OutputDataBase):
189
189
  class PublishCatalogAndQualityMessages(L1OutputDataBase, InterserviceBusMixin):
190
190
  """Task class for publishing Catalog and Quality Messages."""
191
191
 
192
- def frame_messages(self, paths: Iterable[Path]) -> list[CatalogFrameMessage]:
192
+ def frame_messages(
193
+ self, paths: Iterable[Path], folder_modifier: str | None = None
194
+ ) -> list[CatalogFrameMessage]:
193
195
  """
194
196
  Create the frame messages.
195
197
 
@@ -197,6 +199,8 @@ class PublishCatalogAndQualityMessages(L1OutputDataBase, InterserviceBusMixin):
197
199
  ----------
198
200
  paths
199
201
  The input paths for which to publish frame messages
202
+ folder_modifier
203
+ A subdirectory to use if the files in paths are not in the base directory
200
204
 
201
205
  Returns
202
206
  -------
@@ -204,7 +208,7 @@ class PublishCatalogAndQualityMessages(L1OutputDataBase, InterserviceBusMixin):
204
208
  """
205
209
  message_bodies = [
206
210
  CatalogFrameMessageBody(
207
- objectName=self.format_object_key(path=p),
211
+ objectName=self.format_object_key(path=p, folder_modifier=folder_modifier),
208
212
  conversationId=str(self.recipe_run_id),
209
213
  bucket=self.destination_bucket,
210
214
  )
@@ -233,7 +237,7 @@ class PublishCatalogAndQualityMessages(L1OutputDataBase, InterserviceBusMixin):
233
237
  message_bodies = [
234
238
  CatalogObjectMessageBody(
235
239
  objectType=object_type,
236
- objectName=self.format_object_key(p),
240
+ objectName=self.format_object_key(path=p),
237
241
  bucket=self.destination_bucket,
238
242
  conversationId=str(self.recipe_run_id),
239
243
  groupId=self.constants.dataset_id,
@@ -246,19 +250,24 @@ class PublishCatalogAndQualityMessages(L1OutputDataBase, InterserviceBusMixin):
246
250
  def run(self) -> None:
247
251
  """Run method for this task."""
248
252
  with self.telemetry_span("Gather output data"):
249
- frames = self.read(tags=self.output_frame_tags)
250
- movies = self.read(tags=[Tag.output(), Tag.movie()])
253
+ frames = self.read(
254
+ tags=self.output_frame_tags
255
+ ) # frames is kept as a generator as it is much longer than the other file categories
256
+ extras = list(self.read(tags=self.extra_frame_tags))
257
+ movies = list(self.read(tags=[Tag.output(), Tag.movie()]))
251
258
  quality_data = self.read(tags=[Tag.output(), Tag.quality_data()])
252
259
  with self.telemetry_span("Create message objects"):
253
260
  messages = []
254
261
  messages += self.frame_messages(paths=frames)
255
262
  frame_message_count = len(messages)
263
+ messages += self.frame_messages(paths=extras, folder_modifier="extra")
264
+ extra_message_count = len(extras)
256
265
  messages += self.object_messages(paths=movies, object_type="MOVIE")
257
- object_message_count = len(messages) - frame_message_count
266
+ object_message_count = len(movies)
258
267
  dataset_has_quality_data = self.dataset_has_quality_data
259
268
  if dataset_has_quality_data:
260
269
  messages += self.object_messages(paths=quality_data, object_type="QDATA")
261
270
  with self.telemetry_span(
262
- f"Publish messages: {frame_message_count = }, {object_message_count = }, {dataset_has_quality_data = }"
271
+ f"Publish messages: {frame_message_count = }, {extra_message_count = }, {object_message_count = }, {dataset_has_quality_data = }"
263
272
  ):
264
273
  self.interservice_bus_publish(messages=messages)
@@ -22,19 +22,23 @@ class OutputDataBase(WorkflowTaskBase, ABC):
22
22
  """Get the destination bucket."""
23
23
  return self.metadata_store_recipe_run.configuration.destination_bucket
24
24
 
25
- def format_object_key(self, path: Path) -> str:
25
+ def format_object_key(self, path: Path, folder_modifier: str | None = None) -> str:
26
26
  """
27
27
  Convert output paths into object store keys.
28
28
 
29
29
  Parameters
30
30
  ----------
31
31
  path: the Path to convert
32
+ folder_modifier: optional folder name to insert into the path
32
33
 
33
34
  Returns
34
35
  -------
35
36
  formatted path in the object store
36
37
  """
37
- object_key = self.destination_folder / Path(path.name)
38
+ if folder_modifier:
39
+ object_key = self.destination_folder / Path(folder_modifier) / Path(path.name)
40
+ else:
41
+ object_key = self.destination_folder / Path(path.name)
38
42
  return str(object_key)
39
43
 
40
44
  @property
@@ -52,6 +56,11 @@ class OutputDataBase(WorkflowTaskBase, ABC):
52
56
  """Tags that uniquely identify L1 fits frames i.e. the dataset-inventory-able frames."""
53
57
  return [Tag.output(), Tag.frame()]
54
58
 
59
+ @property
60
+ def extra_frame_tags(self) -> list[str]:
61
+ """Tags that uniquely identify dataset extra fits frames."""
62
+ return [Tag.output(), Tag.extra()]
63
+
55
64
 
56
65
  class TransferDataBase(OutputDataBase, ObjectStoreMixin, ABC):
57
66
  """Base class for transferring data from scratch to somewhere else."""
@@ -73,9 +82,21 @@ class TransferDataBase(OutputDataBase, ObjectStoreMixin, ABC):
73
82
  """Build a list of GlobusTransfer items corresponding to all OUTPUT (i.e., L1) frames."""
74
83
  science_frame_paths: list[Path] = list(self.read(tags=self.output_frame_tags))
75
84
 
85
+ return self.build_transfer_list(science_frame_paths)
86
+
87
+ def build_dataset_extra_transfer_list(self) -> list[GlobusTransferItem]:
88
+ """Build a list of GlobusTransfer items corresponding to all extra dataset files."""
89
+ extra_paths: list[Path] = list(self.read(tags=self.extra_frame_tags))
90
+
91
+ return self.build_transfer_list(paths=extra_paths, destination_folder_modifier="extra")
92
+
93
+ def build_transfer_list(
94
+ self, paths: list[Path], destination_folder_modifier: str | None = None
95
+ ) -> list[GlobusTransferItem]:
96
+ """Given a list of paths, build a list of GlobusTransfer items."""
76
97
  transfer_items = []
77
- for p in science_frame_paths:
78
- object_key = self.format_object_key(p)
98
+ for p in paths:
99
+ object_key = self.format_object_key(path=p, folder_modifier=destination_folder_modifier)
79
100
  destination_path = Path(self.destination_bucket, object_key)
80
101
  item = GlobusTransferItem(
81
102
  source_path=p,