dkist-processing-common 11.6.0__py3-none-any.whl → 11.7.0rc1__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.
Files changed (26) hide show
  1. changelog/267.feature.1.rst +1 -0
  2. changelog/267.feature.2.rst +1 -0
  3. changelog/267.feature.rst +1 -0
  4. changelog/267.misc.rst +1 -0
  5. changelog/267.removal.1.rst +2 -0
  6. changelog/267.removal.rst +1 -0
  7. dkist_processing_common/models/constants.py +394 -16
  8. dkist_processing_common/models/fits_access.py +16 -25
  9. dkist_processing_common/parsers/average_bud.py +48 -0
  10. dkist_processing_common/parsers/experiment_id_bud.py +8 -4
  11. dkist_processing_common/parsers/id_bud.py +35 -17
  12. dkist_processing_common/parsers/l0_fits_access.py +3 -3
  13. dkist_processing_common/parsers/l1_fits_access.py +47 -21
  14. dkist_processing_common/parsers/near_bud.py +4 -4
  15. dkist_processing_common/parsers/proposal_id_bud.py +11 -5
  16. dkist_processing_common/parsers/single_value_single_key_flower.py +0 -1
  17. dkist_processing_common/parsers/time.py +141 -27
  18. dkist_processing_common/tasks/parse_l0_input_data.py +284 -1
  19. dkist_processing_common/tests/test_fits_access.py +19 -44
  20. dkist_processing_common/tests/test_parse_l0_input_data.py +39 -5
  21. dkist_processing_common/tests/test_stems.py +127 -10
  22. dkist_processing_common/tests/test_task_parsing.py +6 -6
  23. {dkist_processing_common-11.6.0.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/METADATA +1 -1
  24. {dkist_processing_common-11.6.0.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/RECORD +26 -19
  25. {dkist_processing_common-11.6.0.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/WHEEL +0 -0
  26. {dkist_processing_common-11.6.0.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/top_level.txt +0 -0
@@ -34,16 +34,20 @@ from dkist_processing_common.models.flower_pot import Stem
34
34
  from dkist_processing_common.models.flower_pot import Thorn
35
35
  from dkist_processing_common.models.tags import Tag
36
36
  from dkist_processing_common.models.task_name import TaskName
37
+ from dkist_processing_common.parsers.average_bud import TaskAverageBud
37
38
  from dkist_processing_common.parsers.experiment_id_bud import ContributingExperimentIdsBud
38
39
  from dkist_processing_common.parsers.experiment_id_bud import ExperimentIdBud
40
+ from dkist_processing_common.parsers.id_bud import TaskContributingIdsBud
39
41
  from dkist_processing_common.parsers.proposal_id_bud import ContributingProposalIdsBud
40
42
  from dkist_processing_common.parsers.proposal_id_bud import ProposalIdBud
41
43
  from dkist_processing_common.parsers.time import AverageCadenceBud
42
44
  from dkist_processing_common.parsers.time import MaximumCadenceBud
43
45
  from dkist_processing_common.parsers.time import MinimumCadenceBud
46
+ from dkist_processing_common.parsers.time import TaskDateBeginBud
44
47
  from dkist_processing_common.parsers.time import TaskExposureTimesBud
45
48
  from dkist_processing_common.parsers.time import TaskReadoutExpTimesBud
46
49
  from dkist_processing_common.parsers.time import VarianceCadenceBud
50
+ from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
47
51
  from dkist_processing_common.parsers.unique_bud import UniqueBud
48
52
  from dkist_processing_common.tasks.base import WorkflowTaskBase
49
53
 
@@ -59,9 +63,288 @@ logger = logging.getLogger(__name__)
59
63
  S = TypeVar("S", bound=Stem)
60
64
 
61
65
 
66
+ def dataset_extra_bud_factory() -> list[S]:
67
+ """Provide constant buds for use in dataset extras."""
68
+ return [
69
+ UniqueBud(constant_name=BudName.camera_id, metadata_key=MetadataKey.camera_id),
70
+ UniqueBud(constant_name=BudName.camera_name, metadata_key=MetadataKey.camera_name),
71
+ UniqueBud(
72
+ constant_name=BudName.camera_bit_depth, metadata_key=MetadataKey.camera_bit_depth
73
+ ),
74
+ UniqueBud(
75
+ constant_name=BudName.hardware_binning_x, metadata_key=MetadataKey.hardware_binning_x
76
+ ),
77
+ UniqueBud(
78
+ constant_name=BudName.hardware_binning_y, metadata_key=MetadataKey.hardware_binning_x
79
+ ),
80
+ UniqueBud(
81
+ constant_name=BudName.software_binning_x, metadata_key=MetadataKey.software_binning_x
82
+ ),
83
+ UniqueBud(
84
+ constant_name=BudName.software_binning_y, metadata_key=MetadataKey.software_binning_y
85
+ ),
86
+ UniqueBud(
87
+ constant_name=BudName.hls_version,
88
+ metadata_key=MetadataKey.hls_version,
89
+ ),
90
+ TaskContributingIdsBud(
91
+ constant_name=BudName.dark_observing_program_execution_id,
92
+ metadata_key=MetadataKey.observing_program_execution_id,
93
+ ip_task_types=TaskName.dark,
94
+ ),
95
+ TaskContributingIdsBud(
96
+ constant_name=BudName.solar_gain_observing_program_execution_id,
97
+ metadata_key=MetadataKey.observing_program_execution_id,
98
+ ip_task_types=TaskName.solar_gain,
99
+ ),
100
+ TaskContributingIdsBud(
101
+ constant_name=BudName.polcal_observing_program_execution_id,
102
+ metadata_key=MetadataKey.observing_program_execution_id,
103
+ ip_task_types=TaskName.polcal,
104
+ ),
105
+ TaskUniqueBud(
106
+ constant_name=BudName.dark_num_raw_frames_per_fpa,
107
+ metadata_key=MetadataKey.num_raw_frames_per_fpa,
108
+ ip_task_types=TaskName.dark,
109
+ ),
110
+ TaskUniqueBud(
111
+ constant_name=BudName.solar_gain_num_raw_frames_per_fpa,
112
+ metadata_key=MetadataKey.num_raw_frames_per_fpa,
113
+ ip_task_types=TaskName.solar_gain,
114
+ ),
115
+ TaskUniqueBud(
116
+ constant_name=BudName.polcal_num_raw_frames_per_fpa,
117
+ metadata_key=MetadataKey.num_raw_frames_per_fpa,
118
+ ip_task_types=TaskName.polcal,
119
+ ),
120
+ TaskUniqueBud(
121
+ constant_name=BudName.dark_telescope_tracking_mode,
122
+ metadata_key=MetadataKey.telescope_tracking_mode,
123
+ ip_task_types=TaskName.dark,
124
+ ),
125
+ TaskUniqueBud(
126
+ constant_name=BudName.solar_gain_telescope_tracking_mode,
127
+ metadata_key=MetadataKey.telescope_tracking_mode,
128
+ ip_task_types=TaskName.solar_gain,
129
+ ),
130
+ TaskUniqueBud(
131
+ constant_name=BudName.polcal_telescope_tracking_mode,
132
+ metadata_key=MetadataKey.telescope_tracking_mode,
133
+ ip_task_types=TaskName.polcal,
134
+ ),
135
+ TaskUniqueBud(
136
+ constant_name=BudName.dark_coude_table_tracking_mode,
137
+ metadata_key=MetadataKey.coude_table_tracking_mode,
138
+ ip_task_types=TaskName.dark,
139
+ ),
140
+ TaskUniqueBud(
141
+ constant_name=BudName.solar_gain_coude_table_tracking_mode,
142
+ metadata_key=MetadataKey.coude_table_tracking_mode,
143
+ ip_task_types=TaskName.solar_gain,
144
+ ),
145
+ TaskUniqueBud(
146
+ constant_name=BudName.polcal_coude_table_tracking_mode,
147
+ metadata_key=MetadataKey.coude_table_tracking_mode,
148
+ ip_task_types=TaskName.polcal,
149
+ ),
150
+ TaskUniqueBud(
151
+ constant_name=BudName.dark_telescope_scanning_mode,
152
+ metadata_key=MetadataKey.telescope_scanning_mode,
153
+ ip_task_types=TaskName.dark,
154
+ ),
155
+ TaskUniqueBud(
156
+ constant_name=BudName.solar_gain_telescope_scanning_mode,
157
+ metadata_key=MetadataKey.telescope_scanning_mode,
158
+ ip_task_types=TaskName.solar_gain,
159
+ ),
160
+ TaskUniqueBud(
161
+ constant_name=BudName.polcal_telescope_scanning_mode,
162
+ metadata_key=MetadataKey.telescope_scanning_mode,
163
+ ip_task_types=TaskName.polcal,
164
+ ),
165
+ TaskUniqueBud(
166
+ constant_name=BudName.dark_gos_level3_status,
167
+ metadata_key=MetadataKey.gos_level3_status,
168
+ ip_task_types=TaskName.dark,
169
+ ),
170
+ TaskUniqueBud(
171
+ constant_name=BudName.solar_gain_gos_level3_status,
172
+ metadata_key=MetadataKey.gos_level3_status,
173
+ ip_task_types=TaskName.solar_gain,
174
+ ),
175
+ TaskUniqueBud(
176
+ constant_name=BudName.polcal_gos_level3_status,
177
+ metadata_key=MetadataKey.gos_level3_status,
178
+ ip_task_types=TaskName.polcal,
179
+ ),
180
+ TaskUniqueBud(
181
+ constant_name=BudName.dark_gos_level3_lamp_status,
182
+ metadata_key=MetadataKey.gos_level3_lamp_status,
183
+ ip_task_types=TaskName.dark,
184
+ ),
185
+ TaskUniqueBud(
186
+ constant_name=BudName.solar_gain_gos_level3_lamp_status,
187
+ metadata_key=MetadataKey.gos_level3_lamp_status,
188
+ ip_task_types=TaskName.solar_gain,
189
+ ),
190
+ TaskUniqueBud(
191
+ constant_name=BudName.polcal_gos_level3_lamp_status,
192
+ metadata_key=MetadataKey.gos_level3_lamp_status,
193
+ ip_task_types=TaskName.polcal,
194
+ ),
195
+ TaskUniqueBud(
196
+ constant_name=BudName.dark_gos_polarizer_status,
197
+ metadata_key=MetadataKey.gos_polarizer_status,
198
+ ip_task_types=TaskName.dark,
199
+ ),
200
+ TaskUniqueBud(
201
+ constant_name=BudName.solar_gain_gos_polarizer_status,
202
+ metadata_key=MetadataKey.gos_polarizer_status,
203
+ ip_task_types=TaskName.solar_gain,
204
+ ),
205
+ TaskUniqueBud(
206
+ constant_name=BudName.polcal_gos_polarizer_status,
207
+ metadata_key=MetadataKey.gos_polarizer_status,
208
+ ip_task_types=TaskName.polcal,
209
+ ),
210
+ TaskUniqueBud(
211
+ constant_name=BudName.dark_gos_polarizer_angle,
212
+ metadata_key=MetadataKey.gos_polarizer_angle,
213
+ ip_task_types=TaskName.dark,
214
+ ),
215
+ TaskUniqueBud(
216
+ constant_name=BudName.solar_gain_gos_polarizer_angle,
217
+ metadata_key=MetadataKey.gos_polarizer_angle,
218
+ ip_task_types=TaskName.solar_gain,
219
+ ),
220
+ TaskUniqueBud(
221
+ constant_name=BudName.polcal_gos_polarizer_angle,
222
+ metadata_key=MetadataKey.gos_polarizer_angle,
223
+ ip_task_types=TaskName.polcal,
224
+ ),
225
+ TaskUniqueBud(
226
+ constant_name=BudName.dark_gos_retarder_status,
227
+ metadata_key=MetadataKey.gos_retarder_status,
228
+ ip_task_types=TaskName.dark,
229
+ ),
230
+ TaskUniqueBud(
231
+ constant_name=BudName.solar_gain_gos_retarder_status,
232
+ metadata_key=MetadataKey.gos_retarder_status,
233
+ ip_task_types=TaskName.solar_gain,
234
+ ),
235
+ TaskUniqueBud(
236
+ constant_name=BudName.polcal_gos_retarder_status,
237
+ metadata_key=MetadataKey.gos_retarder_status,
238
+ ip_task_types=TaskName.polcal,
239
+ ),
240
+ TaskUniqueBud(
241
+ constant_name=BudName.dark_gos_retarder_angle,
242
+ metadata_key=MetadataKey.gos_retarder_angle,
243
+ ip_task_types=TaskName.dark,
244
+ ),
245
+ TaskUniqueBud(
246
+ constant_name=BudName.solar_gain_gos_retarder_angle,
247
+ metadata_key=MetadataKey.gos_retarder_angle,
248
+ ip_task_types=TaskName.solar_gain,
249
+ ),
250
+ TaskUniqueBud(
251
+ constant_name=BudName.polcal_gos_retarder_angle,
252
+ metadata_key=MetadataKey.gos_retarder_angle,
253
+ ip_task_types=TaskName.polcal,
254
+ ),
255
+ TaskUniqueBud(
256
+ constant_name=BudName.dark_gos_level0_status,
257
+ metadata_key=MetadataKey.gos_level0_status,
258
+ ip_task_types=TaskName.dark,
259
+ ),
260
+ TaskUniqueBud(
261
+ constant_name=BudName.solar_gain_gos_level0_status,
262
+ metadata_key=MetadataKey.gos_level0_status,
263
+ ip_task_types=TaskName.solar_gain,
264
+ ),
265
+ TaskUniqueBud(
266
+ constant_name=BudName.polcal_gos_level0_status,
267
+ metadata_key=MetadataKey.gos_level0_status,
268
+ ip_task_types=TaskName.polcal,
269
+ ),
270
+ TaskAverageBud(
271
+ constant_name=BudName.dark_average_light_level,
272
+ metadata_key=MetadataKey.light_level,
273
+ ip_task_types=TaskName.dark,
274
+ ),
275
+ TaskAverageBud(
276
+ constant_name=BudName.solar_gain_average_light_level,
277
+ metadata_key=MetadataKey.light_level,
278
+ ip_task_types=TaskName.solar_gain,
279
+ ),
280
+ TaskAverageBud(
281
+ constant_name=BudName.polcal_average_light_level,
282
+ metadata_key=MetadataKey.light_level,
283
+ ip_task_types=TaskName.polcal,
284
+ ),
285
+ TaskAverageBud(
286
+ constant_name=BudName.dark_average_telescope_elevation,
287
+ metadata_key=MetadataKey.elevation,
288
+ ip_task_types=TaskName.dark,
289
+ ),
290
+ TaskAverageBud(
291
+ constant_name=BudName.solar_gain_average_telescope_elevation,
292
+ metadata_key=MetadataKey.elevation,
293
+ ip_task_types=TaskName.solar_gain,
294
+ ),
295
+ TaskAverageBud(
296
+ constant_name=BudName.polcal_average_telescope_elevation,
297
+ metadata_key=MetadataKey.elevation,
298
+ ip_task_types=TaskName.polcal,
299
+ ),
300
+ TaskAverageBud(
301
+ constant_name=BudName.dark_average_coude_table_angle,
302
+ metadata_key=MetadataKey.table_angle,
303
+ ip_task_types=TaskName.dark,
304
+ ),
305
+ TaskAverageBud(
306
+ constant_name=BudName.solar_gain_average_coude_table_angle,
307
+ metadata_key=MetadataKey.table_angle,
308
+ ip_task_types=TaskName.solar_gain,
309
+ ),
310
+ TaskAverageBud(
311
+ constant_name=BudName.polcal_average_coude_table_angle,
312
+ metadata_key=MetadataKey.table_angle,
313
+ ip_task_types=TaskName.polcal,
314
+ ),
315
+ TaskAverageBud(
316
+ constant_name=BudName.dark_average_telescope_azimuth,
317
+ metadata_key=MetadataKey.azimuth,
318
+ ip_task_types=TaskName.dark,
319
+ ),
320
+ TaskAverageBud(
321
+ constant_name=BudName.solar_gain_average_telescope_azimuth,
322
+ metadata_key=MetadataKey.azimuth,
323
+ ip_task_types=TaskName.solar_gain,
324
+ ),
325
+ TaskAverageBud(
326
+ constant_name=BudName.polcal_average_telescope_azimuth,
327
+ metadata_key=MetadataKey.azimuth,
328
+ ip_task_types=TaskName.polcal,
329
+ ),
330
+ TaskDateBeginBud(
331
+ constant_name=BudName.dark_date_begin,
332
+ ip_task_types=TaskName.dark,
333
+ ),
334
+ TaskDateBeginBud(
335
+ constant_name=BudName.solar_gain_date_begin,
336
+ ip_task_types=TaskName.solar_gain,
337
+ ),
338
+ TaskDateBeginBud(
339
+ constant_name=BudName.polcal_date_begin,
340
+ ip_task_types=TaskName.polcal,
341
+ ),
342
+ ]
343
+
344
+
62
345
  def default_constant_bud_factory() -> list[S]:
63
346
  """Provide default constant buds for use in common parsing tasks."""
64
- return [
347
+ return dataset_extra_bud_factory() + [
65
348
  UniqueBud(constant_name=BudName.instrument, metadata_key=MetadataKey.instrument),
66
349
  ProposalIdBud(),
67
350
  ContributingProposalIdsBud(),
@@ -4,7 +4,6 @@ import numpy as np
4
4
  import pytest
5
5
  from astropy.io import fits
6
6
 
7
- from dkist_processing_common.models.fits_access import NOT_FOUND_MESSAGE
8
7
  from dkist_processing_common.models.fits_access import FitsAccessBase
9
8
  from dkist_processing_common.models.fits_access import MetadataKey
10
9
  from dkist_processing_common.parsers.l0_fits_access import L0FitsAccess
@@ -99,30 +98,16 @@ def hdu_with_no_data(complete_common_header):
99
98
  @pytest.fixture()
100
99
  def hdu_with_incomplete_common_header(complete_common_header):
101
100
  """
102
- An HDU with data and a header missing one of the expected common by-frame keywords
101
+ An HDU with data and a header missing two of the expected common by-frame keywords
103
102
  """
104
103
  incomplete_header = complete_common_header
105
- incomplete_header.pop("ELEV_ANG")
106
- incomplete_header.pop("TAZIMUTH")
104
+ incomplete_header.pop(MetadataKey.elevation)
105
+ incomplete_header.pop(MetadataKey.azimuth)
107
106
  data = np.arange(9).reshape(3, 3)
108
107
  hdu = fits.PrimaryHDU(data, header=incomplete_header)
109
108
  return hdu
110
109
 
111
110
 
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
-
126
111
  @pytest.fixture()
127
112
  def fits_file_path(tmp_path, complete_common_header):
128
113
  file_path = tmp_path / "foo.fits"
@@ -155,35 +140,36 @@ class MetadataKeyWithNaxisKeys(StrEnum):
155
140
  class FitsAccessWithNaxisKeys(FitsAccessBase):
156
141
  def __init__(self, hdu, name):
157
142
  super().__init__(hdu, name)
158
- self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis)
159
- self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis1)
160
- self._set_metadata_key_value(MetadataKeyWithNaxisKeys.naxis2)
143
+ self.naxis = self.header[MetadataKeyWithNaxisKeys.naxis]
144
+ self.naxis1 = self.header[MetadataKeyWithNaxisKeys.naxis1]
145
+ self.naxis2 = self.header[MetadataKeyWithNaxisKeys.naxis2]
161
146
 
162
147
 
163
148
  def test_metadata_keys_in_access_bases(hdu_with_no_data):
164
149
  """
165
150
  Given: a set of metadata key names in the MetadataKey sting enumeration
166
151
  When: the FITS access classes define a set of attributes/properties
167
- Then: the sets are the same
152
+ Then: the sets are the same and the values of the attributes/properties are correct
168
153
  """
169
154
  all_metadata_key_names = {mk.name for mk in MetadataKey}
170
155
  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
156
+ fits_obj = L0FitsAccess(hdu=hdu)
157
+ fits_access_defined_attributes = {
158
+ k for k, v in fits_obj.__dict__.items() if k not in ["_hdu", "name", "auto_squeeze"]
159
+ }
160
+ l0_access_properties = {k for k, v in L0FitsAccess.__dict__.items() if isinstance(v, property)}
161
+ l1_access_properties = {k for k, v in L1FitsAccess.__dict__.items() if isinstance(v, property)}
162
+ fits_access_properties = l0_access_properties | l1_access_properties
163
+ assert fits_access_defined_attributes | fits_access_properties == all_metadata_key_names
164
+ for key in fits_access_defined_attributes:
165
+ assert getattr(fits_obj, key) == fits_obj.header[MetadataKey[key]]
180
166
 
181
167
 
182
168
  def test_from_single_hdu(hdu_with_complete_common_header):
183
169
  """
184
170
  Given: an HDU with expected, common by-frame keywords
185
171
  When: loading the HDU with the L0FitsAccess class
186
- Then: all values for common keywords are exposed as properties on the fits_obj class
172
+ Then: values for common keywords are exposed as properties on the fits_obj class
187
173
  """
188
174
  fits_obj = L0FitsAccess(hdu_with_complete_common_header)
189
175
  assert fits_obj.elevation == 6.28
@@ -198,7 +184,7 @@ def test_l1_only_fits_access(hdu_with_complete_l1_only_header):
198
184
  """
199
185
  Given: an HDU with 214 L1-only headers
200
186
  When: loading the HDU with the L1FitsAccess class
201
- Then: no errors are raised and all values are exposed
187
+ Then: no errors are raised and values are exposed
202
188
  """
203
189
  fits_obj = L1FitsAccess(hdu_with_complete_l1_only_header)
204
190
  assert fits_obj.elevation == 6.28
@@ -255,17 +241,6 @@ def test_no_header_value(hdu_with_incomplete_common_header):
255
241
  _ = L0FitsAccess(hdu_with_incomplete_common_header)
256
242
 
257
243
 
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
-
269
244
  def test_as_subclass(hdu_with_complete_common_header):
270
245
  """
271
246
  Given: an instrument-specific fits_obj class that subclasses L0FitsAccess
@@ -97,9 +97,9 @@ class ViSPMetadataKey(StrEnum):
97
97
  class ViSPFitsAccess(FitsAccessBase):
98
98
  def __init__(self, hdu, name, auto_squeeze=False):
99
99
  super().__init__(hdu, name, auto_squeeze=auto_squeeze)
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)
100
+ self.num_mod: int = self.header[ViSPMetadataKey.num_mod]
101
+ self.modstate: int = self.header[ViSPMetadataKey.modstate]
102
+ self.ip_task_type: str = self.header[ViSPMetadataKey.ip_task_type]
103
103
  self.name = name
104
104
 
105
105
 
@@ -260,18 +260,52 @@ def test_subclass_flowers(visp_parse_inputs_task, max_cs_step_time_sec):
260
260
  tag_pot, constant_pot = visp_parse_inputs_task.make_flower_pots()
261
261
 
262
262
  assert len(tag_pot.stems) == 1
263
- assert len(constant_pot.stems) == 12
263
+ assert len(constant_pot.stems) == 71
264
264
  all_flower_names = [StemName.modstate]
265
265
  assert sorted([f.stem_name for f in tag_pot.stems]) == sorted(all_flower_names)
266
266
  all_bud_names = [b.stem_name for b in default_constant_bud_factory()] + [BudName.num_modstates]
267
267
  assert sorted([f.stem_name for f in constant_pot.stems]) == sorted(all_bud_names)
268
268
 
269
269
 
270
+ def test_dataset_extra_bud_factory(visp_parse_inputs_task, max_cs_step_time_sec):
271
+ """
272
+ Given: ParseInputData child class with custom stems
273
+ When: Making the constant pot
274
+ Then: The multi-task dataset extra buds are all created
275
+ """
276
+ _, constant_pot = visp_parse_inputs_task.make_flower_pots()
277
+ stem_names = [f.stem_name.value for f in constant_pot.stems]
278
+ bud_name_base = [
279
+ "DATE_BEGIN",
280
+ "OBSERVING_PROGRAM_EXECUTION_ID",
281
+ "NUM_RAW_FRAMES_PER_FPA",
282
+ "TELESCOPE_TRACKING_MODE",
283
+ "COUDE_TABLE_TRACKING_MODE",
284
+ "TELESCOPE_SCANNING_MODE",
285
+ "AVERAGE_LIGHT_LEVEL",
286
+ "AVERAGE_TELESCOPE_ELEVATION",
287
+ "AVERAGE_COUDE_TABLE_ANGLE",
288
+ "AVERAGE_TELESCOPE_AZIMUTH",
289
+ "GOS_LEVEL3_STATUS",
290
+ "GOS_LEVEL3_LAMP_STATUS",
291
+ "GOS_POLARIZER_STATUS",
292
+ "GOS_POLARIZER_ANGLE",
293
+ "GOS_RETARDER_STATUS",
294
+ "GOS_RETARDER_ANGLE",
295
+ "GOS_LEVEL0_STATUS",
296
+ ]
297
+ bud_name_prefix = ["DARK_", "SOLAR_GAIN_", "POLCAL_"]
298
+ for prefix in bud_name_prefix:
299
+ for base in bud_name_base:
300
+ print(prefix + base)
301
+ assert prefix + base in stem_names
302
+
303
+
270
304
  def test_constants_correct(parse_inputs_task):
271
305
  """
272
306
  Given: ParseInputData task with a populated constant FlowerPot
273
307
  When: Updating pipeline constants
274
- Then: Pipeline constants are correctly populated
308
+ Then: A pipeline constant is correctly populated
275
309
  """
276
310
  _, constant_pot = parse_inputs_task.make_flower_pots()
277
311
  parse_inputs_task.update_constants(constant_pot)