dkist-processing-common 13.0.5rc2__tar.gz → 13.0.6__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 (142) hide show
  1. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/CHANGELOG.rst +21 -0
  2. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/PKG-INFO +2 -2
  3. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/_util/graphql.py +8 -9
  4. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/_util/scratch.py +23 -21
  5. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/_util/tags.py +2 -2
  6. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/graphql.py +4 -4
  7. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/input_dataset.py +2 -2
  8. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/base.py +5 -9
  9. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_scratch.py +34 -16
  10. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_workflow_task_base.py +28 -2
  11. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common.egg-info/PKG-INFO +2 -2
  12. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common.egg-info/SOURCES.txt +0 -1
  13. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common.egg-info/requires.txt +1 -1
  14. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/pyproject.toml +1 -1
  15. dkist_processing_common-13.0.5rc2/changelog/329.feature.rst +0 -1
  16. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/.gitignore +0 -0
  17. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/.pre-commit-config.yaml +0 -0
  18. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/.readthedocs.yml +0 -0
  19. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/.snyk +0 -0
  20. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/README.rst +0 -0
  21. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/bitbucket-pipelines.yml +0 -0
  22. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/changelog/.gitempty +0 -0
  23. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/__init__.py +0 -0
  24. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/_util/__init__.py +0 -0
  25. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/_util/constants.py +0 -0
  26. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/__init__.py +0 -0
  27. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/array.py +0 -0
  28. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/asdf.py +0 -0
  29. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/basemodel.py +0 -0
  30. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/bytes.py +0 -0
  31. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/fits.py +0 -0
  32. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/iobase.py +0 -0
  33. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/json.py +0 -0
  34. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/path.py +0 -0
  35. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/quality.py +0 -0
  36. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/codecs/str.py +0 -0
  37. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/config.py +0 -0
  38. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
  39. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/fonts/__init__.py +0 -0
  40. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/manual.py +0 -0
  41. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/__init__.py +0 -0
  42. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/constants.py +0 -0
  43. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/dkist_location.py +0 -0
  44. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/extras.py +0 -0
  45. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/fits_access.py +0 -0
  46. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/flower_pot.py +0 -0
  47. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/fried_parameter.py +0 -0
  48. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/message.py +0 -0
  49. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/message_queue_binding.py +0 -0
  50. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/metric_code.py +0 -0
  51. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/parameters.py +0 -0
  52. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/quality.py +0 -0
  53. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/tags.py +0 -0
  54. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/task_name.py +0 -0
  55. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/telemetry.py +0 -0
  56. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/models/wavelength.py +0 -0
  57. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/__init__.py +0 -0
  58. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/average_bud.py +0 -0
  59. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/cs_step.py +0 -0
  60. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
  61. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
  62. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/id_bud.py +0 -0
  63. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/l0_fits_access.py +0 -0
  64. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/l1_fits_access.py +0 -0
  65. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/lookup_bud.py +0 -0
  66. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/near_bud.py +0 -0
  67. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/observing_program_id_bud.py +0 -0
  68. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
  69. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/quality.py +0 -0
  70. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/retarder.py +0 -0
  71. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
  72. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/task.py +0 -0
  73. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/time.py +0 -0
  74. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/unique_bud.py +0 -0
  75. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/parsers/wavelength.py +0 -0
  76. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/__init__.py +0 -0
  77. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/assemble_movie.py +0 -0
  78. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/l1_output_data.py +0 -0
  79. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
  80. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/globus.py +0 -0
  81. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
  82. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
  83. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
  84. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
  85. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -0
  86. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/mixin/quality/_metrics.py +0 -0
  87. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/output_data_base.py +0 -0
  88. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/parse_l0_input_data.py +0 -0
  89. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/quality_metrics.py +0 -0
  90. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/teardown.py +0 -0
  91. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/transfer_input_data.py +0 -0
  92. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/trial_catalog.py +0 -0
  93. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/trial_output_data.py +0 -0
  94. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/write_extra.py +0 -0
  95. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/write_l1.py +0 -0
  96. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tasks/write_l1_base.py +0 -0
  97. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/__init__.py +0 -0
  98. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/conftest.py +0 -0
  99. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/mock_metadata_store.py +0 -0
  100. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
  101. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_assemble_quality.py +0 -0
  102. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_base.py +0 -0
  103. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_codecs.py +0 -0
  104. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_constants.py +0 -0
  105. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_construct_dataset_extras.py +0 -0
  106. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_cs_step.py +0 -0
  107. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_dkist_location.py +0 -0
  108. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_fits_access.py +0 -0
  109. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_flower_pot.py +0 -0
  110. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_fried_parameter.py +0 -0
  111. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_input_dataset.py +0 -0
  112. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
  113. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
  114. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_manual_processing.py +0 -0
  115. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_output_data_base.py +0 -0
  116. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_parameters.py +0 -0
  117. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_parse_l0_input_data.py +0 -0
  118. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
  119. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_quality.py +0 -0
  120. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_quality_mixin.py +0 -0
  121. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_stems.py +0 -0
  122. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
  123. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_tags.py +0 -0
  124. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_task_name.py +0 -0
  125. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_task_parsing.py +0 -0
  126. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_teardown.py +0 -0
  127. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
  128. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_transfer_l1_output_data.py +0 -0
  129. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_trial_catalog.py +0 -0
  130. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
  131. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common/tests/test_write_l1.py +0 -0
  132. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
  133. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/dkist_processing_common.egg-info/top_level.txt +0 -0
  134. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/Makefile +0 -0
  135. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/changelog.rst +0 -0
  136. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/conf.py +0 -0
  137. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/index.rst +0 -0
  138. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/landing_page.rst +0 -0
  139. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/make.bat +0 -0
  140. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/docs/requirements.txt +0 -0
  141. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/licenses/LICENSE.rst +0 -0
  142. {dkist_processing_common-13.0.5rc2 → dkist_processing_common-13.0.6}/setup.cfg +0 -0
@@ -1,3 +1,24 @@
1
+ v13.0.6 (2026-04-21)
2
+ ====================
3
+
4
+ Misc
5
+ ----
6
+
7
+ - Implement updated gqlclient v2.0.0, which uses Pydantic v2 BaseModels to
8
+ validate graphql parameters and responses. (`#283 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/283>`__)
9
+ - Raise an informative error if attempting to read or write files in tasks with tags=None. Tags are now a required
10
+ argument for writing with the WorkflowFileSystem. Read and write with an empty list for tags is still supported. (`#327 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/327>`__)
11
+
12
+
13
+ v13.0.5 (2026-04-20)
14
+ ====================
15
+
16
+ Features
17
+ --------
18
+
19
+ - Remove 4 unused quality metric codes: RANGE, NOISE, SENSITIVITY, HISTORICAL. (`#329 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/329>`__)
20
+
21
+
1
22
  v13.0.4 (2026-04-16)
2
23
  ====================
3
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-common
3
- Version: 13.0.5rc2
3
+ Version: 13.0.6
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
@@ -23,7 +23,7 @@ Requires-Dist: dkist-service-configuration<5.0,>=4.3.0
23
23
  Requires-Dist: dkist-spectral-lines<4.0,>=3.0.0
24
24
  Requires-Dist: solar-wavelength-calibration<3.0,>=2.0.0
25
25
  Requires-Dist: globus-sdk<5.0.0,>=4.0.0
26
- Requires-Dist: gqlclient[pydantic]==1.2.3
26
+ Requires-Dist: gqlclient==2.0.0
27
27
  Requires-Dist: sqids==0.5.1
28
28
  Requires-Dist: matplotlib>=3.4
29
29
  Requires-Dist: moviepy>=2.0.0
@@ -5,9 +5,9 @@ from typing import Any
5
5
  from typing import Callable
6
6
 
7
7
  import requests
8
- from gqlclient.base import DefaultParameters
9
8
  from gqlclient.base import GraphQLClientBase
10
9
  from gqlclient.request_wrap import wrap_request
10
+ from pydantic import BaseModel
11
11
  from requests.adapters import HTTPAdapter
12
12
  from requests.packages.urllib3.util.retry import Retry
13
13
 
@@ -59,14 +59,13 @@ class GraphQLClient(GraphQLClientBase):
59
59
  def execute_gql_query(
60
60
  self,
61
61
  query_base: str,
62
- query_response_cls: type,
63
- query_parameters: object | None = DefaultParameters,
64
- response_encoder: Callable[[str, list[dict] | dict, type], Any] | None = None,
62
+ query_response_cls: type[BaseModel],
63
+ query_parameters: BaseModel | None = None,
64
+ response_encoder: Callable[[str, dict | list[dict], type[BaseModel]], Any] | None = None,
65
65
  **kwargs,
66
66
  ) -> Any:
67
67
  """Execute gql query with parameters dynamically wrapped."""
68
- if query_parameters is not None and query_parameters is not DefaultParameters:
69
- query_parameters = wrap_request(query_parameters)
68
+ query_parameters = wrap_request(query_parameters)
70
69
  return super().execute_gql_query(
71
70
  query_base=query_base,
72
71
  query_response_cls=query_response_cls,
@@ -78,9 +77,9 @@ class GraphQLClient(GraphQLClientBase):
78
77
  def execute_gql_mutation(
79
78
  self,
80
79
  mutation_base: str,
81
- mutation_parameters: object,
82
- mutation_response_cls: type | None = None,
83
- response_encoder: Callable[[str, list[dict] | dict, type], Any] | None = None,
80
+ mutation_parameters: BaseModel,
81
+ mutation_response_cls: type[BaseModel],
82
+ response_encoder: Callable[[str, dict | list[dict], type[BaseModel]], Any] | None = None,
84
83
  **kwargs,
85
84
  ) -> Any:
86
85
  """Execute gql mutation with parameters dynamically wrapped."""
@@ -5,7 +5,9 @@ from contextlib import contextmanager
5
5
  from os import umask
6
6
  from pathlib import Path
7
7
  from shutil import rmtree
8
+ from typing import Any
8
9
  from typing import Generator
10
+ from typing import Iterable
9
11
 
10
12
  from dkist_processing_common._util.tags import TagDB
11
13
  from dkist_processing_common.config import common_configurations
@@ -82,19 +84,19 @@ class WorkflowFileSystem:
82
84
  return self.workflow_base_path / relative_path
83
85
 
84
86
  @staticmethod
85
- def parse_tags(tags: str | list | None) -> list:
86
- """Parse tags to support an individual tag in the form of a string or an arbitrarily nested list of strings."""
87
- if tags is None:
88
- return []
89
- if isinstance(tags, str):
90
- return [tags]
91
- return _flatten_list(tags)
87
+ def parse_tags(tags: str | Iterable[str]) -> list:
88
+ """Parse tags to support an individual tag in the form of a string or an arbitrarily nested iterable of strings."""
89
+ if isinstance(tags, Iterable):
90
+ if isinstance(tags, str):
91
+ return [tags]
92
+ return _flatten_tags(tags)
93
+ raise TypeError(f"'tags' must be str or other iterator. Received {tags=}")
92
94
 
93
95
  def write(
94
96
  self,
95
97
  file_obj: bytes,
96
98
  relative_path: Path | str,
97
- tags: str | list | None = None,
99
+ tags: str | Iterable[str],
98
100
  overwrite: bool = False,
99
101
  ) -> None:
100
102
  """
@@ -146,7 +148,7 @@ class WorkflowFileSystem:
146
148
  path.unlink(missing_ok=True)
147
149
  self._tag_db.clear_value(value=path)
148
150
 
149
- def tag(self, path: Path | str, tags: list | str) -> None:
151
+ def tag(self, path: Path | str, tags: str | Iterable[str]) -> None:
150
152
  """
151
153
  Tag existing paths.
152
154
 
@@ -184,7 +186,7 @@ class WorkflowFileSystem:
184
186
  self._audit_new_tag_cache[tag] = tag_is_new
185
187
  return self._audit_new_tag_cache[tag]
186
188
 
187
- def tags(self, path: Path | str):
189
+ def tags(self, path: Path | str) -> list[str]:
188
190
  """
189
191
  Return the tags associated with the given file object.
190
192
 
@@ -199,13 +201,13 @@ class WorkflowFileSystem:
199
201
  value = str(path)
200
202
  return self._tag_db.tags_for_value(value=value)
201
203
 
202
- def remove_tags(self, path: Path | str, tags: list | str) -> None:
204
+ def remove_tags(self, path: Path | str, tags: str | Iterable[str]) -> None:
203
205
  """Remove a tag or tags from a given path."""
204
206
  tags = self.parse_tags(tags)
205
207
  for tag in tags:
206
208
  self._tag_db.remove(tag, str(path))
207
209
 
208
- def find_any(self, tags: str | list) -> Generator[Path, None, None]:
210
+ def find_any(self, tags: str | Iterable[str]) -> Generator[Path, None, None]:
209
211
  """
210
212
  Return a generator of Path objects that are tagged by the union of the input tags.
211
213
 
@@ -224,7 +226,7 @@ class WorkflowFileSystem:
224
226
  for path in paths:
225
227
  yield Path(path)
226
228
 
227
- def find_all(self, tags: str | list) -> Generator[Path, None, None]:
229
+ def find_all(self, tags: str | Iterable[str]) -> Generator[Path, None, None]:
228
230
  """
229
231
  Return a generator of Path objects that are tagged by the intersection of the input tags.
230
232
 
@@ -243,7 +245,7 @@ class WorkflowFileSystem:
243
245
  for path in paths:
244
246
  yield Path(path)
245
247
 
246
- def count_any(self, tags: str | list) -> int:
248
+ def count_any(self, tags: str | Iterable[str]) -> int:
247
249
  """
248
250
  Return the number of objects that are tagged by the union of the input tags.
249
251
 
@@ -259,7 +261,7 @@ class WorkflowFileSystem:
259
261
  tags = self.parse_tags(tags)
260
262
  return len(self._tag_db.any(tags))
261
263
 
262
- def count_all(self, tags: str | list) -> int:
264
+ def count_all(self, tags: str | Iterable[str]) -> int:
263
265
  """
264
266
  Return the number of objects that are tagged by the intersection of the input tags.
265
267
 
@@ -326,12 +328,12 @@ class WorkflowFileSystem:
326
328
  self.close()
327
329
 
328
330
 
329
- def _flatten_list(elements: list) -> list:
330
- """Flatten an arbitrarily nested list."""
331
+ def _flatten_tags(tags: Iterable[Any]) -> list[str]:
332
+ """Flatten an arbitrarily nested iterable into a flat list of strings."""
331
333
  result = []
332
- for element in elements:
333
- if isinstance(element, list):
334
- result.extend(_flatten_list(element))
334
+ for tag in tags:
335
+ if isinstance(tag, str):
336
+ result.append(tag)
335
337
  else:
336
- result.append(element)
338
+ result.extend(_flatten_tags(tag))
337
339
  return result
@@ -52,7 +52,7 @@ class TagDB:
52
52
  def _format_query_result(result: list[bytes]) -> set[str]:
53
53
  return {r.decode("utf8") for r in result}
54
54
 
55
- def _add_name_space(self, tags: Iterable[str] | str) -> Iterable[str] | str:
55
+ def _add_name_space(self, tags: Iterable[str] | str) -> list[str] | str:
56
56
  if isinstance(tags, str):
57
57
  return self.namespace + tags
58
58
  return [f"{self.namespace}{t}" for t in tags]
@@ -184,7 +184,7 @@ class TagDB:
184
184
  r = self.db.sinter(tags)
185
185
  return self._format_query_result(r)
186
186
 
187
- def tags_for_value(self, value: str) -> Iterable[str]:
187
+ def tags_for_value(self, value: str) -> list[str]:
188
188
  """
189
189
  Return list of tags assigned to a value.
190
190
 
@@ -53,13 +53,13 @@ class InputDatasetPartResponse(InputDatasetBaseModel):
53
53
  """Response class for the input dataset part entity."""
54
54
 
55
55
  inputDatasetPartId: int
56
- # inputDatasetPartDocument : Json[InputDatasetPartDocumentList] # will work in gqlclient v2
56
+ # inputDatasetPartDocument : Json[InputDatasetPartDocumentList] # wishlist for next gqlclient version
57
57
  inputDatasetPartDocument: Json[list]
58
58
  inputDatasetPartType: InputDatasetPartTypeResponse
59
59
 
60
60
  @field_validator("inputDatasetPartDocument", mode="after")
61
61
  @classmethod
62
- def _use_frame_or_parameter_model(cls, value_list): # not needed for gqlclient v2
62
+ def _use_frame_or_parameter_model(cls, value_list): # not needed if Json[model] implemented
63
63
  return InputDatasetPartDocumentList(doc_list=value_list)
64
64
 
65
65
 
@@ -121,12 +121,12 @@ class RecipeRunResponse(GraphqlBaseModel):
121
121
  recipeInstance: RecipeInstanceResponse
122
122
  recipeInstanceId: int
123
123
  recipeRunProvenances: list[RecipeRunProvenanceResponse]
124
- # configuration: Json[RecipeRunConfiguration] | None # will work in gqlclient v2
124
+ # configuration: Json[RecipeRunConfiguration] | None # wishlist for next gqlclient version
125
125
  configuration: Json[dict] | None
126
126
 
127
127
  @field_validator("configuration", mode="after")
128
128
  @classmethod
129
- def _use_recipe_run_configuration_model(cls, value): # not needed for gqlclient v2
129
+ def _use_recipe_run_configuration_model(cls, value):
130
130
  if value is None:
131
131
  return RecipeRunConfiguration()
132
132
  return RecipeRunConfiguration.model_validate(value)
@@ -56,7 +56,7 @@ class InputDatasetParameterValue(InputDatasetBaseModel):
56
56
  """Input dataset parameter value validator."""
57
57
 
58
58
  parameter_value_id: int
59
- # parameter_value: Json[InputDatasetFilePointer] | Json[Any] # will work in gqlclient v2
59
+ # parameter_value: Json[InputDatasetFilePointer] | Json[Any] # wishlist for next gqlclient version
60
60
  parameter_value: Json[Any]
61
61
  parameter_value_start_date: Annotated[
62
62
  datetime, Field(default=datetime(1, 1, 1)), PlainSerializer(lambda x: x.isoformat())
@@ -64,7 +64,7 @@ class InputDatasetParameterValue(InputDatasetBaseModel):
64
64
 
65
65
  @field_validator("parameter_value", mode="after")
66
66
  @classmethod
67
- def validate_parameter_value(cls, param_val):
67
+ def validate_parameter_value(cls, param_val): # not needed if Json[model] implemented
68
68
  """Decode and provide additional validation for parameter_value types."""
69
69
  match param_val:
70
70
  case {"__file__": _}:
@@ -214,10 +214,7 @@ class WorkflowTaskBase(TaskBase, MetadataStoreMixin, ABC):
214
214
  """
215
215
  self.write_counter.add(amount=1, attributes=self.base_telemetry_attributes)
216
216
  file_obj = encoder(data, **encoder_kwargs)
217
- if isinstance(tags, str):
218
- tags = [tags]
219
- else:
220
- tags = [t for t in tags] # copy the input list so we don't modify it in place
217
+ tags = self.scratch.parse_tags(tags)
221
218
  tags.append(Tag.workflow_task(self.__class__.__name__))
222
219
 
223
220
  relative_path = relative_path or self.build_generic_tag_filename(tags)
@@ -247,9 +244,9 @@ class WorkflowTaskBase(TaskBase, MetadataStoreMixin, ABC):
247
244
  StemName.modstate.value,
248
245
  ]
249
246
 
250
- def build_generic_tag_filename(self, tags: list) -> str:
247
+ def build_generic_tag_filename(self, tags: list[str]) -> str:
251
248
  """
252
- Build a filename from a set of tags.
249
+ Build a filename from a list of tags.
253
250
 
254
251
  The algorithm is:
255
252
 
@@ -263,9 +260,8 @@ class WorkflowTaskBase(TaskBase, MetadataStoreMixin, ABC):
263
260
 
264
261
  4. You can have any extension you want so long as it's ".dat".
265
262
  """
266
- # This call copies the input list so it doesn't get modified in place and flattens the list to allow
267
- # arbitrarily nested lists.
268
- copied_tags = self.scratch.parse_tags(tags)
263
+ # Copy the tag list so it doesn't get modified in place.
264
+ copied_tags = tags.copy()
269
265
  try:
270
266
  copied_tags.remove(StemName.frame.value)
271
267
  except ValueError:
@@ -9,7 +9,7 @@ from uuid import uuid4
9
9
  import pytest
10
10
 
11
11
  from dkist_processing_common._util.scratch import WorkflowFileSystem
12
- from dkist_processing_common._util.scratch import _flatten_list
12
+ from dkist_processing_common._util.scratch import _flatten_tags
13
13
 
14
14
 
15
15
  @pytest.fixture(
@@ -54,10 +54,10 @@ def test_workflow_file_system(workflow_file_system):
54
54
  @pytest.mark.parametrize(
55
55
  "tags",
56
56
  [
57
- pytest.param(None, id="0"),
58
- pytest.param("foo", id="1"),
59
- pytest.param(["foo", "baz"], id="2"),
60
- pytest.param(["foo", ["bar", "baz"]], id="nested"),
57
+ pytest.param([], id="empty_list_tag"),
58
+ pytest.param("foo", id="str_tag"),
59
+ pytest.param(["foo", "baz"], id="list_tag"),
60
+ pytest.param(["foo", ["bar", "baz"]], id="nested_list_tag"),
61
61
  ],
62
62
  )
63
63
  def test_workflow_file_system_write(workflow_file_system, tags, folder_path):
@@ -82,15 +82,28 @@ def test_workflow_file_system_write(workflow_file_system, tags, folder_path):
82
82
  assert next(wkflow_fs.find_all(tags=tags)) == full_file_path
83
83
 
84
84
 
85
- def test_workflow_file_system_write_invalid(workflow_file_system):
85
+ def test_workflow_file_system_write_invalid_path(workflow_file_system):
86
86
  """
87
87
  Given: An instance of WorkflowFileSystem
88
88
  When: writing to an absolute path
89
- Then: ValueError is raised
89
+ Then: the correct ValueError is raised
90
90
  """
91
91
  wkflow_fs, _, _ = workflow_file_system
92
- with pytest.raises(ValueError):
93
- wkflow_fs.write(b"1234", Path.cwd())
92
+ with pytest.raises(ValueError, match="relative"):
93
+ wkflow_fs.write(b"1234", Path.cwd(), tags="test_tag")
94
+
95
+
96
+ def test_workflow_file_system_write_invalid_tags(workflow_file_system):
97
+ """
98
+ Given: An instance of WorkflowFileSystem
99
+ When: writing with tags=None
100
+ Then: the correct ValueError is raised
101
+ """
102
+ wkflow_fs, _, _ = workflow_file_system
103
+ file_path = Path(f"{uuid4().hex[:6]}.bin")
104
+ rel_path = Path("test_write_path") / file_path
105
+ with pytest.raises(TypeError, match="tags=None"):
106
+ wkflow_fs.write(b"1234", rel_path, tags=None)
94
107
 
95
108
 
96
109
  @pytest.mark.parametrize(
@@ -335,9 +348,9 @@ def test_workflow_file_system_duplicate_do_not_overwrite(workflow_file_system):
335
348
  file_path = Path(f"{uuid4().hex[:6]}.bin")
336
349
  rel_path = Path("test_write_path") / file_path
337
350
  # When / Then
338
- wkflow_fs.write(file_obj, rel_path, tags=None, overwrite=False)
351
+ wkflow_fs.write(file_obj, rel_path, tags=[], overwrite=False)
339
352
  with pytest.raises(FileExistsError):
340
- wkflow_fs.write(file_obj, rel_path, tags=None, overwrite=False)
353
+ wkflow_fs.write(file_obj, rel_path, tags=[], overwrite=False)
341
354
 
342
355
 
343
356
  def test_workflow_file_system_duplicate_do_overwrite(workflow_file_system):
@@ -372,17 +385,22 @@ def test_workflow_file_system_duplicate_do_overwrite(workflow_file_system):
372
385
  ["a", "b", "c", "d", "e", "f", "g", "h", "i"],
373
386
  id="Nested",
374
387
  ),
388
+ pytest.param(
389
+ {"a", ("b", ("c", "d"))},
390
+ ["a", "b", "c", "d"],
391
+ id="Nested_set",
392
+ ),
375
393
  ],
376
394
  )
377
- def test_flatten_list(given, expected):
395
+ def test_flatten_tags(given, expected):
378
396
  """
379
- Given: A list to flatten
380
- When: Flattening the list
397
+ Given: An iterator to flatten
398
+ When: Flattening the iterator into a list
381
399
  Then: The new list matches the expected 1D result
382
400
  """
383
401
  # When
384
- actual = _flatten_list(given)
385
- assert actual == expected
402
+ actual = _flatten_tags(given)
403
+ assert sorted(actual) == sorted(expected)
386
404
 
387
405
 
388
406
  @pytest.fixture()
@@ -94,6 +94,20 @@ def test_valid_read_with_tag_object(workflow_data_task):
94
94
  assert tagged_filepath.exists()
95
95
 
96
96
 
97
+ def test_valid_read_with_tag_set(workflow_data_task):
98
+ """
99
+ Given: a WorkflowDataTask with tagged data
100
+ When: reading tagged files using a set of tags
101
+ Then: the correct number of files are returned and they have the correct names
102
+ """
103
+ task, number_of_files, filenames, tag_string, tag_object = workflow_data_task
104
+ tagged_filepaths = list(task.read(tags={tag_string, tag_object}))
105
+ assert len(tagged_filepaths) == number_of_files
106
+ for tagged_filepath in tagged_filepaths:
107
+ assert tagged_filepath.name in filenames
108
+ assert tagged_filepath.exists()
109
+
110
+
97
111
  def test_valid_write(workflow_data_task):
98
112
  """
99
113
  Given: a WorkflowDataTask
@@ -111,14 +125,26 @@ def test_write_tags_is_none(workflow_data_task):
111
125
  """
112
126
  Given: a WorkflowDataTask
113
127
  When: writing a file to disk with tags=None
114
- Then: a ValueError is raised
128
+ Then: the correct ValueError is raised
115
129
  """
116
130
  task, _, _, _, _ = workflow_data_task
117
131
  relative_path = "bytesio_path"
118
- with pytest.raises(TypeError):
132
+ with pytest.raises(TypeError, match="tags=None"):
119
133
  task.write(data=bytes("abcdefg", "utf-8"), tags=None, relative_path=relative_path)
120
134
 
121
135
 
136
+ def test_read_tags_is_none(workflow_data_task):
137
+ """
138
+ Given: a WorkflowDataTask
139
+ When: reading files with tags=None
140
+ Then: the correct ValueError is raised
141
+ """
142
+ task, _, _, _, _ = workflow_data_task
143
+ filepaths = task.read(tags=None)
144
+ with pytest.raises(TypeError, match="tags=None"):
145
+ next(filepaths)
146
+
147
+
122
148
  def test_read_nonexistent_tag(workflow_data_task):
123
149
  """
124
150
  Given: a WorkflowDataTask
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-common
3
- Version: 13.0.5rc2
3
+ Version: 13.0.6
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
@@ -23,7 +23,7 @@ Requires-Dist: dkist-service-configuration<5.0,>=4.3.0
23
23
  Requires-Dist: dkist-spectral-lines<4.0,>=3.0.0
24
24
  Requires-Dist: solar-wavelength-calibration<3.0,>=2.0.0
25
25
  Requires-Dist: globus-sdk<5.0.0,>=4.0.0
26
- Requires-Dist: gqlclient[pydantic]==1.2.3
26
+ Requires-Dist: gqlclient==2.0.0
27
27
  Requires-Dist: sqids==0.5.1
28
28
  Requires-Dist: matplotlib>=3.4
29
29
  Requires-Dist: moviepy>=2.0.0
@@ -7,7 +7,6 @@ README.rst
7
7
  bitbucket-pipelines.yml
8
8
  pyproject.toml
9
9
  changelog/.gitempty
10
- changelog/329.feature.rst
11
10
  dkist_processing_common/__init__.py
12
11
  dkist_processing_common/config.py
13
12
  dkist_processing_common/manual.py
@@ -8,7 +8,7 @@ dkist-service-configuration<5.0,>=4.3.0
8
8
  dkist-spectral-lines<4.0,>=3.0.0
9
9
  solar-wavelength-calibration<3.0,>=2.0.0
10
10
  globus-sdk<5.0.0,>=4.0.0
11
- gqlclient[pydantic]==1.2.3
11
+ gqlclient==2.0.0
12
12
  sqids==0.5.1
13
13
  matplotlib>=3.4
14
14
  moviepy>=2.0.0
@@ -31,7 +31,7 @@ dependencies = [
31
31
  "dkist-spectral-lines >= 3.0.0, <4.0",
32
32
  "solar-wavelength-calibration >= 2.0.0, <3.0",
33
33
  "globus-sdk >= 4.0.0, <5.0.0",
34
- "gqlclient[pydantic] == 1.2.3",
34
+ "gqlclient == 2.0.0",
35
35
  "sqids == 0.5.1",
36
36
  "matplotlib >= 3.4",
37
37
  "moviepy >= 2.0.0",
@@ -1 +0,0 @@
1
- Remove 4 unused quality metric codes: RANGE, NOISE, SENSITIVITY, HISTORICAL.