dkist-processing-common 14.0.1__tar.gz → 14.0.2__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-14.0.1 → dkist_processing_common-14.0.2}/CHANGELOG.rst +10 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/PKG-INFO +1 -1
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/quality.py +21 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/l1_output_data.py +53 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/quality/_base.py +0 -5
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/quality/_metrics.py +0 -84
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_assemble_quality.py +260 -10
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_quality_mixin.py +0 -50
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common.egg-info/PKG-INFO +1 -1
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/.gitignore +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/.pre-commit-config.yaml +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/.readthedocs.yml +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/.snyk +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/README.rst +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/bitbucket-pipelines.yml +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/changelog/.gitempty +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/_util/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/_util/constants.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/_util/graphql.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/_util/scratch.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/_util/tags.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/array.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/asdf.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/basemodel.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/bytes.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/fits.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/iobase.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/json.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/path.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/quality.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/codecs/str.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/config.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/fonts/Lato-Regular.ttf +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/fonts/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/manual.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/constants.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/dkist_location.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/extras.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/fits_access.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/flower_pot.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/fried_parameter.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/graphql.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/input_dataset.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/message.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/message_queue_binding.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/metric_code.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/parameters.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/tags.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/task_name.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/telemetry.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/models/wavelength.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/average_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/cs_step.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/dsps_repeat.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/experiment_id_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/id_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/l0_fits_access.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/l1_fits_access.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/lookup_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/near_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/observing_program_id_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/proposal_id_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/quality.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/retarder.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/single_value_single_key_flower.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/task.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/time.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/unique_bud.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/parsers/wavelength.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/assemble_movie.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/globus.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/interservice_bus.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/metadata_store.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/object_store.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/mixin/quality/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/output_data_base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/parse_l0_input_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/quality_metrics.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/teardown.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/transfer_input_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/trial_catalog.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/trial_output_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/write_extra.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/write_l1.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tasks/write_l1_base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/__init__.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/conftest.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/mock_metadata_store.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_assemble_movie.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_codecs.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_constants.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_construct_dataset_extras.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_cs_step.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_dkist_location.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_fits_access.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_flower_pot.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_fried_parameter.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_input_dataset.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_interservice_bus.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_interservice_bus_mixin.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_manual_processing.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_output_data_base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_parameters.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_parse_l0_input_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_publish_catalog_messages.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_quality.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_scratch.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_stems.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_submit_dataset_metadata.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_tags.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_task_name.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_task_parsing.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_teardown.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_transfer_input_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_transfer_l1_output_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_trial_catalog.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_trial_output_data.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_workflow_task_base.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/tests/test_write_l1.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common.egg-info/SOURCES.txt +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common.egg-info/dependency_links.txt +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common.egg-info/requires.txt +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common.egg-info/top_level.txt +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/Makefile +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/changelog.rst +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/conf.py +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/index.rst +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/landing_page.rst +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/make.bat +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/docs/requirements.txt +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/licenses/LICENSE.rst +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/pyproject.toml +0 -0
- {dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/setup.cfg +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
v14.0.2 (2026-05-04)
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
Features
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
- Convert TASK_TYPES quality metric to the new methodology. (`#332 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/332>`__)
|
|
8
|
+
- Add `TaskCount` quality metric model. (`#332 <https://bitbucket.org/dkistdc/dkist-processing-common/pull-requests/332>`__)
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
v14.0.1 (2026-04-22)
|
|
2
12
|
====================
|
|
3
13
|
|
|
@@ -10,6 +10,7 @@ from pydantic import ConfigDict
|
|
|
10
10
|
from pydantic import Field
|
|
11
11
|
from pydantic import FiniteFloat
|
|
12
12
|
from pydantic import PlainSerializer
|
|
13
|
+
from pydantic import StringConstraints
|
|
13
14
|
from pydantic import field_validator
|
|
14
15
|
from pydantic import model_serializer
|
|
15
16
|
from pydantic import model_validator
|
|
@@ -348,3 +349,23 @@ class QualityMetric(QualityModel):
|
|
|
348
349
|
raincloud_data: list[RaincloudData] | None = None
|
|
349
350
|
efficiency_data: list[EfficiencyData] | None = None
|
|
350
351
|
warnings: list[str] | None = None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
###########################################################
|
|
355
|
+
# Internal Quality Models #
|
|
356
|
+
# #
|
|
357
|
+
# Shared models used for generating quality metrics, #
|
|
358
|
+
# but not part of the dkist-quality interface #
|
|
359
|
+
###########################################################
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class TaskCount(BaseModel):
|
|
363
|
+
"""Frame counts for a single IP task type."""
|
|
364
|
+
|
|
365
|
+
task_type: Annotated[str, StringConstraints(to_upper=True)]
|
|
366
|
+
total_frames: int
|
|
367
|
+
frames_not_used: int = 0
|
|
368
|
+
|
|
369
|
+
def as_tuple(self) -> tuple[str, str, str]:
|
|
370
|
+
"""Render as a tuple."""
|
|
371
|
+
return self.task_type, str(self.total_frames), str(self.frames_not_used)
|
|
@@ -6,12 +6,16 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Iterable
|
|
7
7
|
|
|
8
8
|
from dkist_processing_common.codecs.basemodel import basemodel_decoder
|
|
9
|
+
from dkist_processing_common.codecs.basemodel import basemodel_encoder
|
|
9
10
|
from dkist_processing_common.codecs.quality import quality_data_encoder
|
|
10
11
|
from dkist_processing_common.models.message import CatalogFrameMessage
|
|
11
12
|
from dkist_processing_common.models.message import CatalogFrameMessageBody
|
|
12
13
|
from dkist_processing_common.models.message import CatalogObjectMessage
|
|
13
14
|
from dkist_processing_common.models.message import CatalogObjectMessageBody
|
|
15
|
+
from dkist_processing_common.models.metric_code import MetricCode
|
|
14
16
|
from dkist_processing_common.models.quality import QualityMetric
|
|
17
|
+
from dkist_processing_common.models.quality import TableData
|
|
18
|
+
from dkist_processing_common.models.quality import TaskCount
|
|
15
19
|
from dkist_processing_common.models.tags import Tag
|
|
16
20
|
from dkist_processing_common.tasks.mixin.globus import GlobusMixin
|
|
17
21
|
from dkist_processing_common.tasks.mixin.interservice_bus import InterserviceBusMixin
|
|
@@ -150,6 +154,7 @@ class AssembleQualityData(L1OutputDataBase, QualityMixin):
|
|
|
150
154
|
"""Run method for the task."""
|
|
151
155
|
# this is the new way, which will eventually supplant the old `quality_assemble_data`
|
|
152
156
|
with self.telemetry_span("Assembling generic quality data"):
|
|
157
|
+
self.compute_and_write_type_counts()
|
|
153
158
|
quality_data = self.assemble_quality_data()
|
|
154
159
|
|
|
155
160
|
# this is the old way, which is being replaced by the new `assemble_quality_data`
|
|
@@ -176,6 +181,54 @@ class AssembleQualityData(L1OutputDataBase, QualityMixin):
|
|
|
176
181
|
metrics.append(metric.model_dump(mode="json"))
|
|
177
182
|
return metrics
|
|
178
183
|
|
|
184
|
+
def compute_and_write_type_counts(self) -> None:
|
|
185
|
+
"""Compute and write TASK_TYPES quality metric."""
|
|
186
|
+
# retrieve the intermediate TASK_TYPES data for each IP task
|
|
187
|
+
task_counts: list[TaskCount] = self.quality_read_intermediate_task_type_counts()
|
|
188
|
+
|
|
189
|
+
# don't write anything if there is no data
|
|
190
|
+
if not task_counts:
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
header = ("Task Type", "Total Frames", "Unused Frames")
|
|
194
|
+
rows = [header]
|
|
195
|
+
|
|
196
|
+
warning_count_threshold = 0.05
|
|
197
|
+
warnings = []
|
|
198
|
+
for task_count in task_counts:
|
|
199
|
+
# add the row
|
|
200
|
+
rows.append(task_count.as_tuple())
|
|
201
|
+
# determine if there are any warnings for this task type
|
|
202
|
+
if task_count.total_frames == 0:
|
|
203
|
+
warnings.append(f"NO {task_count.task_type} frames were used!")
|
|
204
|
+
elif (
|
|
205
|
+
frame_ratio := task_count.frames_not_used / task_count.total_frames
|
|
206
|
+
) > warning_count_threshold:
|
|
207
|
+
warnings.append(
|
|
208
|
+
f"{round(100 * frame_ratio, 1)}% of frames were not used in the "
|
|
209
|
+
f"processing of task type {task_count.task_type}"
|
|
210
|
+
)
|
|
211
|
+
warnings = warnings or None
|
|
212
|
+
|
|
213
|
+
table_data = TableData(rows=tuple(rows))
|
|
214
|
+
metric = QualityMetric(
|
|
215
|
+
name="Frame Counts",
|
|
216
|
+
description="This metric is a count of the number of frames used to produce a "
|
|
217
|
+
"calibrated L1 dataset",
|
|
218
|
+
metric_code=MetricCode.task_types,
|
|
219
|
+
table_data=[table_data],
|
|
220
|
+
warnings=warnings,
|
|
221
|
+
)
|
|
222
|
+
self.write(metric, tags=Tag.quality("GENERIC"), encoder=basemodel_encoder)
|
|
223
|
+
|
|
224
|
+
def quality_read_intermediate_task_type_counts(self) -> list[TaskCount]:
|
|
225
|
+
"""Read intermediate task type data."""
|
|
226
|
+
tags = Tag.quality(MetricCode.task_types)
|
|
227
|
+
task_counts: list[TaskCount] = list(
|
|
228
|
+
self.read(tags=tags, decoder=basemodel_decoder, model=TaskCount)
|
|
229
|
+
)
|
|
230
|
+
return task_counts
|
|
231
|
+
|
|
179
232
|
|
|
180
233
|
class SubmitDatasetMetadata(L1OutputDataBase):
|
|
181
234
|
"""
|
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Iterable
|
|
4
4
|
|
|
5
|
-
import numpy as np
|
|
6
|
-
|
|
7
5
|
from dkist_processing_common.codecs.json import json_encoder
|
|
8
6
|
from dkist_processing_common.codecs.quality import QualityValueEncoder
|
|
9
7
|
from dkist_processing_common.models.tags import Tag
|
|
10
8
|
from dkist_processing_common.models.task_name import TaskName
|
|
11
9
|
from dkist_processing_common.tasks.mixin.quality._metrics import _PolcalQualityMixin
|
|
12
10
|
from dkist_processing_common.tasks.mixin.quality._metrics import _SimplePlotQualityMixin
|
|
13
|
-
from dkist_processing_common.tasks.mixin.quality._metrics import _TableQualityMixin
|
|
14
11
|
from dkist_processing_common.tasks.mixin.quality._metrics import _WavecalQualityMixin
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
class QualityMixin(
|
|
18
15
|
_SimplePlotQualityMixin,
|
|
19
|
-
_TableQualityMixin,
|
|
20
16
|
_PolcalQualityMixin,
|
|
21
17
|
_WavecalQualityMixin,
|
|
22
18
|
):
|
|
@@ -64,7 +60,6 @@ class QualityMixin(
|
|
|
64
60
|
def quality_metrics_no_task_dependence(self) -> dict:
|
|
65
61
|
"""Return a dict of the quality metrics with no task dependence."""
|
|
66
62
|
return {
|
|
67
|
-
"TASK_TYPES": self.quality_build_task_type_counts,
|
|
68
63
|
"WAVECAL_FIT": self.quality_build_wavecal_results,
|
|
69
64
|
}
|
|
70
65
|
|
|
@@ -6,12 +6,7 @@ These classes should not be directly mixed in to anything. They are pre-mixed in
|
|
|
6
6
|
import copy
|
|
7
7
|
import json
|
|
8
8
|
import logging
|
|
9
|
-
from collections import defaultdict
|
|
10
9
|
from datetime import datetime
|
|
11
|
-
from functools import partial
|
|
12
|
-
from typing import Any
|
|
13
|
-
from typing import Iterable
|
|
14
|
-
from typing import Literal
|
|
15
10
|
from typing import Sequence
|
|
16
11
|
|
|
17
12
|
import astropy.units as u
|
|
@@ -67,85 +62,6 @@ class _SimplePlotQualityMixin:
|
|
|
67
62
|
return warnings
|
|
68
63
|
|
|
69
64
|
|
|
70
|
-
class _TableQualityMixin:
|
|
71
|
-
"""Mixing for metrics that present as tables."""
|
|
72
|
-
|
|
73
|
-
@staticmethod
|
|
74
|
-
def _create_table_metric(
|
|
75
|
-
name: str,
|
|
76
|
-
description: str,
|
|
77
|
-
metric_code: str,
|
|
78
|
-
rows: list[list[Any]],
|
|
79
|
-
statement: str | None = None,
|
|
80
|
-
warnings: list[str] | None = None,
|
|
81
|
-
facet: str | None = None,
|
|
82
|
-
) -> dict:
|
|
83
|
-
metric = ReportMetric(
|
|
84
|
-
name=name,
|
|
85
|
-
description=description,
|
|
86
|
-
metric_code=metric_code,
|
|
87
|
-
facet=facet,
|
|
88
|
-
statement=statement,
|
|
89
|
-
table_data=SimpleTable(rows=rows),
|
|
90
|
-
warnings=warnings,
|
|
91
|
-
)
|
|
92
|
-
return metric.model_dump()
|
|
93
|
-
|
|
94
|
-
def quality_store_task_type_counts(
|
|
95
|
-
self, task_type: str, total_frames: int, frames_not_used: int = 0
|
|
96
|
-
):
|
|
97
|
-
"""
|
|
98
|
-
Collect and store task type data.
|
|
99
|
-
|
|
100
|
-
Parameters
|
|
101
|
-
----------
|
|
102
|
-
task_type: task type as listed in the headers
|
|
103
|
-
total_frames: total number of frames supplied of the given task type
|
|
104
|
-
frames_not_used: if some frames aren't used, how many
|
|
105
|
-
"""
|
|
106
|
-
data = {
|
|
107
|
-
"task_type": task_type.upper(),
|
|
108
|
-
"total_frames": total_frames,
|
|
109
|
-
"frames_not_used": frames_not_used,
|
|
110
|
-
}
|
|
111
|
-
self._record_values(values=data, tags=Tag.quality(MetricCode.task_types))
|
|
112
|
-
|
|
113
|
-
def quality_build_task_type_counts(self) -> dict:
|
|
114
|
-
"""Build task type count schema from stored data."""
|
|
115
|
-
# Raise warning if more than 5% of frames of a given type are not used
|
|
116
|
-
warning_count_threshold = 0.05
|
|
117
|
-
default_int_dict = partial(defaultdict, int)
|
|
118
|
-
task_type_counts = defaultdict(default_int_dict)
|
|
119
|
-
# Loop over files that contain data for this metric
|
|
120
|
-
for path in self.read(tags=Tag.quality(MetricCode.task_types)):
|
|
121
|
-
with path.open() as f:
|
|
122
|
-
data = json.load(f)
|
|
123
|
-
task_type_counts[data["task_type"]]["total_frames"] += data["total_frames"]
|
|
124
|
-
task_type_counts[data["task_type"]]["frames_not_used"] += data["frames_not_used"]
|
|
125
|
-
|
|
126
|
-
# Now, build metric from the counts dict
|
|
127
|
-
table_data = [[i[0]] + list(i[1].values()) for i in task_type_counts.items()]
|
|
128
|
-
warnings = []
|
|
129
|
-
for row in table_data:
|
|
130
|
-
if row[1] == 0:
|
|
131
|
-
warnings.append(f"NO {row[0]} frames were used!")
|
|
132
|
-
elif row[2] / row[1] > warning_count_threshold:
|
|
133
|
-
warnings.append(
|
|
134
|
-
f"{round(100 * row[2] / row[1], 1)}% of frames were not used in the "
|
|
135
|
-
f"processing of task type {row[0]}"
|
|
136
|
-
)
|
|
137
|
-
# Add header row
|
|
138
|
-
table_data.insert(0, ["Task Type", "Total Frames", "Unused Frames"])
|
|
139
|
-
return self._create_table_metric(
|
|
140
|
-
name="Frame Counts",
|
|
141
|
-
description="This metric is a count of the number of frames used to produce a "
|
|
142
|
-
"calibrated L1 dataset",
|
|
143
|
-
metric_code=MetricCode.task_types,
|
|
144
|
-
rows=table_data,
|
|
145
|
-
warnings=self._format_warnings(warnings),
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
|
|
149
65
|
class _PolcalQualityMixin:
|
|
150
66
|
"""Mixin Class supporting the building of polcal-specific metrics."""
|
|
151
67
|
|
|
@@ -14,11 +14,13 @@ from dkist_quality.report import ReportMetric
|
|
|
14
14
|
from pandas import DataFrame
|
|
15
15
|
|
|
16
16
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
17
|
+
from dkist_processing_common.codecs.basemodel import basemodel_decoder
|
|
17
18
|
from dkist_processing_common.codecs.basemodel import basemodel_encoder
|
|
18
19
|
from dkist_processing_common.codecs.json import json_decoder
|
|
19
20
|
from dkist_processing_common.models.metric_code import MetricCode
|
|
20
21
|
from dkist_processing_common.models.quality import QualityMetric
|
|
21
22
|
from dkist_processing_common.models.quality import TableData
|
|
23
|
+
from dkist_processing_common.models.quality import TaskCount
|
|
22
24
|
from dkist_processing_common.models.quality import TimeSeriesData
|
|
23
25
|
from dkist_processing_common.models.quality import XYData
|
|
24
26
|
from dkist_processing_common.models.tags import Tag
|
|
@@ -76,12 +78,6 @@ def quality_metrics_old(dataframe_json) -> list[Metric]:
|
|
|
76
78
|
Quality metric data - this OLD FORMAT is being phased out
|
|
77
79
|
"""
|
|
78
80
|
metrics = [
|
|
79
|
-
Metric(
|
|
80
|
-
{"task_type": "dark", "total_frames": 100, "frames_not_used": 7}, ["QUALITY_TASK_TYPES"]
|
|
81
|
-
),
|
|
82
|
-
Metric(
|
|
83
|
-
{"task_type": "gain", "total_frames": 100, "frames_not_used": 0}, ["QUALITY_TASK_TYPES"]
|
|
84
|
-
),
|
|
85
81
|
Metric(
|
|
86
82
|
{
|
|
87
83
|
"param_names": ["foo"],
|
|
@@ -312,6 +308,23 @@ def quality_metrics() -> list[QualityMetric]:
|
|
|
312
308
|
statement=[f"{MetricCode.light_level} statement."],
|
|
313
309
|
description=f"{MetricCode.light_level} description.",
|
|
314
310
|
),
|
|
311
|
+
# TASK_TYPES
|
|
312
|
+
QualityMetric(
|
|
313
|
+
metric_code=MetricCode.task_types,
|
|
314
|
+
name=f"Frame Counts",
|
|
315
|
+
table_data=[
|
|
316
|
+
TableData(
|
|
317
|
+
rows=(
|
|
318
|
+
("Task Type", "Total Frames", "Unused Frames"),
|
|
319
|
+
("dark", "1000", "1"),
|
|
320
|
+
("gain", "1000", "0"),
|
|
321
|
+
("observe", "2000", "0"),
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
],
|
|
325
|
+
warnings=["Past performance does not guarantee future results."],
|
|
326
|
+
description=f"{MetricCode.task_types} description.",
|
|
327
|
+
),
|
|
315
328
|
]
|
|
316
329
|
return metrics
|
|
317
330
|
|
|
@@ -473,6 +486,28 @@ def warnings_expected() -> Callable[[str], bool]:
|
|
|
473
486
|
return expected
|
|
474
487
|
|
|
475
488
|
|
|
489
|
+
@pytest.fixture()
|
|
490
|
+
def assemble_quality_data_task_no_data(
|
|
491
|
+
recipe_run_id: int,
|
|
492
|
+
tmp_path: Path,
|
|
493
|
+
fake_constants_db,
|
|
494
|
+
) -> AssembleQualityData:
|
|
495
|
+
"""An instance of AssembleQualityData with no quality data."""
|
|
496
|
+
task = AssembleQualityData(
|
|
497
|
+
recipe_run_id=recipe_run_id,
|
|
498
|
+
workflow_name="assemble_quality",
|
|
499
|
+
workflow_version="assemble_quality_version",
|
|
500
|
+
)
|
|
501
|
+
scratch = WorkflowFileSystem(
|
|
502
|
+
recipe_run_id=recipe_run_id,
|
|
503
|
+
scratch_base_path=tmp_path,
|
|
504
|
+
)
|
|
505
|
+
task.scratch = scratch
|
|
506
|
+
task.constants._update(fake_constants_db)
|
|
507
|
+
yield task
|
|
508
|
+
task._purge()
|
|
509
|
+
|
|
510
|
+
|
|
476
511
|
@pytest.fixture()
|
|
477
512
|
def scratch_with_quality_metrics(
|
|
478
513
|
recipe_run_id: int,
|
|
@@ -498,11 +533,10 @@ def scratch_with_quality_metrics(
|
|
|
498
533
|
|
|
499
534
|
@pytest.fixture()
|
|
500
535
|
def assemble_quality_data_task(
|
|
501
|
-
recipe_run_id,
|
|
502
|
-
tmp_path,
|
|
536
|
+
recipe_run_id: int,
|
|
537
|
+
tmp_path: Path,
|
|
503
538
|
scratch_with_quality_metrics,
|
|
504
539
|
fake_constants_db,
|
|
505
|
-
quality_metrics: list[QualityMetric],
|
|
506
540
|
) -> AssembleQualityData:
|
|
507
541
|
"""An instance of AssembleQualityData with tagged quality metrics."""
|
|
508
542
|
task = AssembleQualityData(
|
|
@@ -518,7 +552,7 @@ def assemble_quality_data_task(
|
|
|
518
552
|
|
|
519
553
|
@pytest.fixture()
|
|
520
554
|
def assemble_quality_data_for_polcal_task(
|
|
521
|
-
recipe_run_id, tmp_path, scratch_with_quality_metrics, fake_constants_db
|
|
555
|
+
recipe_run_id: int, tmp_path: Path, scratch_with_quality_metrics, fake_constants_db
|
|
522
556
|
) -> AssembleQualityData:
|
|
523
557
|
"""An instance of AssembleQualityData with tagged quality metrics and configured to process PolCal."""
|
|
524
558
|
|
|
@@ -639,3 +673,219 @@ def test_assemble_quality_data_for_polcal(
|
|
|
639
673
|
assert rm.statement
|
|
640
674
|
if warnings_expected(rm.name):
|
|
641
675
|
assert rm.warnings
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
@pytest.mark.parametrize(
|
|
679
|
+
"input_task_counts, expected_metric_count, expected_task_count, expected_warning_count",
|
|
680
|
+
[
|
|
681
|
+
pytest.param([], 0, 0, 0, id="no_tasks"),
|
|
682
|
+
pytest.param(
|
|
683
|
+
[
|
|
684
|
+
TaskCount(
|
|
685
|
+
task_type="one",
|
|
686
|
+
total_frames=100,
|
|
687
|
+
),
|
|
688
|
+
],
|
|
689
|
+
1,
|
|
690
|
+
1,
|
|
691
|
+
0,
|
|
692
|
+
id="one_task",
|
|
693
|
+
),
|
|
694
|
+
pytest.param(
|
|
695
|
+
[
|
|
696
|
+
TaskCount(
|
|
697
|
+
task_type="one",
|
|
698
|
+
total_frames=100,
|
|
699
|
+
frames_not_used=6,
|
|
700
|
+
),
|
|
701
|
+
TaskCount(
|
|
702
|
+
task_type="two",
|
|
703
|
+
total_frames=200,
|
|
704
|
+
frames_not_used=10,
|
|
705
|
+
),
|
|
706
|
+
TaskCount(
|
|
707
|
+
task_type="three",
|
|
708
|
+
total_frames=300,
|
|
709
|
+
frames_not_used=16,
|
|
710
|
+
),
|
|
711
|
+
],
|
|
712
|
+
1,
|
|
713
|
+
3,
|
|
714
|
+
2,
|
|
715
|
+
id="three_tasks_two_outer_warnings",
|
|
716
|
+
),
|
|
717
|
+
pytest.param(
|
|
718
|
+
[
|
|
719
|
+
TaskCount(
|
|
720
|
+
task_type="one",
|
|
721
|
+
total_frames=100,
|
|
722
|
+
frames_not_used=5,
|
|
723
|
+
),
|
|
724
|
+
TaskCount(
|
|
725
|
+
task_type="two",
|
|
726
|
+
total_frames=200,
|
|
727
|
+
frames_not_used=11,
|
|
728
|
+
),
|
|
729
|
+
TaskCount(
|
|
730
|
+
task_type="three",
|
|
731
|
+
total_frames=300,
|
|
732
|
+
frames_not_used=16,
|
|
733
|
+
),
|
|
734
|
+
TaskCount(
|
|
735
|
+
task_type="four",
|
|
736
|
+
total_frames=400,
|
|
737
|
+
frames_not_used=20,
|
|
738
|
+
),
|
|
739
|
+
],
|
|
740
|
+
1,
|
|
741
|
+
4,
|
|
742
|
+
2,
|
|
743
|
+
id="four_tasks_two_inner_warnings",
|
|
744
|
+
),
|
|
745
|
+
],
|
|
746
|
+
)
|
|
747
|
+
def test_compute_and_write_type_counts(
|
|
748
|
+
input_task_counts,
|
|
749
|
+
expected_metric_count: int,
|
|
750
|
+
expected_task_count: int,
|
|
751
|
+
expected_warning_count: int,
|
|
752
|
+
assemble_quality_data_task_no_data: AssembleQualityData,
|
|
753
|
+
):
|
|
754
|
+
"""
|
|
755
|
+
Given: valid TaskCount files in scratch
|
|
756
|
+
When: executing AssembleQualityData.compute_and_write_type_counts()
|
|
757
|
+
Then: writes one FRAME_AVERAGE QualityMetric for each task type
|
|
758
|
+
Then: writes one TASK_TYPES QualityMetric
|
|
759
|
+
"""
|
|
760
|
+
# Given
|
|
761
|
+
task = assemble_quality_data_task_no_data
|
|
762
|
+
for task_count in input_task_counts:
|
|
763
|
+
task.write(task_count, tags="QUALITY_TASK_TYPES", encoder=basemodel_encoder)
|
|
764
|
+
|
|
765
|
+
# When
|
|
766
|
+
task.compute_and_write_type_counts()
|
|
767
|
+
|
|
768
|
+
# Then
|
|
769
|
+
tags = [Tag.quality("GENERIC")]
|
|
770
|
+
metrics: list[QualityMetric] = list(
|
|
771
|
+
task.read(tags=tags, decoder=basemodel_decoder, model=QualityMetric)
|
|
772
|
+
)
|
|
773
|
+
assert len(metrics) == expected_metric_count
|
|
774
|
+
|
|
775
|
+
if expected_metric_count == 0:
|
|
776
|
+
# nothing to inspect
|
|
777
|
+
return
|
|
778
|
+
|
|
779
|
+
metric = metrics[0]
|
|
780
|
+
# basics
|
|
781
|
+
assert metric.metric_code == "TASK_TYPES"
|
|
782
|
+
assert metric.facet is None
|
|
783
|
+
assert metric.name == "Frame Counts"
|
|
784
|
+
assert metric.description.startswith(
|
|
785
|
+
"This metric is a count of the number of frames used to produce"
|
|
786
|
+
)
|
|
787
|
+
assert metric.statement is None
|
|
788
|
+
all_warnings = metric.warnings
|
|
789
|
+
if expected_warning_count:
|
|
790
|
+
assert isinstance(all_warnings, list)
|
|
791
|
+
assert len(all_warnings) == expected_warning_count
|
|
792
|
+
for warning in all_warnings:
|
|
793
|
+
assert "% of frames were not used in the processing of task type" in warning
|
|
794
|
+
for task_count in input_task_counts:
|
|
795
|
+
# check that each out of tolerance task generated a warning
|
|
796
|
+
if task_count.frames_not_used / task_count.total_frames > 0.05:
|
|
797
|
+
assert any(task_count.task_type in w for w in all_warnings)
|
|
798
|
+
else:
|
|
799
|
+
assert all_warnings is None
|
|
800
|
+
# data
|
|
801
|
+
all_table_data = metric.table_data
|
|
802
|
+
assert all_table_data
|
|
803
|
+
assert isinstance(all_table_data, list)
|
|
804
|
+
assert len(all_table_data) == 1
|
|
805
|
+
table_data = all_table_data[0]
|
|
806
|
+
assert isinstance(table_data, TableData)
|
|
807
|
+
rows = table_data.rows
|
|
808
|
+
assert isinstance(rows, tuple)
|
|
809
|
+
assert len(rows) == expected_task_count + 1
|
|
810
|
+
header = rows[0]
|
|
811
|
+
assert header[0] == "Task Type"
|
|
812
|
+
assert header[1] == "Total Frames"
|
|
813
|
+
assert header[2] == "Unused Frames"
|
|
814
|
+
# make sure each task got included in the table
|
|
815
|
+
for task_count in input_task_counts:
|
|
816
|
+
assert any(row[0] == task_count.task_type for row in rows[1:])
|
|
817
|
+
for row in rows[1:]:
|
|
818
|
+
# get the specific task associated with this specific row
|
|
819
|
+
input_task_count = next((it for it in input_task_counts if it.task_type == row[0]))
|
|
820
|
+
# now make sure the other attributes match
|
|
821
|
+
assert row[1] == str(input_task_count.total_frames)
|
|
822
|
+
assert row[2] == str(input_task_count.frames_not_used)
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
@pytest.mark.parametrize(
|
|
826
|
+
"input_task_counts",
|
|
827
|
+
[
|
|
828
|
+
pytest.param([], id="no_tasks"),
|
|
829
|
+
pytest.param(
|
|
830
|
+
[
|
|
831
|
+
TaskCount(
|
|
832
|
+
task_type="one",
|
|
833
|
+
total_frames=100,
|
|
834
|
+
),
|
|
835
|
+
],
|
|
836
|
+
id="one_task",
|
|
837
|
+
),
|
|
838
|
+
pytest.param(
|
|
839
|
+
[
|
|
840
|
+
TaskCount(
|
|
841
|
+
task_type="one",
|
|
842
|
+
total_frames=100,
|
|
843
|
+
frames_not_used=6,
|
|
844
|
+
),
|
|
845
|
+
TaskCount(
|
|
846
|
+
task_type="two",
|
|
847
|
+
total_frames=200,
|
|
848
|
+
frames_not_used=10,
|
|
849
|
+
),
|
|
850
|
+
TaskCount(
|
|
851
|
+
task_type="three",
|
|
852
|
+
total_frames=300,
|
|
853
|
+
frames_not_used=16,
|
|
854
|
+
),
|
|
855
|
+
],
|
|
856
|
+
id="three_tasks",
|
|
857
|
+
),
|
|
858
|
+
],
|
|
859
|
+
)
|
|
860
|
+
def test_read_intermediate_task_type_counts(
|
|
861
|
+
input_task_counts: list[TaskCount],
|
|
862
|
+
assemble_quality_data_task_no_data: AssembleQualityData,
|
|
863
|
+
):
|
|
864
|
+
"""
|
|
865
|
+
Given: valid TaskCount files in scratch
|
|
866
|
+
When: executing AssembleQualityData.quality_read_intermediate_task_type_counts()
|
|
867
|
+
Then: returns one TASK_TYPES file for each TaskCount
|
|
868
|
+
"""
|
|
869
|
+
# Given
|
|
870
|
+
task = assemble_quality_data_task_no_data
|
|
871
|
+
for task_count in input_task_counts:
|
|
872
|
+
task.write(task_count, tags="QUALITY_TASK_TYPES", encoder=basemodel_encoder)
|
|
873
|
+
expected_task_count = len(input_task_counts)
|
|
874
|
+
|
|
875
|
+
# When
|
|
876
|
+
returned_task_counts: list[TaskCount] = task.quality_read_intermediate_task_type_counts()
|
|
877
|
+
|
|
878
|
+
# Then
|
|
879
|
+
assert isinstance(returned_task_counts, list)
|
|
880
|
+
assert len(returned_task_counts) == expected_task_count
|
|
881
|
+
# make sure each task got returned
|
|
882
|
+
for task_count in input_task_counts:
|
|
883
|
+
assert any(rt.task_type == task_count.task_type for rt in returned_task_counts)
|
|
884
|
+
for task_count in returned_task_counts:
|
|
885
|
+
# get the specific input task associated with this one
|
|
886
|
+
input_task_count = next(
|
|
887
|
+
(it for it in input_task_counts if it.task_type == task_count.task_type)
|
|
888
|
+
)
|
|
889
|
+
# now make sure the other attributes match
|
|
890
|
+
assert task_count.total_frames == input_task_count.total_frames
|
|
891
|
+
assert task_count.frames_not_used == input_task_count.frames_not_used
|
|
@@ -97,56 +97,6 @@ def test_find_iqr_outliers(quality_mixin_task):
|
|
|
97
97
|
]
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def test_create_table_metric(quality_mixin_task):
|
|
101
|
-
"""
|
|
102
|
-
Given: a task with the QualityMixin
|
|
103
|
-
When: submitting data to create a table metric
|
|
104
|
-
Then: the metric is encoded with the expected schema
|
|
105
|
-
"""
|
|
106
|
-
task = quality_mixin_task
|
|
107
|
-
name = "table metric"
|
|
108
|
-
description = "table metric description"
|
|
109
|
-
metric_code = "TEST_METRIC"
|
|
110
|
-
rows = [["a", 1], ["b", 2], ["c", 3]]
|
|
111
|
-
statement = "table statement"
|
|
112
|
-
warnings = ["table warning"]
|
|
113
|
-
table_metric = task._create_table_metric(
|
|
114
|
-
name=name,
|
|
115
|
-
description=description,
|
|
116
|
-
rows=rows,
|
|
117
|
-
metric_code=metric_code,
|
|
118
|
-
statement=statement,
|
|
119
|
-
warnings=warnings,
|
|
120
|
-
)
|
|
121
|
-
assert table_metric["name"] == name
|
|
122
|
-
assert table_metric["description"] == description
|
|
123
|
-
assert table_metric["metric_code"] == metric_code
|
|
124
|
-
assert table_metric["facet"] is None
|
|
125
|
-
assert table_metric["statement"] == statement
|
|
126
|
-
assert table_metric["table_data"] == {"header_column": False, "header_row": True, "rows": rows}
|
|
127
|
-
assert table_metric["warnings"] == warnings
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def test_build_task_type_counts(quality_mixin_task):
|
|
131
|
-
"""
|
|
132
|
-
Given: a task with the QualityMixin
|
|
133
|
-
When: writing multiple task type count data elements
|
|
134
|
-
Then: a schema is built containing all elements
|
|
135
|
-
"""
|
|
136
|
-
task = quality_mixin_task
|
|
137
|
-
task.quality_store_task_type_counts(task_type="dark", total_frames=109, frames_not_used=0)
|
|
138
|
-
task.quality_store_task_type_counts(task_type="gain", total_frames=276, frames_not_used=58)
|
|
139
|
-
task.quality_store_task_type_counts(task_type="foo", total_frames=0, frames_not_used=0)
|
|
140
|
-
path = list(task.read(tags=Tag.quality("TASK_TYPES")))
|
|
141
|
-
assert len(path) == 3
|
|
142
|
-
metric = task.quality_build_task_type_counts()
|
|
143
|
-
assert metric["name"] == "Frame Counts"
|
|
144
|
-
assert metric["metric_code"] == "TASK_TYPES"
|
|
145
|
-
assert metric["facet"] is None
|
|
146
|
-
assert "21.0% of frames were not used in the processing of task type GAIN" in metric["warnings"]
|
|
147
|
-
assert "NO FOO frames were used!" in metric["warnings"]
|
|
148
|
-
|
|
149
|
-
|
|
150
100
|
@pytest.mark.parametrize(
|
|
151
101
|
"thin, samples_larger_than_total",
|
|
152
102
|
[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dkist_processing_common-14.0.1 → dkist_processing_common-14.0.2}/dkist_processing_common/manual.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|