dkist-processing-vbi 1.25.2__tar.gz → 1.25.3__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 (80) hide show
  1. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/CHANGELOG.rst +9 -0
  2. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/PKG-INFO +5 -5
  3. dkist_processing_vbi-1.25.3/dkist_processing_vbi/models/fits_access.py +13 -0
  4. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/parsers/spatial_step_pattern.py +2 -1
  5. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/parsers/vbi_l0_fits_access.py +9 -5
  6. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/parsers/vbi_l1_fits_access.py +4 -2
  7. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/parse.py +5 -3
  8. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/write_l1.py +11 -6
  9. dkist_processing_vbi-1.25.3/dkist_processing_vbi/tests/test_fits_access.py +41 -0
  10. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_make_movie_frames.py +6 -4
  11. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_write_l1.py +19 -14
  12. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi.egg-info/PKG-INFO +5 -5
  13. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi.egg-info/SOURCES.txt +2 -0
  14. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi.egg-info/requires.txt +4 -4
  15. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/pyproject.toml +6 -6
  16. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/.gitignore +0 -0
  17. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/.pre-commit-config.yaml +0 -0
  18. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/.readthedocs.yml +0 -0
  19. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/.snyk +0 -0
  20. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/README.rst +0 -0
  21. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/SCIENCE_CHANGELOG.rst +0 -0
  22. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/bitbucket-pipelines.yml +0 -0
  23. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/changelog/.gitempty +0 -0
  24. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/__init__.py +0 -0
  25. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/config.py +0 -0
  26. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/models/__init__.py +0 -0
  27. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/models/constants.py +0 -0
  28. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/models/filter.py +0 -0
  29. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/models/parameters.py +0 -0
  30. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/models/tags.py +0 -0
  31. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/parsers/__init__.py +0 -0
  32. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/parsers/mosaic_repeats.py +0 -0
  33. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/__init__.py +0 -0
  34. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/assemble_movie.py +0 -0
  35. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/dark.py +0 -0
  36. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/gain.py +0 -0
  37. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/make_movie_frames.py +0 -0
  38. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/process_summit_processed.py +0 -0
  39. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/quality_metrics.py +0 -0
  40. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/science.py +0 -0
  41. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tasks/vbi_base.py +0 -0
  42. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/__init__.py +0 -0
  43. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/conftest.py +0 -0
  44. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/local_trial_workflows/__init__.py +0 -0
  45. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/local_trial_workflows/l0_to_l1.py +0 -0
  46. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_assemble_movie.py +0 -0
  47. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_dark.py +0 -0
  48. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_gain.py +0 -0
  49. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_parse_l0.py +0 -0
  50. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_parse_summit.py +0 -0
  51. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_process_summit.py +0 -0
  52. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_quality_metrics.py +0 -0
  53. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_science.py +0 -0
  54. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_spatial_step_pattern.py +0 -0
  55. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_vbi_base.py +0 -0
  56. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_vbi_constants.py +0 -0
  57. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/tests/test_workflows.py +0 -0
  58. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/workflows/__init__.py +0 -0
  59. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/workflows/l0_processing.py +0 -0
  60. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/workflows/summit_data_processing.py +0 -0
  61. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi/workflows/trial_workflows.py +0 -0
  62. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi.egg-info/dependency_links.txt +0 -0
  63. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/dkist_processing_vbi.egg-info/top_level.txt +0 -0
  64. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/Makefile +0 -0
  65. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/changelog.rst +0 -0
  66. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/conf.py +0 -0
  67. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/index.rst +0 -0
  68. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/l0_to_l1_vbi_no-speckle-full-trial.rst +0 -0
  69. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/l0_to_l1_vbi_no-speckle.rst +0 -0
  70. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/l0_to_l1_vbi_summit-calibrated-full-trial.rst +0 -0
  71. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/l0_to_l1_vbi_summit-calibrated.rst +0 -0
  72. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/landing_page.rst +0 -0
  73. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/make.bat +0 -0
  74. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/requirements.txt +0 -0
  75. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/requirements_table.rst +0 -0
  76. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/docs/scientific_changelog.rst +0 -0
  77. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/licenses/LICENSE.rst +0 -0
  78. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/science_towncrier.sh +0 -0
  79. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/setup.cfg +0 -0
  80. {dkist_processing_vbi-1.25.2 → dkist_processing_vbi-1.25.3}/towncrier_science.toml +0 -0
@@ -1,3 +1,12 @@
1
+ v1.25.3 (2025-11-04)
2
+ ====================
3
+
4
+ Misc
5
+ ----
6
+
7
+ - Replace metadata key strings with members of the string enum VbiMetadataKey. (`#152 <https://bitbucket.org/dkistdc/dkist-processing-vbi/pull-requests/152>`__)
8
+
9
+
1
10
  v1.25.2 (2025-11-03)
2
11
  ====================
3
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-vbi
3
- Version: 1.25.2
3
+ Version: 1.25.3
4
4
  Summary: Processing code for the VBI instrument on DKIST
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -68,6 +68,7 @@ Requires-Dist: Flask-Login==0.6.3; extra == "frozen"
68
68
  Requires-Dist: Flask-SQLAlchemy==2.5.1; extra == "frozen"
69
69
  Requires-Dist: Flask-Session==0.5.0; extra == "frozen"
70
70
  Requires-Dist: Flask-WTF==1.2.2; extra == "frozen"
71
+ Requires-Dist: ImageIO==2.37.2; extra == "frozen"
71
72
  Requires-Dist: Jinja2==3.1.6; extra == "frozen"
72
73
  Requires-Dist: Mako==1.3.10; extra == "frozen"
73
74
  Requires-Dist: MarkupSafe==3.0.3; extra == "frozen"
@@ -115,8 +116,8 @@ Requires-Dist: attrs==25.4.0; extra == "frozen"
115
116
  Requires-Dist: babel==2.17.0; extra == "frozen"
116
117
  Requires-Dist: billiard==4.2.2; extra == "frozen"
117
118
  Requires-Dist: blinker==1.9.0; extra == "frozen"
118
- Requires-Dist: boto3==1.40.64; extra == "frozen"
119
- Requires-Dist: botocore==1.40.64; extra == "frozen"
119
+ Requires-Dist: boto3==1.40.65; extra == "frozen"
120
+ Requires-Dist: botocore==1.40.65; extra == "frozen"
120
121
  Requires-Dist: cachelib==0.13.0; extra == "frozen"
121
122
  Requires-Dist: celery==5.3.1; extra == "frozen"
122
123
  Requires-Dist: certifi==2025.10.5; extra == "frozen"
@@ -143,7 +144,7 @@ Requires-Dist: dkist-processing-common==11.8.0; extra == "frozen"
143
144
  Requires-Dist: dkist-processing-core==6.0.0; extra == "frozen"
144
145
  Requires-Dist: dkist-processing-math==2.2.1; extra == "frozen"
145
146
  Requires-Dist: dkist-processing-pac==3.1.1; extra == "frozen"
146
- Requires-Dist: dkist-processing-vbi==1.25.2; extra == "frozen"
147
+ Requires-Dist: dkist-processing-vbi==1.25.3; extra == "frozen"
147
148
  Requires-Dist: dkist-service-configuration==4.1.7; extra == "frozen"
148
149
  Requires-Dist: dkist-spectral-lines==3.0.0; extra == "frozen"
149
150
  Requires-Dist: dkist_fits_specifications==4.17.0; extra == "frozen"
@@ -166,7 +167,6 @@ Requires-Dist: httpcore==1.0.9; extra == "frozen"
166
167
  Requires-Dist: httpx==0.28.1; extra == "frozen"
167
168
  Requires-Dist: humanize==4.14.0; extra == "frozen"
168
169
  Requires-Dist: idna==3.11; extra == "frozen"
169
- Requires-Dist: imageio==2.37.0; extra == "frozen"
170
170
  Requires-Dist: imageio-ffmpeg==0.6.0; extra == "frozen"
171
171
  Requires-Dist: importlib_metadata==8.7.0; extra == "frozen"
172
172
  Requires-Dist: inflection==0.5.1; extra == "frozen"
@@ -0,0 +1,13 @@
1
+ """VBI control of FITS key names and values."""
2
+
3
+ from enum import StrEnum
4
+
5
+
6
+ class VbiMetadataKey(StrEnum):
7
+ """Controlled list of names for FITS metadata header keys."""
8
+
9
+ spatial_step_pattern = "VBISTPAT"
10
+ number_of_spatial_steps = "VBINSTP"
11
+ current_spatial_step = "VBISTP"
12
+ number_of_exp_per_mosaic_step = "VBINFRAM"
13
+ current_mosaic_step_exp = "VBICFRAM"
@@ -4,6 +4,7 @@ from dkist_processing_common.models.task_name import TaskName
4
4
  from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
5
5
 
6
6
  from dkist_processing_vbi.models.constants import VbiBudName
7
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
7
8
 
8
9
 
9
10
  class SpatialStepPatternBud(TaskUniqueBud):
@@ -23,7 +24,7 @@ class SpatialStepPatternBud(TaskUniqueBud):
23
24
  def __init__(self):
24
25
  super().__init__(
25
26
  constant_name=VbiBudName.spatial_step_pattern.value,
26
- metadata_key="spatial_step_pattern",
27
+ metadata_key=VbiMetadataKey.spatial_step_pattern,
27
28
  ip_task_types=TaskName.observe.value,
28
29
  )
29
30
 
@@ -3,6 +3,8 @@
3
3
  from astropy.io import fits
4
4
  from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
5
5
 
6
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
7
+
6
8
 
7
9
  class VbiL0FitsAccess(L0FitsAccess):
8
10
  """
@@ -30,8 +32,10 @@ class VbiL0FitsAccess(L0FitsAccess):
30
32
  ):
31
33
  super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
32
34
 
33
- self.spatial_step_pattern: str = self.header["VBISTPAT"]
34
- self.number_of_spatial_steps: int = self.header.get("VBINSTP")
35
- self.current_spatial_step: int = self.header.get("VBISTP")
36
- self.number_of_exp_per_mosaic_step: int = self.header.get("VBINFRAM")
37
- self.current_mosaic_step_exp: int = self.header.get("VBICFRAM")
35
+ self.spatial_step_pattern: str = self.header[VbiMetadataKey.spatial_step_pattern]
36
+ self.number_of_spatial_steps: int = self.header.get(VbiMetadataKey.number_of_spatial_steps)
37
+ self.current_spatial_step: int = self.header.get(VbiMetadataKey.current_spatial_step)
38
+ self.number_of_exp_per_mosaic_step: int = self.header.get(
39
+ VbiMetadataKey.number_of_exp_per_mosaic_step
40
+ )
41
+ self.current_mosaic_step_exp: int = self.header.get(VbiMetadataKey.current_mosaic_step_exp)
@@ -3,6 +3,8 @@
3
3
  from astropy.io import fits
4
4
  from dkist_processing_common.parsers.l1_fits_access import L1FitsAccess
5
5
 
6
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
7
+
6
8
 
7
9
  class VbiL1FitsAccess(L1FitsAccess):
8
10
  """
@@ -30,5 +32,5 @@ class VbiL1FitsAccess(L1FitsAccess):
30
32
  ):
31
33
  super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
32
34
 
33
- self.number_of_spatial_steps: int = self.header.get("VBINSTP")
34
- self.current_spatial_step: int = self.header.get("VBISTP")
35
+ self.number_of_spatial_steps: int = self.header.get(VbiMetadataKey.number_of_spatial_steps)
36
+ self.current_spatial_step: int = self.header.get(VbiMetadataKey.current_spatial_step)
@@ -1,5 +1,6 @@
1
1
  """VBI parse task."""
2
2
 
3
+ from dkist_processing_common.models.fits_access import MetadataKey
3
4
  from dkist_processing_common.models.tags import StemName
4
5
  from dkist_processing_common.models.task_name import TaskName
5
6
  from dkist_processing_common.parsers.single_value_single_key_flower import (
@@ -13,6 +14,7 @@ from dkist_processing_common.tasks import ParseL0InputDataBase
13
14
  from dkist_processing_common.tasks.parse_l0_input_data import S
14
15
 
15
16
  from dkist_processing_vbi.models.constants import VbiBudName
17
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
16
18
  from dkist_processing_vbi.models.tags import VbiStemName
17
19
  from dkist_processing_vbi.parsers.mosaic_repeats import MosaicRepeatNumberFlower
18
20
  from dkist_processing_vbi.parsers.mosaic_repeats import TotalMosaicRepeatsBud
@@ -50,7 +52,7 @@ class ParseL0VbiInputData(ParseL0InputDataBase):
50
52
  return super().constant_buds + [
51
53
  UniqueBud(
52
54
  constant_name=VbiBudName.num_spatial_steps.value,
53
- metadata_key="number_of_spatial_steps",
55
+ metadata_key=VbiMetadataKey.number_of_spatial_steps,
54
56
  ),
55
57
  SpatialStepPatternBud(),
56
58
  ObsIpStartTimeBud(),
@@ -69,10 +71,10 @@ class ParseL0VbiInputData(ParseL0InputDataBase):
69
71
  return super().tag_flowers + [
70
72
  SingleValueSingleKeyFlower(
71
73
  tag_stem_name=VbiStemName.current_spatial_step.value,
72
- metadata_key="current_spatial_step",
74
+ metadata_key=VbiMetadataKey.current_spatial_step,
73
75
  ),
74
76
  SingleValueSingleKeyFlower(
75
- tag_stem_name=StemName.task.value, metadata_key="ip_task_type"
77
+ tag_stem_name=StemName.task.value, metadata_key=MetadataKey.ip_task_type
76
78
  ),
77
79
  MosaicRepeatNumberFlower(),
78
80
  ExposureTimeFlower(),
@@ -9,6 +9,7 @@ from astropy.io import fits
9
9
  from astropy.time import Time
10
10
  from astropy.time import TimeDelta
11
11
  from dkist_processing_common.models.constants import ConstantsBase
12
+ from dkist_processing_common.models.fits_access import MetadataKey
12
13
  from dkist_processing_common.tasks.write_l1 import WavelengthRange
13
14
  from dkist_processing_common.tasks.write_l1 import WriteL1Frame
14
15
  from dkist_service_configuration.logging import logger
@@ -19,6 +20,8 @@ from dkist_processing_vbi.models.filter import find_associated_filter
19
20
 
20
21
  __all__ = ["VbiWriteL1Frame"]
21
22
 
23
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
24
+
22
25
 
23
26
  class VbiWriteL1Frame(WriteL1Frame):
24
27
  """
@@ -85,7 +88,7 @@ class VbiWriteL1Frame(WriteL1Frame):
85
88
 
86
89
  # ---Temporal---
87
90
  if self.constants.num_mosaic_repeats > 1:
88
- num_exp_per_dsp = header["VBINFRAM"]
91
+ num_exp_per_dsp = header[VbiMetadataKey.number_of_exp_per_mosaic_step]
89
92
  header["DNAXIS3"] = self.constants.num_mosaic_repeats * num_exp_per_dsp
90
93
  header["DTYPE3"] = "TEMPORAL"
91
94
  header["DPNAME3"] = "time"
@@ -93,7 +96,7 @@ class VbiWriteL1Frame(WriteL1Frame):
93
96
  header["DUNIT3"] = "s"
94
97
  # Temporal position in dataset
95
98
  current_mosaic_number = header["VBICMOSC"]
96
- current_exposure = header["VBICFRAM"]
99
+ current_exposure = header[VbiMetadataKey.current_mosaic_step_exp]
97
100
  header["DINDEX3"] = (current_mosaic_number - 1) * num_exp_per_dsp + current_exposure
98
101
 
99
102
  # ---Wavelength Info---
@@ -101,8 +104,8 @@ class VbiWriteL1Frame(WriteL1Frame):
101
104
  header["WAVEREF"] = "Air"
102
105
 
103
106
  # --- Mosaic ---
104
- number_of_spatial_steps = int(header["VBINSTP"])
105
- current_step = int(header["VBISTP"])
107
+ number_of_spatial_steps = int(header[VbiMetadataKey.number_of_spatial_steps])
108
+ current_step = int(header[VbiMetadataKey.current_spatial_step])
106
109
  if number_of_spatial_steps not in [1, 4, 5, 9]: # not a known number of spatial steps
107
110
  raise ValueError(
108
111
  f"Mosaic grid must be a known configuration (steps in 1, 4, 5, 9). "
@@ -151,7 +154,9 @@ class VbiWriteL1Frame(WriteL1Frame):
151
154
  """
152
155
  return (
153
156
  Time(header["DATE-BEG"], format="isot", precision=6)
154
- + TimeDelta(float(header["TEXPOSUR"]) / 1000, format="sec")
157
+ + TimeDelta(
158
+ float(header[MetadataKey.sensor_readout_exposure_time_ms]) / 1000, format="sec"
159
+ )
155
160
  ).to_value("isot")
156
161
 
157
162
  def get_wavelength_range(self, header: fits.Header) -> WavelengthRange:
@@ -160,7 +165,7 @@ class VbiWriteL1Frame(WriteL1Frame):
160
165
 
161
166
  Range is the wavelengths at the edges of the filter bandpass.
162
167
  """
163
- vbi_filter = find_associated_filter(wavelength=header["LINEWAV"] * u.nm)
168
+ vbi_filter = find_associated_filter(wavelength=header[MetadataKey.wavelength] * u.nm)
164
169
  return WavelengthRange(min=vbi_filter.min, max=vbi_filter.max)
165
170
 
166
171
  def get_waveband(self, wavelength: u.Quantity, wavelength_range: WavelengthRange) -> str:
@@ -0,0 +1,41 @@
1
+ import pytest
2
+ from astropy.io import fits
3
+ from dkist_header_validator import spec122_validator
4
+
5
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
6
+ from dkist_processing_vbi.parsers.vbi_l0_fits_access import VbiL0FitsAccess
7
+ from dkist_processing_vbi.parsers.vbi_l1_fits_access import VbiL1FitsAccess
8
+ from dkist_processing_vbi.tests.conftest import Vbi122ObserveFrames
9
+
10
+
11
+ @pytest.fixture(scope="function")
12
+ def header():
13
+ ds = Vbi122ObserveFrames(array_shape=(1, 2, 2), num_steps=1)
14
+ header_list = [
15
+ spec122_validator.validate_and_translate_to_214_l0(d.header(), return_type=fits.HDUList)[
16
+ 0
17
+ ].header
18
+ for d in ds
19
+ ]
20
+ return header_list[0]
21
+
22
+
23
+ def test_metadata_keys_in_access_bases(header):
24
+ """
25
+ Given: the set of metadata key names in VbiMetadataKey
26
+ When: the VBI FITS access classes define a set of new attributes
27
+ Then: the sets are the same the attributes have the correct values
28
+ """
29
+ vbi_metadata_key_names = {vmk.name for vmk in VbiMetadataKey}
30
+ all_vbi_fits_access_attrs = set()
31
+ for access_class in [VbiL0FitsAccess, VbiL1FitsAccess]:
32
+ fits_obj = access_class.from_header(header)
33
+ vbi_instance_attrs = set(vars(fits_obj).keys())
34
+ parent_class = access_class.mro()[1]
35
+ parent_fits_obj = parent_class.from_header(header)
36
+ parent_instance_attrs = set(vars(parent_fits_obj).keys())
37
+ vbi_fits_access_attrs = vbi_instance_attrs - parent_instance_attrs
38
+ for attr in vbi_fits_access_attrs:
39
+ assert getattr(fits_obj, attr) == fits_obj.header[VbiMetadataKey[attr]]
40
+ all_vbi_fits_access_attrs |= vbi_fits_access_attrs
41
+ assert vbi_metadata_key_names == all_vbi_fits_access_attrs
@@ -9,8 +9,10 @@ from dkist_processing_common.codecs.fits import fits_access_decoder
9
9
  from dkist_processing_common.codecs.fits import fits_array_decoder
10
10
  from dkist_processing_common.codecs.fits import fits_hdulist_encoder
11
11
  from dkist_processing_common.models.fits_access import FitsAccessBase
12
+ from dkist_processing_common.models.fits_access import MetadataKey
12
13
 
13
14
  from dkist_processing_vbi.models.constants import VbiConstants
15
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
14
16
  from dkist_processing_vbi.models.tags import VbiTag
15
17
  from dkist_processing_vbi.parsers.vbi_l1_fits_access import VbiL1FitsAccess
16
18
  from dkist_processing_vbi.tasks.make_movie_frames import MakeVbiMovieFrames
@@ -57,8 +59,8 @@ def raw_make_movie_frames_task(tmp_path, recipe_run_id, init_vbi_constants_db):
57
59
  hdl[1].header["CDELT2"] = 1.0
58
60
  hdl[1].header["CRPIX1"] = (s % 2) * 7
59
61
  hdl[1].header["CRPIX2"] = -1 * ((s - 1) // 2 - 1) * 7
60
- hdl[1].header["DSPSNUM"] = m
61
- hdl[1].header["VBISTP"] = s
62
+ hdl[1].header[MetadataKey.current_dsps_repeat] = m
63
+ hdl[1].header[VbiMetadataKey.current_spatial_step] = s
62
64
  task.write(
63
65
  data=hdl,
64
66
  tags=[
@@ -116,8 +118,8 @@ def make_movie_frames_task_with_averages(tmp_path_factory):
116
118
  hdl[1].header["CDELT2"] = 1.0
117
119
  hdl[1].header["CRPIX1"] = (s % 2) * 7
118
120
  hdl[1].header["CRPIX2"] = -1 * ((s - 1) // 2 - 1) * 7
119
- hdl[1].header["DSPSNUM"] = m
120
- hdl[1].header["VBISTP"] = s
121
+ hdl[1].header[MetadataKey.current_dsps_repeat] = m
122
+ hdl[1].header[VbiMetadataKey.current_spatial_step] = s
121
123
  task.write(
122
124
  data=hdl,
123
125
  tags=[
@@ -9,10 +9,12 @@ from dkist_fits_specifications import __version__ as spec_version
9
9
  from dkist_header_validator import spec122_validator
10
10
  from dkist_header_validator import spec214_validator
11
11
  from dkist_processing_common.codecs.fits import fits_array_encoder
12
+ from dkist_processing_common.models.fits_access import MetadataKey
12
13
  from dkist_processing_common.models.tags import Tag
13
14
  from dkist_service_configuration.logging import logger
14
15
 
15
16
  from dkist_processing_vbi.models.constants import VbiConstants
17
+ from dkist_processing_vbi.models.fits_access import VbiMetadataKey
16
18
  from dkist_processing_vbi.tasks.write_l1 import VbiWriteL1Frame
17
19
  from dkist_processing_vbi.tests.conftest import Vbi122ObserveFrames
18
20
  from dkist_processing_vbi.tests.conftest import VbiConstantsDb
@@ -34,25 +36,25 @@ def calibrated_header(is_mosaic: bool, camera_str: Literal["red", "blue", "red_a
34
36
  header["CUNIT3"] = "s"
35
37
  if is_mosaic:
36
38
  if camera_str == "blue":
37
- header["VBINSTP"] = 9
38
- header["VBISTP"] = 5
39
+ header[VbiMetadataKey.number_of_spatial_steps] = 9
40
+ header[VbiMetadataKey.current_spatial_step] = 5
39
41
  elif camera_str == "red_all":
40
- header["VBINSTP"] = 5
41
- header["VBISTP"] = 5
42
+ header[VbiMetadataKey.number_of_spatial_steps] = 5
43
+ header[VbiMetadataKey.current_spatial_step] = 5
42
44
  else:
43
- header["VBINSTP"] = 4
44
- header["VBISTP"] = 3
45
+ header[VbiMetadataKey.number_of_spatial_steps] = 4
46
+ header[VbiMetadataKey.current_spatial_step] = 3
45
47
  else:
46
- header["VBINSTP"] = 1
47
- header["VBISTP"] = 1
48
- header["VBISTPAT"] = "5"
49
- header["VBINFRAM"] = 3
50
- header["VBICFRAM"] = 2
48
+ header[VbiMetadataKey.number_of_spatial_steps] = 1
49
+ header[VbiMetadataKey.current_spatial_step] = 1
50
+ header[VbiMetadataKey.spatial_step_pattern] = "5"
51
+ header[VbiMetadataKey.number_of_exp_per_mosaic_step] = 3
52
+ header[VbiMetadataKey.current_mosaic_step_exp] = 2
51
53
  header["VBINMOSC"] = 3
52
54
  header["VBICMOSC"] = 2
53
- header["DSPSNUM"] = 1002 # To mimic a large offset
55
+ header[MetadataKey.current_dsps_repeat] = 1002 # To mimic a large offset
54
56
  header["DATE-BEG"] = "2025-07-11T00:00:00"
55
- header["TEXPOSUR"] = 100
57
+ header[MetadataKey.sensor_readout_exposure_time_ms] = 100
56
58
  return header
57
59
 
58
60
 
@@ -141,7 +143,10 @@ def test_write_l1_frame(
141
143
 
142
144
  if num_mosaic_repeats > 1:
143
145
  assert header["DEAXES"] == 1
144
- assert header["DNAXIS3"] == header["VBINFRAM"] * header["VBINMOSC"]
146
+ assert (
147
+ header["DNAXIS3"]
148
+ == header[VbiMetadataKey.number_of_exp_per_mosaic_step] * header["VBINMOSC"]
149
+ )
145
150
  assert header["DTYPE3"] == "TEMPORAL"
146
151
  assert header["DUNIT3"] == "s"
147
152
  assert header["DPNAME3"] == "time"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dkist-processing-vbi
3
- Version: 1.25.2
3
+ Version: 1.25.3
4
4
  Summary: Processing code for the VBI instrument on DKIST
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -68,6 +68,7 @@ Requires-Dist: Flask-Login==0.6.3; extra == "frozen"
68
68
  Requires-Dist: Flask-SQLAlchemy==2.5.1; extra == "frozen"
69
69
  Requires-Dist: Flask-Session==0.5.0; extra == "frozen"
70
70
  Requires-Dist: Flask-WTF==1.2.2; extra == "frozen"
71
+ Requires-Dist: ImageIO==2.37.2; extra == "frozen"
71
72
  Requires-Dist: Jinja2==3.1.6; extra == "frozen"
72
73
  Requires-Dist: Mako==1.3.10; extra == "frozen"
73
74
  Requires-Dist: MarkupSafe==3.0.3; extra == "frozen"
@@ -115,8 +116,8 @@ Requires-Dist: attrs==25.4.0; extra == "frozen"
115
116
  Requires-Dist: babel==2.17.0; extra == "frozen"
116
117
  Requires-Dist: billiard==4.2.2; extra == "frozen"
117
118
  Requires-Dist: blinker==1.9.0; extra == "frozen"
118
- Requires-Dist: boto3==1.40.64; extra == "frozen"
119
- Requires-Dist: botocore==1.40.64; extra == "frozen"
119
+ Requires-Dist: boto3==1.40.65; extra == "frozen"
120
+ Requires-Dist: botocore==1.40.65; extra == "frozen"
120
121
  Requires-Dist: cachelib==0.13.0; extra == "frozen"
121
122
  Requires-Dist: celery==5.3.1; extra == "frozen"
122
123
  Requires-Dist: certifi==2025.10.5; extra == "frozen"
@@ -143,7 +144,7 @@ Requires-Dist: dkist-processing-common==11.8.0; extra == "frozen"
143
144
  Requires-Dist: dkist-processing-core==6.0.0; extra == "frozen"
144
145
  Requires-Dist: dkist-processing-math==2.2.1; extra == "frozen"
145
146
  Requires-Dist: dkist-processing-pac==3.1.1; extra == "frozen"
146
- Requires-Dist: dkist-processing-vbi==1.25.2; extra == "frozen"
147
+ Requires-Dist: dkist-processing-vbi==1.25.3; extra == "frozen"
147
148
  Requires-Dist: dkist-service-configuration==4.1.7; extra == "frozen"
148
149
  Requires-Dist: dkist-spectral-lines==3.0.0; extra == "frozen"
149
150
  Requires-Dist: dkist_fits_specifications==4.17.0; extra == "frozen"
@@ -166,7 +167,6 @@ Requires-Dist: httpcore==1.0.9; extra == "frozen"
166
167
  Requires-Dist: httpx==0.28.1; extra == "frozen"
167
168
  Requires-Dist: humanize==4.14.0; extra == "frozen"
168
169
  Requires-Dist: idna==3.11; extra == "frozen"
169
- Requires-Dist: imageio==2.37.0; extra == "frozen"
170
170
  Requires-Dist: imageio-ffmpeg==0.6.0; extra == "frozen"
171
171
  Requires-Dist: importlib_metadata==8.7.0; extra == "frozen"
172
172
  Requires-Dist: inflection==0.5.1; extra == "frozen"
@@ -20,6 +20,7 @@ dkist_processing_vbi.egg-info/top_level.txt
20
20
  dkist_processing_vbi/models/__init__.py
21
21
  dkist_processing_vbi/models/constants.py
22
22
  dkist_processing_vbi/models/filter.py
23
+ dkist_processing_vbi/models/fits_access.py
23
24
  dkist_processing_vbi/models/parameters.py
24
25
  dkist_processing_vbi/models/tags.py
25
26
  dkist_processing_vbi/parsers/__init__.py
@@ -42,6 +43,7 @@ dkist_processing_vbi/tests/__init__.py
42
43
  dkist_processing_vbi/tests/conftest.py
43
44
  dkist_processing_vbi/tests/test_assemble_movie.py
44
45
  dkist_processing_vbi/tests/test_dark.py
46
+ dkist_processing_vbi/tests/test_fits_access.py
45
47
  dkist_processing_vbi/tests/test_gain.py
46
48
  dkist_processing_vbi/tests/test_make_movie_frames.py
47
49
  dkist_processing_vbi/tests/test_parse_l0.py
@@ -37,6 +37,7 @@ Flask-Login==0.6.3
37
37
  Flask-SQLAlchemy==2.5.1
38
38
  Flask-Session==0.5.0
39
39
  Flask-WTF==1.2.2
40
+ ImageIO==2.37.2
40
41
  Jinja2==3.1.6
41
42
  Mako==1.3.10
42
43
  MarkupSafe==3.0.3
@@ -84,8 +85,8 @@ attrs==25.4.0
84
85
  babel==2.17.0
85
86
  billiard==4.2.2
86
87
  blinker==1.9.0
87
- boto3==1.40.64
88
- botocore==1.40.64
88
+ boto3==1.40.65
89
+ botocore==1.40.65
89
90
  cachelib==0.13.0
90
91
  celery==5.3.1
91
92
  certifi==2025.10.5
@@ -112,7 +113,7 @@ dkist-processing-common==11.8.0
112
113
  dkist-processing-core==6.0.0
113
114
  dkist-processing-math==2.2.1
114
115
  dkist-processing-pac==3.1.1
115
- dkist-processing-vbi==1.25.2
116
+ dkist-processing-vbi==1.25.3
116
117
  dkist-service-configuration==4.1.7
117
118
  dkist-spectral-lines==3.0.0
118
119
  dkist_fits_specifications==4.17.0
@@ -135,7 +136,6 @@ httpcore==1.0.9
135
136
  httpx==0.28.1
136
137
  humanize==4.14.0
137
138
  idna==3.11
138
- imageio==2.37.0
139
139
  imageio-ffmpeg==0.6.0
140
140
  importlib_metadata==8.7.0
141
141
  inflection==0.5.1
@@ -9,8 +9,8 @@ find = {}
9
9
 
10
10
  [tool.dkist-dev-tools]
11
11
  # Most recently frozen version by dkist-dev-tools
12
- version = "1.25.2"
13
- date = 2025-11-03T14:37:41.715625
12
+ version = "1.25.3"
13
+ date = 2025-11-04T12:10:47.113111
14
14
 
15
15
  [project]
16
16
  dynamic = ["version"]
@@ -96,6 +96,7 @@ frozen = [
96
96
  "Flask-SQLAlchemy == 2.5.1",
97
97
  "Flask-Session == 0.5.0",
98
98
  "Flask-WTF == 1.2.2",
99
+ "ImageIO == 2.37.2",
99
100
  "Jinja2 == 3.1.6",
100
101
  "Mako == 1.3.10",
101
102
  "MarkupSafe == 3.0.3",
@@ -143,8 +144,8 @@ frozen = [
143
144
  "babel == 2.17.0",
144
145
  "billiard == 4.2.2",
145
146
  "blinker == 1.9.0",
146
- "boto3 == 1.40.64",
147
- "botocore == 1.40.64",
147
+ "boto3 == 1.40.65",
148
+ "botocore == 1.40.65",
148
149
  "cachelib == 0.13.0",
149
150
  "celery == 5.3.1",
150
151
  "certifi == 2025.10.5",
@@ -171,7 +172,7 @@ frozen = [
171
172
  "dkist-processing-core == 6.0.0",
172
173
  "dkist-processing-math == 2.2.1",
173
174
  "dkist-processing-pac == 3.1.1",
174
- "dkist-processing-vbi == 1.25.2",
175
+ "dkist-processing-vbi == 1.25.3",
175
176
  "dkist-service-configuration == 4.1.7",
176
177
  "dkist-spectral-lines == 3.0.0",
177
178
  "dkist_fits_specifications == 4.17.0",
@@ -194,7 +195,6 @@ frozen = [
194
195
  "httpx == 0.28.1",
195
196
  "humanize == 4.14.0",
196
197
  "idna == 3.11",
197
- "imageio == 2.37.0",
198
198
  "imageio-ffmpeg == 0.6.0",
199
199
  "importlib_metadata == 8.7.0",
200
200
  "inflection == 0.5.1",