dkist-processing-common 11.4.0rc1__py3-none-any.whl → 11.5.0__py3-none-any.whl
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/models/constants.py +42 -28
- dkist_processing_common/models/fits_access.py +56 -0
- dkist_processing_common/models/tags.py +2 -1
- dkist_processing_common/models/task_name.py +2 -2
- dkist_processing_common/parsers/cs_step.py +2 -2
- dkist_processing_common/parsers/dsps_repeat.py +5 -4
- dkist_processing_common/parsers/experiment_id_bud.py +5 -2
- dkist_processing_common/parsers/id_bud.py +6 -3
- dkist_processing_common/parsers/l0_fits_access.py +4 -3
- dkist_processing_common/parsers/l1_fits_access.py +22 -21
- dkist_processing_common/parsers/near_bud.py +5 -2
- dkist_processing_common/parsers/proposal_id_bud.py +3 -2
- dkist_processing_common/parsers/retarder.py +4 -3
- dkist_processing_common/parsers/single_value_single_key_flower.py +6 -1
- dkist_processing_common/parsers/task.py +7 -6
- dkist_processing_common/parsers/time.py +19 -15
- dkist_processing_common/parsers/unique_bud.py +5 -2
- dkist_processing_common/parsers/wavelength.py +4 -3
- dkist_processing_common/tasks/parse_l0_input_data.py +5 -3
- dkist_processing_common/tests/test_assemble_movie.py +0 -1
- dkist_processing_common/tests/test_constants.py +15 -0
- dkist_processing_common/tests/test_fits_access.py +62 -7
- dkist_processing_common/tests/test_parse_l0_input_data.py +22 -24
- dkist_processing_common/tests/test_stems.py +30 -21
- dkist_processing_common/tests/test_task_parsing.py +17 -7
- {dkist_processing_common-11.4.0rc1.dist-info → dkist_processing_common-11.5.0.dist-info}/METADATA +2 -2
- {dkist_processing_common-11.4.0rc1.dist-info → dkist_processing_common-11.5.0.dist-info}/RECORD +29 -30
- changelog/266.misc.rst +0 -1
- {dkist_processing_common-11.4.0rc1.dist-info → dkist_processing_common-11.5.0.dist-info}/WHEEL +0 -0
- {dkist_processing_common-11.4.0rc1.dist-info → dkist_processing_common-11.5.0.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from datetime import timezone
|
|
5
|
+
from enum import StrEnum
|
|
5
6
|
from typing import Callable
|
|
6
7
|
from typing import Hashable
|
|
7
8
|
from typing import Type
|
|
@@ -9,6 +10,7 @@ from typing import Type
|
|
|
9
10
|
import numpy as np
|
|
10
11
|
|
|
11
12
|
from dkist_processing_common.models.constants import BudName
|
|
13
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
12
14
|
from dkist_processing_common.models.flower_pot import SpilledDirt
|
|
13
15
|
from dkist_processing_common.models.flower_pot import Stem
|
|
14
16
|
from dkist_processing_common.models.tags import EXP_TIME_ROUND_DIGITS
|
|
@@ -28,9 +30,9 @@ class ObsIpStartTimeBud(TaskUniqueBud):
|
|
|
28
30
|
|
|
29
31
|
def __init__(self):
|
|
30
32
|
super().__init__(
|
|
31
|
-
constant_name=BudName.obs_ip_start_time
|
|
32
|
-
metadata_key=
|
|
33
|
-
ip_task_types=TaskName.observe
|
|
33
|
+
constant_name=BudName.obs_ip_start_time,
|
|
34
|
+
metadata_key=MetadataKey.ip_start_time,
|
|
35
|
+
ip_task_types=TaskName.observe,
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
|
|
@@ -38,7 +40,7 @@ class CadenceBudBase(UniqueBud):
|
|
|
38
40
|
"""Base class for all Cadence Buds."""
|
|
39
41
|
|
|
40
42
|
def __init__(self, constant_name: str):
|
|
41
|
-
super().__init__(constant_name, metadata_key=
|
|
43
|
+
super().__init__(constant_name, metadata_key=MetadataKey.time_obs)
|
|
42
44
|
|
|
43
45
|
def setter(self, fits_obj: L0FitsAccess) -> float | Type[SpilledDirt]:
|
|
44
46
|
"""
|
|
@@ -65,7 +67,7 @@ class AverageCadenceBud(CadenceBudBase):
|
|
|
65
67
|
"""Class for the average cadence Bud."""
|
|
66
68
|
|
|
67
69
|
def __init__(self):
|
|
68
|
-
super().__init__(constant_name=BudName.average_cadence
|
|
70
|
+
super().__init__(constant_name=BudName.average_cadence)
|
|
69
71
|
|
|
70
72
|
def getter(self, key) -> np.float64:
|
|
71
73
|
"""
|
|
@@ -87,7 +89,7 @@ class MaximumCadenceBud(CadenceBudBase):
|
|
|
87
89
|
"""Class for the maximum cadence bud."""
|
|
88
90
|
|
|
89
91
|
def __init__(self):
|
|
90
|
-
super().__init__(constant_name=BudName.maximum_cadence
|
|
92
|
+
super().__init__(constant_name=BudName.maximum_cadence)
|
|
91
93
|
|
|
92
94
|
def getter(self, key) -> np.float64:
|
|
93
95
|
"""
|
|
@@ -109,7 +111,7 @@ class MinimumCadenceBud(CadenceBudBase):
|
|
|
109
111
|
"""Class for the minimum cadence bud."""
|
|
110
112
|
|
|
111
113
|
def __init__(self):
|
|
112
|
-
super().__init__(constant_name=BudName.minimum_cadence
|
|
114
|
+
super().__init__(constant_name=BudName.minimum_cadence)
|
|
113
115
|
|
|
114
116
|
def getter(self, key) -> np.float64:
|
|
115
117
|
"""
|
|
@@ -131,7 +133,7 @@ class VarianceCadenceBud(CadenceBudBase):
|
|
|
131
133
|
"""Class for the variance cadence Bud."""
|
|
132
134
|
|
|
133
135
|
def __init__(self):
|
|
134
|
-
super().__init__(constant_name=BudName.variance_cadence
|
|
136
|
+
super().__init__(constant_name=BudName.variance_cadence)
|
|
135
137
|
|
|
136
138
|
def getter(self, key) -> np.float64:
|
|
137
139
|
"""
|
|
@@ -172,7 +174,7 @@ class ExposureTimeFlower(TimeFlowerBase):
|
|
|
172
174
|
|
|
173
175
|
def __init__(self):
|
|
174
176
|
super().__init__(
|
|
175
|
-
tag_stem_name=StemName.exposure_time
|
|
177
|
+
tag_stem_name=StemName.exposure_time, metadata_key=MetadataKey.fpa_exposure_time_ms
|
|
176
178
|
)
|
|
177
179
|
|
|
178
180
|
|
|
@@ -181,8 +183,8 @@ class ReadoutExpTimeFlower(TimeFlowerBase):
|
|
|
181
183
|
|
|
182
184
|
def __init__(self):
|
|
183
185
|
super().__init__(
|
|
184
|
-
tag_stem_name=StemName.readout_exp_time
|
|
185
|
-
metadata_key=
|
|
186
|
+
tag_stem_name=StemName.readout_exp_time,
|
|
187
|
+
metadata_key=MetadataKey.sensor_readout_exposure_time_ms,
|
|
186
188
|
)
|
|
187
189
|
|
|
188
190
|
|
|
@@ -213,15 +215,17 @@ class TaskTimeBudBase(Stem):
|
|
|
213
215
|
def __init__(
|
|
214
216
|
self,
|
|
215
217
|
stem_name: str,
|
|
216
|
-
metadata_key: str,
|
|
218
|
+
metadata_key: str | StrEnum,
|
|
217
219
|
ip_task_types: str | list[str],
|
|
218
220
|
header_task_parsing_func: Callable = passthrough_header_ip_task,
|
|
219
221
|
):
|
|
220
222
|
super().__init__(stem_name=stem_name)
|
|
221
223
|
|
|
224
|
+
if isinstance(metadata_key, StrEnum):
|
|
225
|
+
metadata_key = metadata_key.name
|
|
226
|
+
self.metadata_key = metadata_key
|
|
222
227
|
if isinstance(ip_task_types, str):
|
|
223
228
|
ip_task_types = [ip_task_types]
|
|
224
|
-
self.metadata_key = metadata_key
|
|
225
229
|
self.ip_task_types = [task.casefold() for task in ip_task_types]
|
|
226
230
|
self.header_parsing_function = header_task_parsing_func
|
|
227
231
|
|
|
@@ -252,7 +256,7 @@ class TaskExposureTimesBud(TaskTimeBudBase):
|
|
|
252
256
|
):
|
|
253
257
|
super().__init__(
|
|
254
258
|
stem_name=stem_name,
|
|
255
|
-
metadata_key=
|
|
259
|
+
metadata_key=MetadataKey.fpa_exposure_time_ms,
|
|
256
260
|
ip_task_types=ip_task_types,
|
|
257
261
|
header_task_parsing_func=header_task_parsing_func,
|
|
258
262
|
)
|
|
@@ -269,7 +273,7 @@ class TaskReadoutExpTimesBud(TaskTimeBudBase):
|
|
|
269
273
|
):
|
|
270
274
|
super().__init__(
|
|
271
275
|
stem_name=stem_name,
|
|
272
|
-
metadata_key=
|
|
276
|
+
metadata_key=MetadataKey.sensor_readout_exposure_time_ms,
|
|
273
277
|
ip_task_types=ip_task_types,
|
|
274
278
|
header_task_parsing_func=header_task_parsing_func,
|
|
275
279
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Pre-made flower that reads a single header key from all files and raises a ValueError if it is not unique."""
|
|
2
2
|
|
|
3
|
+
from enum import StrEnum
|
|
3
4
|
from typing import Callable
|
|
4
5
|
|
|
5
6
|
from dkist_processing_common.models.flower_pot import SpilledDirt
|
|
@@ -24,9 +25,11 @@ class UniqueBud(Stem):
|
|
|
24
25
|
def __init__(
|
|
25
26
|
self,
|
|
26
27
|
constant_name: str,
|
|
27
|
-
metadata_key: str,
|
|
28
|
+
metadata_key: str | StrEnum,
|
|
28
29
|
):
|
|
29
30
|
super().__init__(stem_name=constant_name)
|
|
31
|
+
if isinstance(metadata_key, StrEnum):
|
|
32
|
+
metadata_key = metadata_key.name
|
|
30
33
|
self.metadata_key = metadata_key
|
|
31
34
|
|
|
32
35
|
def setter(self, fits_obj: L0FitsAccess):
|
|
@@ -85,7 +88,7 @@ class TaskUniqueBud(UniqueBud):
|
|
|
85
88
|
def __init__(
|
|
86
89
|
self,
|
|
87
90
|
constant_name: str,
|
|
88
|
-
metadata_key: str,
|
|
91
|
+
metadata_key: str | StrEnum,
|
|
89
92
|
ip_task_types: str | list[str],
|
|
90
93
|
task_type_parsing_function: Callable = passthrough_header_ip_task,
|
|
91
94
|
):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Bud to get the wavelength of observe frames."""
|
|
2
2
|
|
|
3
3
|
from dkist_processing_common.models.constants import BudName
|
|
4
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
4
5
|
from dkist_processing_common.models.task_name import TaskName
|
|
5
6
|
from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
|
|
6
7
|
|
|
@@ -10,7 +11,7 @@ class ObserveWavelengthBud(TaskUniqueBud):
|
|
|
10
11
|
|
|
11
12
|
def __init__(self):
|
|
12
13
|
super().__init__(
|
|
13
|
-
constant_name=BudName.wavelength
|
|
14
|
-
metadata_key=
|
|
15
|
-
ip_task_types=TaskName.observe
|
|
14
|
+
constant_name=BudName.wavelength,
|
|
15
|
+
metadata_key=MetadataKey.wavelength,
|
|
16
|
+
ip_task_types=TaskName.observe,
|
|
16
17
|
)
|
|
@@ -28,10 +28,12 @@ from typing import TypeVar
|
|
|
28
28
|
|
|
29
29
|
from dkist_processing_common.codecs.fits import fits_access_decoder
|
|
30
30
|
from dkist_processing_common.models.constants import BudName
|
|
31
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
31
32
|
from dkist_processing_common.models.flower_pot import FlowerPot
|
|
32
33
|
from dkist_processing_common.models.flower_pot import Stem
|
|
33
34
|
from dkist_processing_common.models.flower_pot import Thorn
|
|
34
35
|
from dkist_processing_common.models.tags import Tag
|
|
36
|
+
from dkist_processing_common.models.task_name import TaskName
|
|
35
37
|
from dkist_processing_common.parsers.experiment_id_bud import ContributingExperimentIdsBud
|
|
36
38
|
from dkist_processing_common.parsers.experiment_id_bud import ExperimentIdBud
|
|
37
39
|
from dkist_processing_common.parsers.proposal_id_bud import ContributingProposalIdsBud
|
|
@@ -60,7 +62,7 @@ S = TypeVar("S", bound=Stem)
|
|
|
60
62
|
def default_constant_bud_factory() -> list[S]:
|
|
61
63
|
"""Provide default constant buds for use in common parsing tasks."""
|
|
62
64
|
return [
|
|
63
|
-
UniqueBud(constant_name=BudName.instrument
|
|
65
|
+
UniqueBud(constant_name=BudName.instrument, metadata_key=MetadataKey.instrument),
|
|
64
66
|
ProposalIdBud(),
|
|
65
67
|
ContributingProposalIdsBud(),
|
|
66
68
|
ExperimentIdBud(),
|
|
@@ -69,9 +71,9 @@ def default_constant_bud_factory() -> list[S]:
|
|
|
69
71
|
MaximumCadenceBud(),
|
|
70
72
|
MinimumCadenceBud(),
|
|
71
73
|
VarianceCadenceBud(),
|
|
72
|
-
TaskExposureTimesBud(stem_name=BudName.dark_exposure_times
|
|
74
|
+
TaskExposureTimesBud(stem_name=BudName.dark_exposure_times, ip_task_types=TaskName.dark),
|
|
73
75
|
TaskReadoutExpTimesBud(
|
|
74
|
-
stem_name=BudName.dark_readout_exp_times
|
|
76
|
+
stem_name=BudName.dark_readout_exp_times, ip_task_types=TaskName.dark
|
|
75
77
|
),
|
|
76
78
|
]
|
|
77
79
|
|
|
@@ -40,6 +40,21 @@ class ConstantsFinal(ConstantsBase):
|
|
|
40
40
|
return self._db_dict["KEY 1"] ** 2 # Just to show that you can do whatever you want
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def test_bud_names_in_constant_base():
|
|
44
|
+
"""
|
|
45
|
+
Given: a set of constants in the BudNames sting enumeration
|
|
46
|
+
When: ConstantBase class defines a set of properties
|
|
47
|
+
Then: the sets are the same (except for constants that are not in the redis database)
|
|
48
|
+
"""
|
|
49
|
+
all_bud_names = {b.name for b in BudName}
|
|
50
|
+
all_properties_in_constants_base = {
|
|
51
|
+
k for k, v in ConstantsBase.__dict__.items() if isinstance(v, property)
|
|
52
|
+
}
|
|
53
|
+
constants_not_in_redis = {"dataset_id", "stokes_params"}
|
|
54
|
+
all_buds_defined_in_constant_base = all_properties_in_constants_base - constants_not_in_redis
|
|
55
|
+
assert all_bud_names == all_buds_defined_in_constant_base
|
|
56
|
+
|
|
57
|
+
|
|
43
58
|
def test_constants_db_as_dict(test_constants_db, test_dict):
|
|
44
59
|
"""
|
|
45
60
|
Given: a ConstantsDb object and a python dictionary
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
import pytest
|
|
3
5
|
from astropy.io import fits
|
|
4
6
|
|
|
7
|
+
from dkist_processing_common.models.fits_access import NOT_FOUND_MESSAGE
|
|
5
8
|
from dkist_processing_common.models.fits_access import FitsAccessBase
|
|
9
|
+
from dkist_processing_common.models.fits_access import MetadataKey
|
|
6
10
|
from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
|
|
7
11
|
from dkist_processing_common.parsers.l1_fits_access import L1FitsAccess
|
|
8
12
|
|
|
@@ -93,17 +97,32 @@ def hdu_with_no_data(complete_common_header):
|
|
|
93
97
|
|
|
94
98
|
|
|
95
99
|
@pytest.fixture()
|
|
96
|
-
def hdu_with_incomplete_common_header(
|
|
100
|
+
def hdu_with_incomplete_common_header(complete_common_header):
|
|
97
101
|
"""
|
|
98
102
|
An HDU with data and a header missing one of the expected common by-frame keywords
|
|
99
103
|
"""
|
|
104
|
+
incomplete_header = complete_common_header
|
|
105
|
+
incomplete_header.pop("ELEV_ANG")
|
|
106
|
+
incomplete_header.pop("TAZIMUTH")
|
|
100
107
|
data = np.arange(9).reshape(3, 3)
|
|
101
|
-
hdu = fits.PrimaryHDU(data)
|
|
102
|
-
hdu.header["TELEVATN"] = 6.28
|
|
103
|
-
hdu.header["TAZIMUTH"] = 3.14
|
|
108
|
+
hdu = fits.PrimaryHDU(data, header=incomplete_header)
|
|
104
109
|
return hdu
|
|
105
110
|
|
|
106
111
|
|
|
112
|
+
class MetadataKeyWithOptionalKeys(StrEnum):
|
|
113
|
+
optional1 = "ELEV_ANG"
|
|
114
|
+
optional2 = "TAZIMUTH"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class FitsAccessWithOptionalKeys(FitsAccessBase):
|
|
118
|
+
def __init__(self, hdu, name):
|
|
119
|
+
super().__init__(hdu, name)
|
|
120
|
+
self._set_metadata_key_value(MetadataKeyWithOptionalKeys.optional1, optional=True)
|
|
121
|
+
self._set_metadata_key_value(
|
|
122
|
+
MetadataKeyWithOptionalKeys.optional2, optional=True, default="SO_RAD"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
107
126
|
@pytest.fixture()
|
|
108
127
|
def fits_file_path(tmp_path, complete_common_header):
|
|
109
128
|
file_path = tmp_path / "foo.fits"
|
|
@@ -127,12 +146,37 @@ def fits_file_path_with_data_in_imagehdu(tmp_path, complete_common_header):
|
|
|
127
146
|
return file_path
|
|
128
147
|
|
|
129
148
|
|
|
149
|
+
class MetadataKeyWithNaxisKeys(StrEnum):
|
|
150
|
+
naxis = "NAXIS"
|
|
151
|
+
naxis1 = "NAXIS1"
|
|
152
|
+
naxis2 = "NAXIS2"
|
|
153
|
+
|
|
154
|
+
|
|
130
155
|
class FitsAccessWithNaxisKeys(FitsAccessBase):
|
|
131
156
|
def __init__(self, hdu, name):
|
|
132
157
|
super().__init__(hdu, name)
|
|
133
|
-
self.naxis
|
|
134
|
-
self.naxis1
|
|
135
|
-
self.naxis2
|
|
158
|
+
self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis)
|
|
159
|
+
self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis1)
|
|
160
|
+
self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis2)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_metadata_keys_in_access_bases(hdu_with_no_data):
|
|
164
|
+
"""
|
|
165
|
+
Given: a set of metadata key names in the MetadataKey sting enumeration
|
|
166
|
+
When: the FITS access classes define a set of attributes/properties
|
|
167
|
+
Then: the sets are the same
|
|
168
|
+
"""
|
|
169
|
+
all_metadata_key_names = {mk.name for mk in MetadataKey}
|
|
170
|
+
hdu = hdu_with_no_data
|
|
171
|
+
l1_properties = {k for k, v in L1FitsAccess.__dict__.items() if isinstance(v, property)}
|
|
172
|
+
l0_properties = {k for k, v in L0FitsAccess.__dict__.items() if isinstance(v, property)}
|
|
173
|
+
all_fits_access_properties = l1_properties | l0_properties
|
|
174
|
+
l1_dict_keys = {k for k, v in L1FitsAccess(hdu=hdu).__dict__.items()}
|
|
175
|
+
l0_dict_keys = {k for k, v in L0FitsAccess(hdu=hdu).__dict__.items()}
|
|
176
|
+
all_fits_access_dict_keys = l1_dict_keys | l0_dict_keys
|
|
177
|
+
instance_dict_keys = {"_hdu", "name", "auto_squeeze"}
|
|
178
|
+
keys_defined_in_fits_access = all_fits_access_dict_keys | all_fits_access_properties
|
|
179
|
+
assert all_metadata_key_names == keys_defined_in_fits_access - instance_dict_keys
|
|
136
180
|
|
|
137
181
|
|
|
138
182
|
def test_from_single_hdu(hdu_with_complete_common_header):
|
|
@@ -211,6 +255,17 @@ def test_no_header_value(hdu_with_incomplete_common_header):
|
|
|
211
255
|
_ = L0FitsAccess(hdu_with_incomplete_common_header)
|
|
212
256
|
|
|
213
257
|
|
|
258
|
+
def test_default_header_values(hdu_with_incomplete_common_header):
|
|
259
|
+
"""
|
|
260
|
+
Given: an HDU with a header with missing common by-frame keywords
|
|
261
|
+
When: processing the HDU with a FITS access class that sets these keywords as optional
|
|
262
|
+
Then: the correct default values are set
|
|
263
|
+
"""
|
|
264
|
+
fits_obj = FitsAccessWithOptionalKeys(hdu_with_incomplete_common_header, name="foo")
|
|
265
|
+
assert fits_obj.optional1 == MetadataKeyWithOptionalKeys.optional1 + NOT_FOUND_MESSAGE
|
|
266
|
+
assert fits_obj.optional2 == "SO_RAD"
|
|
267
|
+
|
|
268
|
+
|
|
214
269
|
def test_as_subclass(hdu_with_complete_common_header):
|
|
215
270
|
"""
|
|
216
271
|
Given: an instrument-specific fits_obj class that subclasses L0FitsAccess
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Tests for the parse L0 input data task"""
|
|
2
2
|
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
3
5
|
import numpy as np
|
|
4
6
|
import pytest
|
|
5
7
|
from astropy.io import fits
|
|
@@ -20,6 +22,7 @@ from dkist_processing_common.parsers.single_value_single_key_flower import (
|
|
|
20
22
|
)
|
|
21
23
|
from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
22
24
|
from dkist_processing_common.tasks.parse_l0_input_data import ParseL0InputDataBase
|
|
25
|
+
from dkist_processing_common.tasks.parse_l0_input_data import default_constant_bud_factory
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
class VispHeaders(Spec122Dataset):
|
|
@@ -85,25 +88,33 @@ class VispHeaders(Spec122Dataset):
|
|
|
85
88
|
return self.index % self.num_mod
|
|
86
89
|
|
|
87
90
|
|
|
91
|
+
class ViSPMetadataKey(StrEnum):
|
|
92
|
+
num_mod = "VISP_010"
|
|
93
|
+
modstate = "VISP_011"
|
|
94
|
+
ip_task_type = "DKIST004"
|
|
95
|
+
|
|
96
|
+
|
|
88
97
|
class ViSPFitsAccess(FitsAccessBase):
|
|
89
98
|
def __init__(self, hdu, name, auto_squeeze=False):
|
|
90
99
|
super().__init__(hdu, name, auto_squeeze=auto_squeeze)
|
|
91
|
-
self.num_mod
|
|
92
|
-
self.modstate
|
|
93
|
-
self.ip_task_type
|
|
100
|
+
self._set_metadata_key_value(ViSPMetadataKey.num_mod)
|
|
101
|
+
self._set_metadata_key_value(ViSPMetadataKey.modstate)
|
|
102
|
+
self._set_metadata_key_value(ViSPMetadataKey.ip_task_type)
|
|
94
103
|
self.name = name
|
|
95
104
|
|
|
96
105
|
|
|
97
106
|
@pytest.fixture(scope="function")
|
|
98
107
|
def visp_flowers():
|
|
99
108
|
return [
|
|
100
|
-
SingleValueSingleKeyFlower(
|
|
109
|
+
SingleValueSingleKeyFlower(
|
|
110
|
+
tag_stem_name=StemName.modstate, metadata_key=ViSPMetadataKey.modstate
|
|
111
|
+
)
|
|
101
112
|
]
|
|
102
113
|
|
|
103
114
|
|
|
104
115
|
@pytest.fixture(scope="function")
|
|
105
116
|
def visp_buds():
|
|
106
|
-
return [UniqueBud(constant_name=BudName.num_modstates
|
|
117
|
+
return [UniqueBud(constant_name=BudName.num_modstates, metadata_key=ViSPMetadataKey.num_mod)]
|
|
107
118
|
|
|
108
119
|
|
|
109
120
|
@pytest.fixture(scope="function")
|
|
@@ -233,9 +244,9 @@ def test_make_flowerpots(parse_inputs_task):
|
|
|
233
244
|
|
|
234
245
|
assert len(tag_pot.stems) == 2
|
|
235
246
|
assert len(constant_pot.stems) == 3
|
|
236
|
-
assert tag_pot.stems[0].stem_name == StemName.modstate
|
|
247
|
+
assert tag_pot.stems[0].stem_name == StemName.modstate
|
|
237
248
|
assert tag_pot.stems[1].stem_name == "EMPTY_FLOWER"
|
|
238
|
-
assert constant_pot.stems[0].stem_name == BudName.num_modstates
|
|
249
|
+
assert constant_pot.stems[0].stem_name == BudName.num_modstates
|
|
239
250
|
assert constant_pot.stems[1].stem_name == "EMPTY_BUD"
|
|
240
251
|
assert constant_pot.stems[2].stem_name == "PICKY_BUD"
|
|
241
252
|
|
|
@@ -250,23 +261,10 @@ def test_subclass_flowers(visp_parse_inputs_task, max_cs_step_time_sec):
|
|
|
250
261
|
|
|
251
262
|
assert len(tag_pot.stems) == 1
|
|
252
263
|
assert len(constant_pot.stems) == 12
|
|
253
|
-
|
|
254
|
-
assert sorted([f.stem_name for f in
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
BudName.num_modstates.value,
|
|
258
|
-
BudName.proposal_id.value,
|
|
259
|
-
BudName.contributing_proposal_ids.value,
|
|
260
|
-
BudName.average_cadence.value,
|
|
261
|
-
BudName.maximum_cadence.value,
|
|
262
|
-
BudName.minimum_cadence.value,
|
|
263
|
-
BudName.variance_cadence.value,
|
|
264
|
-
BudName.dark_exposure_times.value,
|
|
265
|
-
BudName.dark_readout_exp_times.value,
|
|
266
|
-
BudName.experiment_id.value,
|
|
267
|
-
BudName.contributing_experiment_ids.value,
|
|
268
|
-
]
|
|
269
|
-
)
|
|
264
|
+
all_flower_names = [StemName.modstate]
|
|
265
|
+
assert sorted([f.stem_name for f in tag_pot.stems]) == sorted(all_flower_names)
|
|
266
|
+
all_bud_names = [b.stem_name for b in default_constant_bud_factory()] + [BudName.num_modstates]
|
|
267
|
+
assert sorted([f.stem_name for f in constant_pot.stems]) == sorted(all_bud_names)
|
|
270
268
|
|
|
271
269
|
|
|
272
270
|
def test_constants_correct(parse_inputs_task):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
1
2
|
from itertools import chain
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -39,30 +40,38 @@ from dkist_processing_common.parsers.unique_bud import UniqueBud
|
|
|
39
40
|
from dkist_processing_common.parsers.wavelength import ObserveWavelengthBud
|
|
40
41
|
|
|
41
42
|
|
|
43
|
+
class FitsReaderMetadataKey(StrEnum):
|
|
44
|
+
thing_id = "id_key"
|
|
45
|
+
constant_thing = "constant"
|
|
46
|
+
near_thing = "near"
|
|
47
|
+
proposal_id = "ID___013"
|
|
48
|
+
experiment_id = "ID___012"
|
|
49
|
+
ip_task_type = "DKIST004"
|
|
50
|
+
ip_start_time = "DKIST011"
|
|
51
|
+
fpa_exposure_time_ms = "XPOSURE"
|
|
52
|
+
sensor_readout_exposure_time_ms = "TEXPOSUR"
|
|
53
|
+
num_raw_frames_per_fpa = "NSUMEXP"
|
|
54
|
+
num_dsps_repeats = "DSPSREPS"
|
|
55
|
+
current_dsps_repeat = "DSPSNUM"
|
|
56
|
+
time_obs = "DATE-OBS"
|
|
57
|
+
gos_level3_status = "GOSLVL3"
|
|
58
|
+
gos_level3_lamp_status = "GOSLAMP"
|
|
59
|
+
gos_level0_status = "GOSLVL0"
|
|
60
|
+
gos_retarder_status = "GOSRET"
|
|
61
|
+
gos_polarizer_status = "GOSPOL"
|
|
62
|
+
wavelength = "LINEWAV"
|
|
63
|
+
roundable_time = "RTIME"
|
|
64
|
+
|
|
65
|
+
|
|
42
66
|
class FitsReader(FitsAccessBase):
|
|
43
67
|
def __init__(self, hdu, name):
|
|
44
68
|
super().__init__(hdu, name)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
self.
|
|
69
|
+
for key in FitsReaderMetadataKey:
|
|
70
|
+
self._set_metadata_key_value(key=key, optional=True)
|
|
71
|
+
self._set_metadata_key_value(
|
|
72
|
+
FitsReaderMetadataKey.roundable_time, optional=True, default=0.0
|
|
73
|
+
)
|
|
48
74
|
self.name = name
|
|
49
|
-
self.proposal_id: str = self.header.get("ID___013")
|
|
50
|
-
self.experiment_id: str = self.header.get("ID___012")
|
|
51
|
-
self.ip_task_type: str = self.header.get("DKIST004")
|
|
52
|
-
self.ip_start_time: str = self.header.get("DKIST011")
|
|
53
|
-
self.fpa_exposure_time_ms: float = self.header.get("XPOSURE")
|
|
54
|
-
self.sensor_readout_exposure_time_ms: float = self.header.get("TEXPOSUR")
|
|
55
|
-
self.num_raw_frames_per_fpa: int = self.header.get("NSUMEXP")
|
|
56
|
-
self.num_dsps_repeats: int = self.header.get("DSPSREPS")
|
|
57
|
-
self.current_dsps_repeat: int = self.header.get("DSPSNUM")
|
|
58
|
-
self.time_obs: str = self.header.get("DATE-OBS")
|
|
59
|
-
self.gos_level3_status: str = self.header.get("GOSLVL3")
|
|
60
|
-
self.gos_level3_lamp_status: str = self.header.get("GOSLAMP")
|
|
61
|
-
self.gos_level0_status: str = self.header.get("GOSLVL0")
|
|
62
|
-
self.gos_retarder_status: str = self.header.get("GOSRET")
|
|
63
|
-
self.gos_polarizer_status: str = self.header.get("GOSPOL")
|
|
64
|
-
self.wavelength: str = self.header.get("LINEWAV")
|
|
65
|
-
self.roundable_time: float = self.header.get("RTIME", 0.0)
|
|
66
75
|
|
|
67
76
|
|
|
68
77
|
@pytest.fixture()
|
|
@@ -926,4 +935,4 @@ def test_retarder_name_bud_error(bad_polcal_header_objs):
|
|
|
926
935
|
_ = bud.bud
|
|
927
936
|
|
|
928
937
|
|
|
929
|
-
# TODO: test new
|
|
938
|
+
# TODO: test new stem types that have been added to parse_l0_input_data
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
from astropy.io import fits
|
|
3
5
|
|
|
@@ -9,6 +11,15 @@ from dkist_processing_common.parsers.task import parse_polcal_task_type
|
|
|
9
11
|
from dkist_processing_common.parsers.task import passthrough_header_ip_task
|
|
10
12
|
|
|
11
13
|
|
|
14
|
+
class DummyMetadataKey(StrEnum):
|
|
15
|
+
ip_task_type = "IPTASK"
|
|
16
|
+
gos_level3_status = "GOSLVL3"
|
|
17
|
+
gos_level3_lamp_status = "GOSLAMP"
|
|
18
|
+
gos_level0_status = "GOSLVL0"
|
|
19
|
+
gos_retarder_status = "GOSRET"
|
|
20
|
+
gos_polarizer_status = "GOSPOL"
|
|
21
|
+
|
|
22
|
+
|
|
12
23
|
class DummyFitsAccess(FitsAccessBase):
|
|
13
24
|
def __init__(
|
|
14
25
|
self,
|
|
@@ -17,13 +28,12 @@ class DummyFitsAccess(FitsAccessBase):
|
|
|
17
28
|
auto_squeeze: bool = False, # Because L1 data should always have the right form, right?
|
|
18
29
|
):
|
|
19
30
|
super().__init__(hdu=hdu, name=name, auto_squeeze=auto_squeeze)
|
|
20
|
-
|
|
21
|
-
self.
|
|
22
|
-
self.
|
|
23
|
-
self.
|
|
24
|
-
self.
|
|
25
|
-
self.
|
|
26
|
-
self.gos_polarizer_status: str = self.header["GOSPOL"]
|
|
31
|
+
self._set_metadata_key_value(DummyMetadataKey.ip_task_type)
|
|
32
|
+
self._set_metadata_key_value(DummyMetadataKey.gos_level3_status)
|
|
33
|
+
self._set_metadata_key_value(DummyMetadataKey.gos_level3_lamp_status)
|
|
34
|
+
self._set_metadata_key_value(DummyMetadataKey.gos_level0_status)
|
|
35
|
+
self._set_metadata_key_value(DummyMetadataKey.gos_retarder_status)
|
|
36
|
+
self._set_metadata_key_value(DummyMetadataKey.gos_polarizer_status)
|
|
27
37
|
|
|
28
38
|
|
|
29
39
|
@pytest.fixture
|
{dkist_processing_common-11.4.0rc1.dist-info → dkist_processing_common-11.5.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dkist-processing-common
|
|
3
|
-
Version: 11.
|
|
3
|
+
Version: 11.5.0
|
|
4
4
|
Summary: Common task classes used by the DKIST science data processing pipelines
|
|
5
5
|
Author-email: NSO / AURA <dkistdc@nso.edu>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -17,7 +17,7 @@ Requires-Dist: asdf<4.0.0,>=3.5.0
|
|
|
17
17
|
Requires-Dist: astropy>=7.0.0
|
|
18
18
|
Requires-Dist: dkist-fits-specifications<5.0,>=4.0.0
|
|
19
19
|
Requires-Dist: dkist-header-validator<6.0,>=5.0.0
|
|
20
|
-
Requires-Dist: dkist-processing-core==5.2.
|
|
20
|
+
Requires-Dist: dkist-processing-core==5.2.1
|
|
21
21
|
Requires-Dist: dkist-processing-pac<4.0,>=3.1
|
|
22
22
|
Requires-Dist: dkist-service-configuration<3.0,>=2.0.2
|
|
23
23
|
Requires-Dist: dkist-spectral-lines<4.0,>=3.0.0
|