dkist-processing-common 12.0.0rc6__tar.gz → 12.2.0rc2__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.
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/.readthedocs.yml +1 -1
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/CHANGELOG.rst +35 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/PKG-INFO +4 -4
- dkist_processing_common-12.2.0rc2/changelog/272.feature.rst +1 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/fits.py +27 -6
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/constants.py +8 -2
- dkist_processing_common-12.2.0rc2/dkist_processing_common/models/extras.py +35 -0
- dkist_processing_common-12.2.0rc2/dkist_processing_common/models/flower_pot.py +416 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/tags.py +13 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/average_bud.py +0 -2
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/cs_step.py +10 -10
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/id_bud.py +8 -10
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/lookup_bud.py +7 -11
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/near_bud.py +7 -12
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/retarder.py +9 -13
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/time.py +19 -55
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/unique_bud.py +7 -14
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/l1_output_data.py +16 -11
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/output_data_base.py +25 -4
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/parse_l0_input_data.py +4 -2
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/transfer_input_data.py +1 -0
- dkist_processing_common-12.2.0rc2/dkist_processing_common/tasks/write_extra.py +333 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/write_l1.py +2 -55
- dkist_processing_common-12.2.0rc2/dkist_processing_common/tasks/write_l1_base.py +67 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_codecs.py +57 -11
- dkist_processing_common-12.2.0rc2/dkist_processing_common/tests/test_construct_dataset_extras.py +219 -0
- dkist_processing_common-12.2.0rc2/dkist_processing_common/tests/test_flower_pot.py +247 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_output_data_base.py +24 -2
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_parse_l0_input_data.py +28 -4
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_stems.py +140 -193
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_transfer_l1_output_data.py +1 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_workflow_task_base.py +0 -11
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_write_l1.py +0 -1
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common.egg-info/PKG-INFO +4 -4
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common.egg-info/SOURCES.txt +5 -1
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common.egg-info/requires.txt +3 -3
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/pyproject.toml +3 -3
- dkist_processing_common-12.0.0rc6/changelog/288.misc.rst +0 -1
- dkist_processing_common-12.0.0rc6/dkist_processing_common/models/flower_pot.py +0 -195
- dkist_processing_common-12.0.0rc6/dkist_processing_common/tests/test_flower_pot.py +0 -105
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/.gitignore +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/.pre-commit-config.yaml +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/.snyk +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/README.rst +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/bitbucket-pipelines.yml +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/changelog/.gitempty +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/_util/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/_util/constants.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/_util/graphql.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/_util/scratch.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/_util/tags.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/array.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/asdf.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/basemodel.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/bytes.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/iobase.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/json.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/path.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/quality.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/codecs/str.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/config.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/fonts/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/manual.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/dkist_location.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/fits_access.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/fried_parameter.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/graphql.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/input_dataset.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/message.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/message_queue_binding.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/metric_code.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/parameters.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/quality.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/task_name.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/telemetry.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/models/wavelength.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/l0_fits_access.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/l1_fits_access.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/observing_program_id_bud.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/quality.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/task.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/parsers/wavelength.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/assemble_movie.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/base.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/globus.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/mixin/quality/_metrics.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/quality_metrics.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/teardown.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/trial_catalog.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tasks/trial_output_data.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/__init__.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/conftest.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/mock_metadata_store.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_assemble_quality.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_base.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_constants.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_cs_step.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_dkist_location.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_fits_access.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_fried_parameter.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_input_dataset.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_manual_processing.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_parameters.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_quality.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_quality_mixin.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_scratch.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_tags.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_task_name.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_task_parsing.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_teardown.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_trial_catalog.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/dkist_processing_common.egg-info/top_level.txt +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/Makefile +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/changelog.rst +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/conf.py +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/index.rst +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/landing_page.rst +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/make.bat +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/docs/requirements.txt +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/licenses/LICENSE.rst +0 -0
- {dkist_processing_common-12.0.0rc6 → dkist_processing_common-12.2.0rc2}/setup.cfg +0 -0
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
v12.1.0 (2026-01-26)
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
Features
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
- Add `ListStem` base class for huge speedup in cases where the keys don't matter and the `getter` logic only depends on the
|
|
8
|
+
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>`__)
|
|
9
|
+
- Add `SetStem` base class that has all the benefits of `ListStem` but also gets a speedup by storing values in a `set` for
|
|
10
|
+
cases where repeated values don't need to be tracked. (`#282 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/282>`__)
|
|
11
|
+
- 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>`__)
|
|
12
|
+
- Speed up `NumCSStepBud`, `[Task]UniqueBud`, `[Task]ContributingIdsBud`, and `TaskRoundTimeBudBase` parsing by basing
|
|
13
|
+
these buds on `SetStem`. (`#285 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/285>`__)
|
|
14
|
+
- Speed up `CSStepFlower` parsing by using an internal set to keep track of the unique `CSStep` objects. This removes the
|
|
15
|
+
need to compute the unique set when computing the tag for each file. (`#286 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/286>`__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Misc
|
|
19
|
+
----
|
|
20
|
+
|
|
21
|
+
- 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>`__)
|
|
22
|
+
- Update `RetarderNameBud` to drop "clear" values (i.e., the retarder is out of the beam) in the `setter` instead of the `getter`.
|
|
23
|
+
This brings it in line with standard Bud-practice. (`#285 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/285>`__)
|
|
24
|
+
- Convert the TimeLookupBud to be a SetStem constant. (`#287 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/287>`__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
v12.0.0 (2026-01-22)
|
|
28
|
+
====================
|
|
29
|
+
|
|
30
|
+
Misc
|
|
31
|
+
----
|
|
32
|
+
|
|
33
|
+
- Upgrade dkist-processing-core to 7.0.0 which includes an upgrade of Airflow to 3.1.5 and python >= 3.13. (`#278 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/278>`__)
|
|
34
|
+
|
|
35
|
+
|
|
1
36
|
v11.9.3 (2026-01-07)
|
|
2
37
|
====================
|
|
3
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dkist-processing-common
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.2.0rc2
|
|
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,10 +16,10 @@ 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.
|
|
20
|
-
Requires-Dist: dkist-processing-core==7.0.
|
|
19
|
+
Requires-Dist: dkist-header-validator<6.0,>=5.3.0
|
|
20
|
+
Requires-Dist: dkist-processing-core==7.0.1
|
|
21
21
|
Requires-Dist: dkist-processing-pac<4.0,>=3.1
|
|
22
|
-
Requires-Dist: dkist-service-configuration<5.0,>=4.
|
|
22
|
+
Requires-Dist: dkist-service-configuration<5.0,>=4.2.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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
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.
|
|
@@ -31,15 +31,30 @@ def fits_hdulist_encoder(hdu_list: fits.HDUList) -> bytes:
|
|
|
31
31
|
return iobase_encoder(file_obj)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def fits_hdu_decoder(
|
|
34
|
+
def fits_hdu_decoder(
|
|
35
|
+
path: Path,
|
|
36
|
+
hdu: int | None = None,
|
|
37
|
+
checksum: bool = True,
|
|
38
|
+
disable_image_compression: bool = False,
|
|
39
|
+
) -> fits.PrimaryHDU | fits.CompImageHDU:
|
|
35
40
|
"""Read a Path with `fits` to produce an `HDUList`."""
|
|
36
|
-
hdu_list = fits.open(
|
|
41
|
+
hdu_list = fits.open(
|
|
42
|
+
path, checksum=checksum, disable_image_compression=disable_image_compression
|
|
43
|
+
)
|
|
37
44
|
return _extract_hdu(hdu_list, hdu)
|
|
38
45
|
|
|
39
46
|
|
|
40
|
-
def fits_array_decoder(
|
|
47
|
+
def fits_array_decoder(
|
|
48
|
+
path: Path,
|
|
49
|
+
hdu: int | None = None,
|
|
50
|
+
auto_squeeze: bool = True,
|
|
51
|
+
checksum: bool = True,
|
|
52
|
+
disable_image_compression: bool = False,
|
|
53
|
+
) -> np.ndarray:
|
|
41
54
|
"""Read a Path with `fits` and return the `.data` property."""
|
|
42
|
-
hdu = fits_hdu_decoder(
|
|
55
|
+
hdu = fits_hdu_decoder(
|
|
56
|
+
path, hdu=hdu, checksum=checksum, disable_image_compression=disable_image_compression
|
|
57
|
+
)
|
|
43
58
|
data = hdu.data
|
|
44
59
|
|
|
45
60
|
# This conditional is explicitly to catch summit data with a dummy first axis for WCS
|
|
@@ -50,10 +65,16 @@ def fits_array_decoder(path: Path, hdu: int | None = None, auto_squeeze: bool =
|
|
|
50
65
|
|
|
51
66
|
|
|
52
67
|
def fits_access_decoder(
|
|
53
|
-
path: Path,
|
|
68
|
+
path: Path,
|
|
69
|
+
fits_access_class: Type[FitsAccessBase],
|
|
70
|
+
checksum: bool = True,
|
|
71
|
+
disable_image_compression: bool = False,
|
|
72
|
+
**fits_access_kwargs,
|
|
54
73
|
) -> FitsAccessBase:
|
|
55
74
|
"""Read a Path with `fits` and ingest into a `FitsAccessBase`-type object."""
|
|
56
|
-
hdu = fits_hdu_decoder(
|
|
75
|
+
hdu = fits_hdu_decoder(
|
|
76
|
+
path, checksum=checksum, disable_image_compression=disable_image_compression
|
|
77
|
+
)
|
|
57
78
|
return fits_access_class(hdu=hdu, name=str(path), **fits_access_kwargs)
|
|
58
79
|
|
|
59
80
|
|
|
@@ -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
|
|
@@ -333,8 +339,8 @@ class ConstantsBase:
|
|
|
333
339
|
def dark_num_raw_frames_per_fpa(self) -> dict[float, list]:
|
|
334
340
|
"""Return the dictionary of exposure times to number of raw frames per fpa."""
|
|
335
341
|
raw_return = self._db_dict[BudName.dark_num_raw_frames_per_fpa]
|
|
336
|
-
# convert
|
|
337
|
-
return {k: v for k, v in raw_return}
|
|
342
|
+
# convert JSON string keys back to float
|
|
343
|
+
return {float(k): v for k, v in raw_return.items()}
|
|
338
344
|
|
|
339
345
|
@property
|
|
340
346
|
def solar_gain_num_raw_frames_per_fpa(self) -> int:
|
|
@@ -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"
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Framework for grouping multiple keys and values with arbitrary logic.
|
|
3
|
+
|
|
4
|
+
The key components are:
|
|
5
|
+
**Stem:** ABC for groupings that depend on both the key and (maybe) value. Subgroups (Petals) are implied but not enforced.
|
|
6
|
+
|
|
7
|
+
**ListStem:** ABC for groups that depend on value only. More limited, but faster than `Stem` for cases where the keys don't matter.
|
|
8
|
+
|
|
9
|
+
**SetStem:** ABC for groups that depend on value only and the values are well represented by a `set`. Even more limited, but faster than `Stem` for cases where the keys don't matter.
|
|
10
|
+
|
|
11
|
+
**FlowerPot:** Container for Stem children (Flowers)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from abc import ABC
|
|
17
|
+
from abc import abstractmethod
|
|
18
|
+
from collections import defaultdict
|
|
19
|
+
from collections.abc import Hashable
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class FlowerPot:
|
|
24
|
+
"""Base class to hold multiple sets (Stems) of key, value pairs."""
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
self.stems: list[Stem] = list()
|
|
28
|
+
|
|
29
|
+
def __iter__(self):
|
|
30
|
+
return self.stems.__iter__()
|
|
31
|
+
|
|
32
|
+
def __len__(self):
|
|
33
|
+
return self.stems.__len__()
|
|
34
|
+
|
|
35
|
+
def __getitem__(self, item):
|
|
36
|
+
return self.stems.__getitem__(item)
|
|
37
|
+
|
|
38
|
+
def add_dirt(self, key: Hashable, value: Any) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Send key and value through all Stems.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
key
|
|
45
|
+
The key
|
|
46
|
+
value
|
|
47
|
+
The value
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
None
|
|
52
|
+
"""
|
|
53
|
+
if not isinstance(key, Hashable):
|
|
54
|
+
raise TypeError(f"Type of key ({type(key)}) is not hashable")
|
|
55
|
+
|
|
56
|
+
for stem in self.stems:
|
|
57
|
+
stem.update(key, value)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class SpilledDirt:
|
|
61
|
+
"""
|
|
62
|
+
A custom class for when a Stem wants the FlowerPot to skip that particular key/value.
|
|
63
|
+
|
|
64
|
+
Exists because None, False, [], (), etc. etc. are all valid Stem return values
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Thorn:
|
|
69
|
+
"""
|
|
70
|
+
Custom class to indicate that a Bud's value should not be used.
|
|
71
|
+
|
|
72
|
+
I.e., don't pick this Bud because it's thorny. This exists for "Picky" Buds that merely perform a check and Error
|
|
73
|
+
on failure. If the check passes we don't need to do anything with the Bud's value and that value should be a Thorn.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Petal:
|
|
78
|
+
"""
|
|
79
|
+
Base class to hold a single key, value pair.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
item
|
|
84
|
+
The key, value pair to be added
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(self, item: tuple):
|
|
88
|
+
self.value = item[0]
|
|
89
|
+
self.keys = item[1]
|
|
90
|
+
|
|
91
|
+
def __repr__(self):
|
|
92
|
+
return f"Petal: {{{self.value}: {self.keys}}}"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Stem(ABC):
|
|
96
|
+
"""
|
|
97
|
+
Base class for grouping keys via arbitrary logic on the total collection of keys and values.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
stem_name
|
|
102
|
+
The name to be associated with the stem
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
def __init__(self, stem_name: Any):
|
|
106
|
+
self.stem_name = stem_name
|
|
107
|
+
self.key_to_petal_dict: dict[Hashable, Hashable] = dict()
|
|
108
|
+
|
|
109
|
+
self._petal_cache: list[Petal] = []
|
|
110
|
+
self._need_to_generate_petals: bool = True
|
|
111
|
+
|
|
112
|
+
def update(self, key: Hashable, value: Any) -> None:
|
|
113
|
+
"""
|
|
114
|
+
Ingest a single key/value pair.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
key
|
|
119
|
+
The key
|
|
120
|
+
value
|
|
121
|
+
The value
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
None
|
|
126
|
+
"""
|
|
127
|
+
result = self.setter(value)
|
|
128
|
+
if result is not SpilledDirt:
|
|
129
|
+
self.key_to_petal_dict[key] = result
|
|
130
|
+
self._need_to_generate_petals = True
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def petals(self) -> list[Petal]:
|
|
134
|
+
"""Return subgroups and associated keys."""
|
|
135
|
+
if self._need_to_generate_petals:
|
|
136
|
+
self._generate_petal_list()
|
|
137
|
+
|
|
138
|
+
return self._petal_cache
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def can_be_picked(self) -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Return True if there are any values to be picked.
|
|
144
|
+
|
|
145
|
+
A `Stem` could have no values even after dirt is added if all of the results were `SpilledDirt`.
|
|
146
|
+
"""
|
|
147
|
+
return len(self.petals) > 0
|
|
148
|
+
|
|
149
|
+
def _generate_petal_list(self) -> None:
|
|
150
|
+
"""
|
|
151
|
+
Generate a list of petals.
|
|
152
|
+
|
|
153
|
+
Generating a petal list can be expensive because it involves inverting the `key_to_petal_dict`. To avoid doing
|
|
154
|
+
this every the `petals` property is accessed, this method produces a cached list of petals that is only
|
|
155
|
+
re-generated when the `key_to_petal_dict` has been updated.
|
|
156
|
+
|
|
157
|
+
Note: We can't make `petals` a `@cached_property` because that would make `petals` always tied to whatever the
|
|
158
|
+
state of this `Stem` was when `petals` was first accessed. And we can't use `lru_cache` because the object that
|
|
159
|
+
changes, `key_to_petal_dict`, is unhashable.
|
|
160
|
+
"""
|
|
161
|
+
petal_to_key_dict = defaultdict(list)
|
|
162
|
+
for key in self.key_to_petal_dict.keys():
|
|
163
|
+
petal = self.getter(key)
|
|
164
|
+
petal_to_key_dict[petal].append(key)
|
|
165
|
+
|
|
166
|
+
self._petal_cache = [Petal(item) for item in petal_to_key_dict.items()]
|
|
167
|
+
self._need_to_generate_petals = False
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def bud(self) -> Petal:
|
|
171
|
+
"""Just the first petal."""
|
|
172
|
+
bud = self.petals[0]
|
|
173
|
+
return bud
|
|
174
|
+
|
|
175
|
+
@abstractmethod
|
|
176
|
+
def setter(self, value: Any) -> Any:
|
|
177
|
+
"""
|
|
178
|
+
Logic to apply to a single key/value pair on ingest.
|
|
179
|
+
|
|
180
|
+
Implemented in derived class.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
value
|
|
185
|
+
The value to be added
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
Any
|
|
190
|
+
"""
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
@abstractmethod
|
|
194
|
+
def getter(self, key: Hashable) -> Hashable:
|
|
195
|
+
"""
|
|
196
|
+
Logic to apply to all ingested values when picking the Stem.
|
|
197
|
+
|
|
198
|
+
Implemented in derived class.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
key
|
|
203
|
+
The key to return the value of
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
The value
|
|
207
|
+
"""
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class ListStem(ABC):
|
|
212
|
+
"""
|
|
213
|
+
Base class for collecting and applying logic to values in a `list` with a `Stem`-like interface.
|
|
214
|
+
|
|
215
|
+
Unlike the full `Stem`, this class does NOT retain information about the keys and thus does no grouping of keys based
|
|
216
|
+
on values. The direct consequence of this is that the `.petals` property is undefined and will raise an ``AttributeError``
|
|
217
|
+
if accessed. This also means there is no need to invert the `key_to_petal_dict` (because it doesn't exist), which,
|
|
218
|
+
in turn, means there is no need to run the `getter` for every key. The result is that the `bud` property only needs
|
|
219
|
+
one call to `getter`. Thus, the calculation of a single value derived from all values (i.e., `bud`) is much faster
|
|
220
|
+
than using a full `Stem`.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
stem_name
|
|
225
|
+
The name to be associated with the stem
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def __init__(self, stem_name: Any):
|
|
229
|
+
self.stem_name = stem_name
|
|
230
|
+
self.value_list: list = list()
|
|
231
|
+
self._need_to_compute_bud_value: bool = True
|
|
232
|
+
|
|
233
|
+
def update(self, key: Any, value: Any) -> None:
|
|
234
|
+
"""
|
|
235
|
+
Ingest a single key/value pair. Note that the ``key`` is not used.
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
key
|
|
240
|
+
The key (unused)
|
|
241
|
+
|
|
242
|
+
value
|
|
243
|
+
The value
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
None
|
|
248
|
+
"""
|
|
249
|
+
result = self.setter(value)
|
|
250
|
+
if result is not SpilledDirt:
|
|
251
|
+
self.value_list.append(result)
|
|
252
|
+
self._need_to_compute_bud_value = True
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def petals(self) -> None:
|
|
256
|
+
"""Raise an error because `ListStem` does not retain key information and therefore cannot group keys."""
|
|
257
|
+
raise AttributeError(
|
|
258
|
+
f"{self.__class__.__name__} subclasses ListStem and therefore does not define the `petals` property"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def can_be_picked(self) -> bool:
|
|
263
|
+
"""
|
|
264
|
+
Return True if there are any values to be picked.
|
|
265
|
+
|
|
266
|
+
A `Stem` could have no values even after dirt is added if all of the results were `SpilledDirt`.
|
|
267
|
+
"""
|
|
268
|
+
return len(self.value_list) > 0
|
|
269
|
+
|
|
270
|
+
@property
|
|
271
|
+
def bud(self) -> Petal:
|
|
272
|
+
"""Return the result of `getter` packaged in a `Petal` object."""
|
|
273
|
+
if self._need_to_compute_bud_value:
|
|
274
|
+
self._value_cache = self.getter()
|
|
275
|
+
self._need_to_compute_bud_value = False
|
|
276
|
+
|
|
277
|
+
return Petal((self._value_cache, "LISTSTEM_NOT_USED"))
|
|
278
|
+
|
|
279
|
+
@abstractmethod
|
|
280
|
+
def setter(self, value: Any) -> Any:
|
|
281
|
+
"""
|
|
282
|
+
Logic to apply to a single value pair on ingest.
|
|
283
|
+
|
|
284
|
+
Implemented in derived class.
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
value
|
|
289
|
+
The value to be added
|
|
290
|
+
|
|
291
|
+
Returns
|
|
292
|
+
-------
|
|
293
|
+
Any
|
|
294
|
+
"""
|
|
295
|
+
pass
|
|
296
|
+
|
|
297
|
+
@abstractmethod
|
|
298
|
+
def getter(self) -> Any:
|
|
299
|
+
"""
|
|
300
|
+
Logic to apply to all ingested values when computing the `bud`.
|
|
301
|
+
|
|
302
|
+
Implemented in derived class.
|
|
303
|
+
|
|
304
|
+
Returns
|
|
305
|
+
-------
|
|
306
|
+
The value of the bud
|
|
307
|
+
"""
|
|
308
|
+
pass
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class SetStem(ABC):
|
|
312
|
+
"""
|
|
313
|
+
Base class for collecting and applying logic to values in a `set` with a `Stem`-like interface.
|
|
314
|
+
|
|
315
|
+
Unlike the full `Stem`, this class does NOT retain information about the keys and thus does no grouping of keys based
|
|
316
|
+
on values. The direct consequence of this is that the `.petals` property is undefined and will raise an ``AttributeError``
|
|
317
|
+
if accessed. This also means there is no need to invert the `key_to_petal_dict` (because it doesn't exist), which,
|
|
318
|
+
in turn, means there is no need to run the `getter` for every key. The result is that the `bud` property only needs
|
|
319
|
+
one call to `getter`. Combined with the efficiency of storing values in a `set`, the calculation of a single value
|
|
320
|
+
derived from all values (i.e., `bud`) is much faster than using a full `Stem`.
|
|
321
|
+
|
|
322
|
+
.. Note::
|
|
323
|
+
The use of a `set` as the underlying storage mechanism means information regarding how many times a particular value
|
|
324
|
+
is present will be lost. It also means the return type of `setter` must be hashable. Both of these constraints can
|
|
325
|
+
be avoided by using `ListStem`, which still gets a significant speedup over `Stem` by dropping key information.
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
stem_name
|
|
331
|
+
The name to be associated with the stem
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
def __init__(self, stem_name: Any):
|
|
335
|
+
self.stem_name = stem_name
|
|
336
|
+
self.value_set: set = set()
|
|
337
|
+
self._need_to_compute_bud_value: bool = True
|
|
338
|
+
|
|
339
|
+
def update(self, key: Any, value: Any) -> None:
|
|
340
|
+
"""
|
|
341
|
+
Ingest a single key/value pair. Note that the ``key`` is not used.
|
|
342
|
+
|
|
343
|
+
Parameters
|
|
344
|
+
----------
|
|
345
|
+
key
|
|
346
|
+
The key (unused)
|
|
347
|
+
|
|
348
|
+
value
|
|
349
|
+
The value
|
|
350
|
+
|
|
351
|
+
Returns
|
|
352
|
+
-------
|
|
353
|
+
None
|
|
354
|
+
"""
|
|
355
|
+
result = self.setter(value)
|
|
356
|
+
if result is not SpilledDirt:
|
|
357
|
+
self.value_set.add(result)
|
|
358
|
+
self._need_to_compute_bud_value = True
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
def petals(self) -> None:
|
|
362
|
+
"""Raise an error because `SetStem` does not retain key information and therefore cannot group keys."""
|
|
363
|
+
raise AttributeError(
|
|
364
|
+
f"{self.__class__.__name__} subclasses SetStem and therefore does not define the `petals` property"
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def can_be_picked(self) -> bool:
|
|
369
|
+
"""
|
|
370
|
+
Return True if there are any values to be picked.
|
|
371
|
+
|
|
372
|
+
A `Stem` could have no values even after dirt is added if all of the results were `SpilledDirt`.
|
|
373
|
+
"""
|
|
374
|
+
return len(self.value_set) > 0
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def bud(self) -> Petal:
|
|
378
|
+
"""Return the result of `getter` packaged in a `Petal` object."""
|
|
379
|
+
if self._need_to_compute_bud_value:
|
|
380
|
+
self._value_cache = self.getter()
|
|
381
|
+
self._need_to_compute_bud_value = False
|
|
382
|
+
|
|
383
|
+
return Petal((self._value_cache, "SETSTEM_NOT_USED"))
|
|
384
|
+
|
|
385
|
+
@abstractmethod
|
|
386
|
+
def setter(self, value: Any) -> Hashable:
|
|
387
|
+
"""
|
|
388
|
+
Logic to apply to a single value pair on ingest.
|
|
389
|
+
|
|
390
|
+
Must return a Hashable object because the result will be stored in a `set`.
|
|
391
|
+
|
|
392
|
+
Implemented in derived class.
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
value
|
|
397
|
+
The value to be added
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
Any
|
|
402
|
+
"""
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
@abstractmethod
|
|
406
|
+
def getter(self) -> Any:
|
|
407
|
+
"""
|
|
408
|
+
Logic to apply to all ingested values when computing the `bud`.
|
|
409
|
+
|
|
410
|
+
Implemented in derived class.
|
|
411
|
+
|
|
412
|
+
Returns
|
|
413
|
+
-------
|
|
414
|
+
The value of the bud
|
|
415
|
+
"""
|
|
416
|
+
pass
|
|
@@ -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)
|