dkist-processing-common 13.0.2__tar.gz → 14.0.0rc1__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 (147) hide show
  1. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/CHANGELOG.rst +0 -9
  2. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/PKG-INFO +2 -2
  3. dkist_processing_common-14.0.0rc1/changelog/323.misc.2.rst +2 -0
  4. dkist_processing_common-14.0.0rc1/changelog/323.misc.rst +2 -0
  5. dkist_processing_common-14.0.0rc1/changelog/323.removal.2.rst +1 -0
  6. dkist_processing_common-14.0.0rc1/changelog/323.removal.3.rst +1 -0
  7. dkist_processing_common-14.0.0rc1/changelog/323.removal.rst +2 -0
  8. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/fits.py +4 -3
  9. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/fits_access.py +32 -61
  10. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/l0_fits_access.py +12 -4
  11. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/l1_fits_access.py +12 -4
  12. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/quality.py +5 -2
  13. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/quality_metrics.py +16 -25
  14. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/write_l1.py +3 -6
  15. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/conftest.py +9 -8
  16. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_codecs.py +4 -10
  17. dkist_processing_common-14.0.0rc1/dkist_processing_common/tests/test_fits_access.py +246 -0
  18. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_parse_l0_input_data.py +2 -3
  19. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_stems.py +28 -12
  20. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_task_parsing.py +24 -21
  21. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common.egg-info/PKG-INFO +2 -2
  22. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common.egg-info/SOURCES.txt +5 -0
  23. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common.egg-info/requires.txt +1 -1
  24. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/pyproject.toml +1 -1
  25. dkist_processing_common-13.0.2/dkist_processing_common/tests/test_fits_access.py +0 -378
  26. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/.gitignore +0 -0
  27. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/.pre-commit-config.yaml +0 -0
  28. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/.readthedocs.yml +0 -0
  29. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/.snyk +0 -0
  30. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/README.rst +0 -0
  31. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/bitbucket-pipelines.yml +0 -0
  32. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/changelog/.gitempty +0 -0
  33. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/__init__.py +0 -0
  34. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/_util/__init__.py +0 -0
  35. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/_util/constants.py +0 -0
  36. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/_util/graphql.py +0 -0
  37. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/_util/scratch.py +0 -0
  38. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/_util/tags.py +0 -0
  39. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/__init__.py +0 -0
  40. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/array.py +0 -0
  41. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/asdf.py +0 -0
  42. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/basemodel.py +0 -0
  43. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/bytes.py +0 -0
  44. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/iobase.py +0 -0
  45. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/json.py +0 -0
  46. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/path.py +0 -0
  47. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/quality.py +0 -0
  48. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/codecs/str.py +0 -0
  49. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/config.py +0 -0
  50. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
  51. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/fonts/__init__.py +0 -0
  52. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/manual.py +0 -0
  53. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/__init__.py +0 -0
  54. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/constants.py +0 -0
  55. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/dkist_location.py +0 -0
  56. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/extras.py +0 -0
  57. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/flower_pot.py +0 -0
  58. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/fried_parameter.py +0 -0
  59. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/graphql.py +0 -0
  60. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/input_dataset.py +0 -0
  61. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/message.py +0 -0
  62. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/message_queue_binding.py +0 -0
  63. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/metric_code.py +0 -0
  64. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/parameters.py +0 -0
  65. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/quality.py +0 -0
  66. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/tags.py +0 -0
  67. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/task_name.py +0 -0
  68. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/telemetry.py +0 -0
  69. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/models/wavelength.py +0 -0
  70. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/__init__.py +0 -0
  71. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/average_bud.py +0 -0
  72. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/cs_step.py +0 -0
  73. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
  74. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
  75. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/id_bud.py +0 -0
  76. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/lookup_bud.py +0 -0
  77. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/near_bud.py +0 -0
  78. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/observing_program_id_bud.py +0 -0
  79. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
  80. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/retarder.py +0 -0
  81. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
  82. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/task.py +0 -0
  83. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/time.py +0 -0
  84. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/unique_bud.py +0 -0
  85. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/parsers/wavelength.py +0 -0
  86. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/__init__.py +0 -0
  87. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/assemble_movie.py +0 -0
  88. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/base.py +0 -0
  89. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/l1_output_data.py +0 -0
  90. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
  91. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/globus.py +0 -0
  92. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
  93. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
  94. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
  95. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
  96. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -0
  97. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/mixin/quality/_metrics.py +0 -0
  98. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/output_data_base.py +0 -0
  99. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/parse_l0_input_data.py +0 -0
  100. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/teardown.py +0 -0
  101. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/transfer_input_data.py +0 -0
  102. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/trial_catalog.py +0 -0
  103. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/trial_output_data.py +0 -0
  104. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/write_extra.py +0 -0
  105. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tasks/write_l1_base.py +0 -0
  106. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/__init__.py +0 -0
  107. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/mock_metadata_store.py +0 -0
  108. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
  109. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_assemble_quality.py +0 -0
  110. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_base.py +0 -0
  111. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_constants.py +0 -0
  112. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_construct_dataset_extras.py +0 -0
  113. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_cs_step.py +0 -0
  114. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_dkist_location.py +0 -0
  115. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_flower_pot.py +0 -0
  116. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_fried_parameter.py +0 -0
  117. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_input_dataset.py +0 -0
  118. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
  119. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
  120. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_manual_processing.py +0 -0
  121. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_output_data_base.py +0 -0
  122. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_parameters.py +0 -0
  123. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
  124. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_quality.py +0 -0
  125. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_quality_mixin.py +0 -0
  126. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_scratch.py +0 -0
  127. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
  128. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_tags.py +0 -0
  129. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_task_name.py +0 -0
  130. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_teardown.py +0 -0
  131. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
  132. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_transfer_l1_output_data.py +0 -0
  133. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_trial_catalog.py +0 -0
  134. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
  135. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_workflow_task_base.py +0 -0
  136. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common/tests/test_write_l1.py +0 -0
  137. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
  138. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/dkist_processing_common.egg-info/top_level.txt +0 -0
  139. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/Makefile +0 -0
  140. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/changelog.rst +0 -0
  141. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/conf.py +0 -0
  142. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/index.rst +0 -0
  143. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/landing_page.rst +0 -0
  144. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/make.bat +0 -0
  145. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/docs/requirements.txt +0 -0
  146. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/licenses/LICENSE.rst +0 -0
  147. {dkist_processing_common-13.0.2 → dkist_processing_common-14.0.0rc1}/setup.cfg +0 -0
@@ -1,12 +1,3 @@
1
- v13.0.2 (2026-04-08)
2
- ====================
3
-
4
- Misc
5
- ----
6
-
7
- - Upgrade `dkist-processing-core` to version 7.2.0 which includes an `apache-airflow` version upgrade to 3.2.0. (`#325 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/325>`__)
8
-
9
-
10
1
  v13.0.1 (2026-04-07)
11
2
  ====================
12
3
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-common
3
- Version: 13.0.2
3
+ Version: 14.0.0rc1
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
@@ -17,7 +17,7 @@ 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.24.0
19
19
  Requires-Dist: dkist-header-validator<6.0,>=5.3.0
20
- Requires-Dist: dkist-processing-core==7.2.0
20
+ Requires-Dist: dkist-processing-core==7.1.0
21
21
  Requires-Dist: dkist-processing-pac<4.0,>=3.1
22
22
  Requires-Dist: dkist-service-configuration<5.0,>=4.3.0
23
23
  Requires-Dist: dkist-spectral-lines<4.0,>=3.0.0
@@ -0,0 +1,2 @@
1
+ Simplify the reading of L0 files in the `QualityL0Metrics` task; we now read `FitsAccess` objects directly via the
2
+ `fits_access_decoder`.
@@ -0,0 +1,2 @@
1
+ `FitsAccessBase` no longer uses an HDU object for internal storage. It is now instantiated with a `header` and
2
+ (optionally) `data` directly.
@@ -0,0 +1 @@
1
+ Remove `.from_path` constructor from `FitsAccessBase`. This should be replaced with a call to the `fits_access_decoder`.
@@ -0,0 +1 @@
1
+ Remove the `.size` property from `FitsAccessBase`. This not always correct and no longer used anywhere.
@@ -0,0 +1,2 @@
1
+ Remove `.from_header` constructor from `FitsAccessBase`. This should be replaced by passing the header object directly
2
+ on instantiation.
@@ -144,14 +144,15 @@ def fits_access_decoder(
144
144
  disable_image_compression=disable_image_compression,
145
145
  memmap=memmap,
146
146
  )
147
- return fits_access_class(hdu=data_hdu, name=str(path), **fits_access_kwargs)
147
+ return fits_access_class(
148
+ header=data_hdu.header, data=data_hdu.data, name=str(path), **fits_access_kwargs
149
+ )
148
150
 
149
151
 
150
152
  def fits_access_header_decoder(
151
153
  path: Path,
152
154
  fits_access_class: Type[FitsAccessBase],
153
155
  hdu: int | None = None,
154
- **from_header_kwargs,
155
156
  ) -> FitsAccessBase:
156
157
  """
157
158
  Read a header from a Path with `~astropy.io.fits` and ingest into a `~dkist_processing_common.models.fits_access.FitsAccessBase`-type object.
@@ -163,7 +164,7 @@ def fits_access_header_decoder(
163
164
  path,
164
165
  hdu=hdu,
165
166
  )
166
- return fits_access_class.from_header(header=header, name=str(path), **from_header_kwargs)
167
+ return fits_access_class(header=header, name=str(path))
167
168
 
168
169
 
169
170
  def _extract_hdu(hdul: fits.HDUList, hdu: int | None = None) -> fits.PrimaryHDU | fits.CompImageHDU:
@@ -59,33 +59,46 @@ class FitsAccessBase:
59
59
  """
60
60
  Abstraction layer for accessing fits data via class attributes.
61
61
 
62
+ .. note::
63
+ The preferred method to load a FITS file into this class or its children is to use one of the `fits access codecs <dkist_processing_common.codecs.fits>`
64
+ in combination with `~dkist_processing_common.tasks.base.WorkflowTaskBase.read`. Direct instantiation should only
65
+ be used in unit tests or when `header` and `data` have been recently been generated an only live in memory.
66
+
62
67
  Parameters
63
68
  ----------
64
- hdu
65
- The fits object
69
+ header
70
+ The header from which to parse higher-level properties
71
+
72
+ data
73
+ A data array to associate with the current instance
74
+
66
75
  name
67
76
  An optional name that can be associated with the object
77
+
68
78
  auto_squeeze
69
79
  A boolean indicating whether to 'squeeze' out dimensions of size 1
70
80
  """
71
81
 
72
82
  def __init__(
73
83
  self,
74
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU | fits.BinTableHDU,
84
+ *,
85
+ header: fits.Header,
86
+ data: np.ndarray | None = None,
75
87
  name: str | Path | None = None,
76
88
  auto_squeeze: bool = True,
77
89
  ):
78
- self._hdu = hdu
90
+ self.header = header
91
+ self._data = data
79
92
  self.name = name
80
93
  self.auto_squeeze = auto_squeeze
81
94
 
82
95
  def __repr__(self):
83
- return f"{self.__class__.__name__}(hdu={self._hdu!r}, name={self.name!r}, auto_squeeze={self.auto_squeeze})"
96
+ return f"{self.__class__.__name__}(header={self.header!r}, data={self._data!r}, name={self.name!r}, auto_squeeze={self.auto_squeeze})"
84
97
 
85
98
  @property
86
- def data(self) -> np.ndarray:
99
+ def data(self) -> np.ndarray | None:
87
100
  """
88
- Return the data array from the associated FITS object, with axes of length 1 removed if the array has three dimensions and the unit axis is the zeroth one.
101
+ Return the data array, with axes of length 1 removed if the array has three dimensions and the unit axis is the zeroth one.
89
102
 
90
103
  This is intended solely to remove the dummy dimension that is in raw data from the summit.
91
104
 
@@ -95,17 +108,25 @@ class FitsAccessBase:
95
108
  -------
96
109
  data array
97
110
  """
111
+ if not self.auto_squeeze or self._data is None:
112
+ return self._data
113
+
98
114
  # This conditional is explicitly to catch summit data with a dummy first axis for WCS
99
115
  # purposes
100
- if self.auto_squeeze and len(self._hdu.data.shape) == 3 and self._hdu.data.shape[0] == 1:
101
- return np.squeeze(self._hdu.data)
102
- return self._hdu.data
116
+ if len(self._data.shape) == 3 and self._data.shape[0] == 1:
117
+ return np.squeeze(self._data)
118
+
119
+ return self._data
103
120
 
104
121
  @data.setter
105
122
  def data(self, array: np.ndarray) -> None:
106
123
  """
107
124
  Set the data array using an input data array.
108
125
 
126
+ Note that this method does not update any keys in this object's `.header` (NAXIS, BITPIX, etc.). If the data and
127
+ header of this object are to be written to disk, make sure to use the `~astropy.io.fits` interface, which will
128
+ correctly update the header on write.
129
+
109
130
  Parameters
110
131
  ----------
111
132
  array
@@ -115,14 +136,7 @@ class FitsAccessBase:
115
136
  -------
116
137
  None
117
138
  """
118
- # There is no shape magic stuff going on here right now because the tasks/services that care about
119
- # it will deal with it themselves (I think (tm)).
120
- self._hdu.data = array
121
-
122
- @property
123
- def header(self) -> fits.Header:
124
- """Return the header for this fits object."""
125
- return self._hdu.header
139
+ self._data = array
126
140
 
127
141
  @property
128
142
  def header_dict(self) -> dict:
@@ -134,46 +148,3 @@ class FitsAccessBase:
134
148
  else:
135
149
  result[card] = value
136
150
  return result
137
-
138
- @property
139
- def size(self) -> float:
140
- """Return the size in bytes of the data portion of this fits object."""
141
- return self._hdu.size
142
-
143
- @classmethod
144
- def from_header(cls, header: fits.Header | dict, name: str | None = None) -> FitsAccessBase:
145
- """
146
- Convert a header to a FitsAccessBase (or child) object.
147
-
148
- Parameters
149
- ----------
150
- header
151
- A single `astropy.io.fits.header.Header` HDU object.
152
- name
153
- A unique name for the fits access instance
154
- """
155
- if isinstance(header, dict):
156
- header = fits.Header(header)
157
- hdu = fits.PrimaryHDU()
158
-
159
- # We need to update the header after `PrimaryHDU` instantiation because some of the FITS controlled keys
160
- # (e.g., NAXIS, NAXISn) would otherwise be changed by checks that occur during instantiation.
161
- hdu.header.update(header)
162
- return cls(hdu=hdu, name=name)
163
-
164
- @classmethod
165
- def from_path(cls, path: str | Path) -> FitsAccessBase:
166
- """
167
- Load the file at given path into a FitsAccess object.
168
-
169
- Parameters
170
- ----------
171
- path
172
- Location of fits file on disk
173
- """
174
- hdul = fits.open(path)
175
- if hdul[0].data is not None:
176
- hdu = hdul[0]
177
- else:
178
- hdu = hdul[1]
179
- return cls(hdu=hdu, name=path)
@@ -1,5 +1,6 @@
1
1
  """By-frame 214 L0 header keywords that are not instrument specific."""
2
2
 
3
+ import numpy as np
3
4
  from astropy.io import fits
4
5
 
5
6
  from dkist_processing_common.models.fits_access import MetadataKey
@@ -33,10 +34,15 @@ class L0FitsAccess(L1FitsAccess):
33
34
 
34
35
  Parameters
35
36
  ----------
36
- hdu
37
- The input fits hdu
37
+ header
38
+ The header from which to parse higher-level properties
39
+
40
+ data
41
+ A data array to associate with the current instance
42
+
38
43
  name
39
44
  An optional name to be associated with the hdu
45
+
40
46
  auto_squeeze
41
47
  A boolean indicating whether to 'squeeze' out dimensions of size 1
42
48
  """
@@ -45,11 +51,13 @@ class L0FitsAccess(L1FitsAccess):
45
51
 
46
52
  def __init__(
47
53
  self,
48
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU,
54
+ *,
55
+ header: fits.Header,
56
+ data: np.ndarray | None = None,
49
57
  name: str | None = None,
50
58
  auto_squeeze: bool = True,
51
59
  ):
52
- super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
60
+ super().__init__(header=header, data=data, name=name, auto_squeeze=auto_squeeze)
53
61
  self.ip_task_type: str = self.header[MetadataKey.ip_task_type]
54
62
  self.ip_start_time: str = self.header[MetadataKey.ip_start_time]
55
63
  self.ip_end_time: str = self.header[MetadataKey.ip_end_time]
@@ -1,5 +1,6 @@
1
1
  """By-frame 214 L1 only header keywords that are not instrument specific."""
2
2
 
3
+ import numpy as np
3
4
  from astropy.io import fits
4
5
 
5
6
  from dkist_processing_common.models.fits_access import HEADER_KEY_NOT_FOUND
@@ -15,21 +16,28 @@ class L1FitsAccess(FitsAccessBase):
15
16
 
16
17
  Parameters
17
18
  ----------
18
- hdu
19
- The input fits hdu
19
+ header
20
+ The header from which to parse higher-level properties
21
+
22
+ data
23
+ A data array to associate with the current instance
24
+
20
25
  name
21
26
  An optional name to be associated with the hdu
27
+
22
28
  auto_squeeze
23
29
  A boolean indicating whether to 'squeeze' out dimensions of size 1
24
30
  """
25
31
 
26
32
  def __init__(
27
33
  self,
28
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU,
34
+ *,
35
+ header: fits.Header,
36
+ data: np.ndarray | None = None,
29
37
  name: str | None = None,
30
38
  auto_squeeze: bool = False, # Because L1 data should always have the right form, right?
31
39
  ):
32
- super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
40
+ super().__init__(header=header, data=data, name=name, auto_squeeze=auto_squeeze)
33
41
 
34
42
  self.elevation: float = self.header[MetadataKey.elevation]
35
43
  self.azimuth: float = self.header[MetadataKey.azimuth]
@@ -1,5 +1,6 @@
1
1
  """Support classes to define object attributes from header information."""
2
2
 
3
+ import numpy as np
3
4
  from astropy.io import fits
4
5
 
5
6
  from dkist_processing_common.parsers.l0_fits_access import L1FitsAccess
@@ -21,11 +22,13 @@ class L1QualityFitsAccess(L1FitsAccess):
21
22
 
22
23
  def __init__(
23
24
  self,
24
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU,
25
+ *,
26
+ header: fits.Header,
27
+ data: np.ndarray | None = None,
25
28
  name: str | None = None,
26
29
  auto_squeeze: bool = True,
27
30
  ):
28
- super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
31
+ super().__init__(header=header, data=data, name=name, auto_squeeze=auto_squeeze)
29
32
 
30
33
  self.fried_parameter: float = self.header["ATMOS_R0"]
31
34
  self.date_begin: str = self.header["DATE-BEG"]
@@ -5,9 +5,7 @@ from collections import defaultdict
5
5
  from datetime import datetime
6
6
  from inspect import signature
7
7
  from itertools import chain
8
- from pathlib import Path
9
8
  from typing import Callable
10
- from typing import Generator
11
9
  from typing import Iterable
12
10
  from typing import Type
13
11
 
@@ -15,6 +13,7 @@ import numpy as np
15
13
  from pydantic import FiniteFloat
16
14
 
17
15
  from dkist_processing_common.codecs.basemodel import basemodel_encoder
16
+ from dkist_processing_common.codecs.fits import fits_access_decoder
18
17
  from dkist_processing_common.models.fits_access import FitsAccessBase
19
18
  from dkist_processing_common.models.metric_code import MetricCode
20
19
  from dkist_processing_common.models.quality import QualityMetric
@@ -128,21 +127,6 @@ class QualityL0Metrics(WorkflowTaskBase, QualityMixin):
128
127
  with self.telemetry_span("Writing L0 Quality Metrics to disk"):
129
128
  self.compute_and_write_l0_quality_metrics(segmented_quality_data)
130
129
 
131
- # TODO FUTURE - this method should ultimately go away
132
- def get_paths_for_modstate_and_task(
133
- self, modstate: int | None, task_type: str
134
- ) -> Generator[Path, None, None]:
135
- """
136
- Return Paths for all raw files that tagged with the given modstate and task type.
137
-
138
- The tag that defines "raw" can be changed in the `raw_frame_tag` property.
139
- """
140
- tags = [self.raw_frame_tag, Tag.task(task_type)]
141
- if modstate is not None:
142
- tags.append(Tag.modstate(modstate))
143
-
144
- return self.read(tags)
145
-
146
130
  def collect_l0_quality_data(self) -> dict[str, dict[str, L0QualityData]]:
147
131
  """Calculate L0 quality metrics for each task type and modstate combo."""
148
132
  intermediate_l0_quality_data_segmented_first_by_ip_task_and_then_by_modstate: dict[
@@ -152,25 +136,29 @@ class QualityL0Metrics(WorkflowTaskBase, QualityMixin):
152
136
  for task_type in self.quality_task_types:
153
137
  with self.telemetry_span(f"Collecting {task_type = }"):
154
138
  for modstate in modstate_list:
155
- # TODO FUTURE - this should do something like this: self.read(decoder=l0_fits_access_decoder)
156
- paths = self.get_paths_for_modstate_and_task(modstate, task_type)
139
+ tags = [self.raw_frame_tag, Tag.task(task_type)]
140
+ if modstate is not None:
141
+ tags.append(Tag.modstate(modstate))
142
+
143
+ fits_objs = self.read(
144
+ tags=tags, decoder=fits_access_decoder, fits_access_class=L0FitsAccess
145
+ )
157
146
 
158
147
  # establish empty lists for this task type AND modstate
159
148
  datetimes = []
160
149
  average_values = []
161
150
  rms_values = []
162
151
 
163
- for path in paths:
164
- frame = L0FitsAccess.from_path(path)
165
- data = frame.data.astype(float)
166
- exposure_time_sec = frame.fpa_exposure_time_ms / 1000
152
+ for fo in fits_objs:
153
+ data = fo.data.astype(float)
154
+ exposure_time_sec = fo.fpa_exposure_time_ms / 1000
167
155
 
168
156
  # Mean and RMS for Frame
169
157
  normalized_mean = self.compute_normalized_mean(data, exposure_time_sec)
170
158
  normalized_rms = self.compute_normalized_rms(data, exposure_time_sec)
171
159
 
172
160
  # accumulate each value into its list
173
- datetimes.append(datetime.fromisoformat(frame.time_obs))
161
+ datetimes.append(datetime.fromisoformat(fo.time_obs))
174
162
  average_values.append(normalized_mean)
175
163
  rms_values.append(normalized_rms)
176
164
 
@@ -488,13 +476,16 @@ class QualityL1Metrics(WorkflowTaskBase, QualityMixin):
488
476
  ]
489
477
 
490
478
  with self.telemetry_span("Reading L1 frames"):
479
+ # Read in paths and convert to `FitsAccess` objects below because we iterate throught `paths` multiple times
491
480
  paths = list(self.read(tags=[Tag.calibrated(), Tag.frame()]))
492
481
 
493
482
  with self.telemetry_span("Calculating L1 quality metrics"):
494
483
  for metric in metrics:
495
484
  with self.telemetry_span(f"Calculating L1 metric {metric.value_source}"):
496
485
  for path in paths:
497
- frame = L1QualityFitsAccess.from_path(path)
486
+ frame = fits_access_decoder(
487
+ path=path, fits_access_class=L1QualityFitsAccess
488
+ )
498
489
  metric.append_value(frame=frame)
499
490
 
500
491
  with self.telemetry_span("Sending lists for storage"):
@@ -67,7 +67,6 @@ class WriteL1Frame(WriteL1Base, ABC):
67
67
  l1_header = self.convert_l0_to_l1(
68
68
  header=calibrated_fits_object.header,
69
69
  data=calibrated_fits_object.data,
70
- hdu_size=calibrated_fits_object.size,
71
70
  stokes_param=stokes_param,
72
71
  )
73
72
 
@@ -160,7 +159,6 @@ class WriteL1Frame(WriteL1Base, ABC):
160
159
  def add_datacenter_headers(
161
160
  self,
162
161
  header: fits.Header,
163
- hdu_size: float,
164
162
  stokes: Literal["I", "Q", "U", "V"],
165
163
  ) -> fits.Header:
166
164
  """Fill out the spec 214 datacenter header table."""
@@ -301,7 +299,6 @@ class WriteL1Frame(WriteL1Base, ABC):
301
299
  self,
302
300
  header: fits.Header,
303
301
  data: np.ndarray,
304
- hdu_size: float,
305
302
  stokes_param: Literal["I", "Q", "U", "V"],
306
303
  ) -> fits.Header:
307
304
  """
@@ -311,10 +308,10 @@ class WriteL1Frame(WriteL1Base, ABC):
311
308
  ----------
312
309
  header
313
310
  The L0 header
311
+
314
312
  data
315
313
  The data array
316
- hdu_size
317
- The hdu size
314
+
318
315
  stokes_param
319
316
  The stokes parameter
320
317
 
@@ -335,7 +332,7 @@ class WriteL1Frame(WriteL1Base, ABC):
335
332
  # Add the stats table
336
333
  header = self.add_stats_headers(header=header, data=data)
337
334
  # Add the datacenter table
338
- header = self.add_datacenter_headers(header=header, hdu_size=hdu_size, stokes=stokes_param)
335
+ header = self.add_datacenter_headers(header=header, stokes=stokes_param)
339
336
  # Add extra headers recommended by solarnet (not all in a single table)
340
337
  header = self.add_solarnet_headers(header=header)
341
338
  # Add the documentation headers
@@ -297,11 +297,12 @@ class NonPolCalDataset(Spec122Dataset):
297
297
  class ModstateFitsAccess(L0FitsAccess):
298
298
  def __init__(
299
299
  self,
300
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU,
300
+ *,
301
+ header: fits.Header,
301
302
  name: str | None = None,
302
303
  auto_squeeze: bool = True,
303
304
  ):
304
- super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
305
+ super().__init__(header=header, name=name, auto_squeeze=auto_squeeze)
305
306
  self.modulator_state: int = self.header["VSPSTNUM"]
306
307
 
307
308
 
@@ -348,7 +349,7 @@ def grouped_cal_sequence_fits_objs(
348
349
  for i in range(ds.num_steps):
349
350
  for m in range(ds.num_modstates):
350
351
  for j in range(ds.num_frames_per_CS_step):
351
- expected_cs_dict[i].append(ModstateFitsAccess.from_header(header_list.pop(0)))
352
+ expected_cs_dict[i].append(ModstateFitsAccess(header=header_list.pop(0)))
352
353
 
353
354
  # Make sure we used all the dataset frames
354
355
  assert len(header_list) == 0
@@ -376,7 +377,7 @@ def grouped_cal_sequence_modstate_fits_objs(
376
377
  for i in range(ds.num_steps):
377
378
  for m in range(ds.num_modstates):
378
379
  for j in range(ds.num_frames_per_CS_step):
379
- expected_cs_dict[i][m].append(ModstateFitsAccess.from_header(header_list.pop(0)))
380
+ expected_cs_dict[i][m].append(ModstateFitsAccess(header=header_list.pop(0)))
380
381
 
381
382
  # Make sure we used all the dataset frames
382
383
  assert len(header_list) == 0
@@ -392,7 +393,7 @@ def non_polcal_fits_objs() -> list[L0FitsAccess]:
392
393
  ].header
393
394
  for d in ds
394
395
  ]
395
- obj_list = [L0FitsAccess.from_header(h) for h in header_list]
396
+ obj_list = [L0FitsAccess(header=h) for h in header_list]
396
397
  return obj_list
397
398
 
398
399
 
@@ -485,8 +486,8 @@ class CalibrationSequenceStepDataset(Spec122Dataset):
485
486
 
486
487
 
487
488
  class InstAccess(L0FitsAccess):
488
- def __init__(self, hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU):
489
- super().__init__(hdu, auto_squeeze=False)
489
+ def __init__(self, *, header: fits.Header, data: np.ndarray | None = None):
490
+ super().__init__(header=header, data=data, auto_squeeze=False)
490
491
  self.modulator_state = self.header["VSPSTNUM"]
491
492
  self.number_of_modulator_states = self.header["VSPNUMST"]
492
493
 
@@ -577,7 +578,7 @@ def cs_with_correct_geometry(cs_data_shape):
577
578
  )
578
579
  )
579
580
 
580
- out_dict[n] = [InstAccess(h) for h in hdu_list]
581
+ out_dict[n] = [InstAccess(header=h.header, data=h.data) for h in hdu_list]
581
582
  start_time = ds.start_time + timedelta(seconds=60)
582
583
 
583
584
  return out_dict
@@ -382,11 +382,13 @@ def check_open_file_descriptors() -> int | None:
382
382
  class DummyFitsAccess(FitsAccessBase):
383
383
  def __init__(
384
384
  self,
385
- hdu: fits.ImageHDU | fits.PrimaryHDU | fits.CompImageHDU,
385
+ *,
386
+ header: fits.Header,
387
+ data: np.ndarray | None = None,
386
388
  name: str | None = None,
387
389
  auto_squeeze: bool = False,
388
390
  ):
389
- super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
391
+ super().__init__(header=header, data=data, name=name, auto_squeeze=auto_squeeze)
390
392
  self.foo = self.header["foo"]
391
393
 
392
394
 
@@ -636,14 +638,6 @@ def test_fits_access_decoder(
636
638
  assert post_num_fd <= init_num_fd + 1 if memmap and not decompress else init_num_fd
637
639
  assert fits_obj.name == str(file_path)
638
640
  assert fits_obj.foo == fits_header["foo"]
639
- if "compressed" in path_fixture_name:
640
- if decompress:
641
- assert isinstance(fits_obj._hdu, fits.CompImageHDU)
642
- else:
643
- assert isinstance(fits_obj._hdu, fits.BinTableHDU)
644
- else:
645
- assert isinstance(fits_obj._hdu, fits.PrimaryHDU)
646
-
647
641
  if "compressed" in path_fixture_name and not decompress:
648
642
  assert not np.array_equal(fits_obj.data, ndarray_object)
649
643
  else: