dkist-processing-common 11.6.0rc1__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 (29) 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/models/telemetry.py +9 -2
  10. dkist_processing_common/parsers/average_bud.py +48 -0
  11. dkist_processing_common/parsers/experiment_id_bud.py +8 -4
  12. dkist_processing_common/parsers/id_bud.py +35 -17
  13. dkist_processing_common/parsers/l0_fits_access.py +3 -3
  14. dkist_processing_common/parsers/l1_fits_access.py +47 -21
  15. dkist_processing_common/parsers/near_bud.py +4 -4
  16. dkist_processing_common/parsers/proposal_id_bud.py +11 -5
  17. dkist_processing_common/parsers/single_value_single_key_flower.py +0 -1
  18. dkist_processing_common/parsers/time.py +141 -27
  19. dkist_processing_common/tasks/base.py +21 -3
  20. dkist_processing_common/tasks/parse_l0_input_data.py +289 -36
  21. dkist_processing_common/tests/test_fits_access.py +19 -44
  22. dkist_processing_common/tests/test_parse_l0_input_data.py +39 -5
  23. dkist_processing_common/tests/test_stems.py +127 -10
  24. dkist_processing_common/tests/test_task_parsing.py +6 -6
  25. {dkist_processing_common-11.6.0rc1.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/METADATA +3 -3
  26. {dkist_processing_common-11.6.0rc1.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/RECORD +28 -22
  27. changelog/268.misc.rst +0 -1
  28. {dkist_processing_common-11.6.0rc1.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/WHEEL +0 -0
  29. {dkist_processing_common-11.6.0rc1.dist-info → dkist_processing_common-11.7.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ Add new bud types TaskAverageBud and TaskBeginDateBud, which is based on new TaskDatetimeBudBase.
@@ -0,0 +1 @@
1
+ Add new bud type TaskContributingIdsBud, based on ContributingIdsBud, for for specific task types.
@@ -0,0 +1 @@
1
+ Add new buds to parsing for what will become the dataset extras.
changelog/267.misc.rst ADDED
@@ -0,0 +1 @@
1
+ Rename TimeFlowerBase and TaskTimeBudBase to RoundTimeFlowerBase and TaskRoundTimeBudBase, respectively.
@@ -0,0 +1,2 @@
1
+ Remove the `_set_metadata_key_value` method from FitsAccessBase. Instead of using `setattr`, attributes
2
+ are assigned explicitly in access classes using `MetadataKey` members in place of header key strings.
@@ -0,0 +1 @@
1
+ Remove IdBud, which is just a TaskUniqueBud with the task set to observe, and therefore is not needed.
@@ -6,6 +6,7 @@ accessing the database (tab completion, etc.)
6
6
  """
7
7
 
8
8
  from enum import StrEnum
9
+ from enum import unique
9
10
  from string import ascii_uppercase
10
11
 
11
12
  from sqids import Sqids
@@ -13,6 +14,7 @@ from sqids import Sqids
13
14
  from dkist_processing_common._util.constants import ConstantsDb
14
15
 
15
16
 
17
+ @unique
16
18
  class BudName(StrEnum):
17
19
  """Controlled list of names for constant stems (buds)."""
18
20
 
@@ -33,6 +35,69 @@ class BudName(StrEnum):
33
35
  dark_exposure_times = "DARK_EXPOSURE_TIMES"
34
36
  dark_readout_exp_times = "DARK_READOUT_EXP_TIMES"
35
37
  wavelength = "WAVELENGTH"
38
+ camera_id = "CAMERA_ID"
39
+ camera_name = "CAMERA_NAME"
40
+ camera_bit_depth = "CAMERA_BIT_DEPTH"
41
+ hardware_binning_x = "HARDWARE_BINNING_X"
42
+ hardware_binning_y = "HARDWARE_BINNING_Y"
43
+ software_binning_x = "SOFTWARE_BINNING_X"
44
+ software_binning_y = "SOFTWARE_BINNING_Y"
45
+ hls_version = "HLS_VERSION"
46
+ # Multi-task buds start here:
47
+ dark_observing_program_execution_id = "DARK_OBSERVING_PROGRAM_EXECUTION_ID"
48
+ solar_gain_observing_program_execution_id = "SOLAR_GAIN_OBSERVING_PROGRAM_EXECUTION_ID"
49
+ polcal_observing_program_execution_id = "POLCAL_OBSERVING_PROGRAM_EXECUTION_ID"
50
+ dark_date_begin = "DARK_DATE_BEGIN"
51
+ solar_gain_date_begin = "SOLAR_GAIN_DATE_BEGIN"
52
+ polcal_date_begin = "POLCAL_DATE_BEGIN"
53
+ dark_date_end = "DARK_DATE_END"
54
+ solar_gain_date_end = "SOLAR_GAIN_DATE_END"
55
+ polcal_date_end = "POLCAL_DATE_END"
56
+ dark_num_raw_frames_per_fpa = "DARK_NUM_RAW_FRAMES_PER_FPA"
57
+ solar_gain_num_raw_frames_per_fpa = "SOLAR_GAIN_NUM_RAW_FRAMES_PER_FPA"
58
+ polcal_num_raw_frames_per_fpa = "POLCAL_NUM_RAW_FRAMES_PER_FPA"
59
+ dark_telescope_tracking_mode = "DARK_TELESCOPE_TRACKING_MODE"
60
+ solar_gain_telescope_tracking_mode = "SOLAR_GAIN_TELESCOPE_TRACKING_MODE"
61
+ polcal_telescope_tracking_mode = "POLCAL_TELESCOPE_TRACKING_MODE"
62
+ dark_coude_table_tracking_mode = "DARK_COUDE_TABLE_TRACKING_MODE"
63
+ solar_gain_coude_table_tracking_mode = "SOLAR_GAIN_COUDE_TABLE_TRACKING_MODE"
64
+ polcal_coude_table_tracking_mode = "POLCAL_COUDE_TABLE_TRACKING_MODE"
65
+ dark_telescope_scanning_mode = "DARK_TELESCOPE_SCANNING_MODE"
66
+ solar_gain_telescope_scanning_mode = "SOLAR_GAIN_TELESCOPE_SCANNING_MODE"
67
+ polcal_telescope_scanning_mode = "POLCAL_TELESCOPE_SCANNING_MODE"
68
+ dark_average_light_level = "DARK_AVERAGE_LIGHT_LEVEL"
69
+ solar_gain_average_light_level = "SOLAR_GAIN_AVERAGE_LIGHT_LEVEL"
70
+ polcal_average_light_level = "POLCAL_AVERAGE_LIGHT_LEVEL"
71
+ dark_average_telescope_elevation = "DARK_AVERAGE_TELESCOPE_ELEVATION"
72
+ solar_gain_average_telescope_elevation = "SOLAR_GAIN_AVERAGE_TELESCOPE_ELEVATION"
73
+ polcal_average_telescope_elevation = "POLCAL_AVERAGE_TELESCOPE_ELEVATION"
74
+ dark_average_coude_table_angle = "DARK_AVERAGE_COUDE_TABLE_ANGLE"
75
+ solar_gain_average_coude_table_angle = "SOLAR_GAIN_AVERAGE_COUDE_TABLE_ANGLE"
76
+ polcal_average_coude_table_angle = "POLCAL_AVERAGE_COUDE_TABLE_ANGLE"
77
+ dark_average_telescope_azimuth = "DARK_AVERAGE_TELESCOPE_AZIMUTH"
78
+ solar_gain_average_telescope_azimuth = "SOLAR_GAIN_AVERAGE_TELESCOPE_AZIMUTH"
79
+ polcal_average_telescope_azimuth = "POLCAL_AVERAGE_TELESCOPE_AZIMUTH"
80
+ dark_gos_level3_status = "DARK_GOS_LEVEL3_STATUS"
81
+ solar_gain_gos_level3_status = "SOLAR_GAIN_GOS_LEVEL3_STATUS"
82
+ polcal_gos_level3_status = "POLCAL_GOS_LEVEL3_STATUS"
83
+ dark_gos_level3_lamp_status = "DARK_GOS_LEVEL3_LAMP_STATUS"
84
+ solar_gain_gos_level3_lamp_status = "SOLAR_GAIN_GOS_LEVEL3_LAMP_STATUS"
85
+ polcal_gos_level3_lamp_status = "POLCAL_GOS_LEVEL3_LAMP_STATUS"
86
+ dark_gos_polarizer_status = "DARK_GOS_POLARIZER_STATUS"
87
+ solar_gain_gos_polarizer_status = "SOLAR_GAIN_GOS_POLARIZER_STATUS"
88
+ polcal_gos_polarizer_status = "POLCAL_GOS_POLARIZER_STATUS"
89
+ dark_gos_polarizer_angle = "DARK_GOS_POLARIZER_ANGLE"
90
+ solar_gain_gos_polarizer_angle = "SOLAR_GAIN_GOS_POLARIZER_ANGLE"
91
+ polcal_gos_polarizer_angle = "POLCAL_GOS_POLARIZER_ANGLE"
92
+ dark_gos_retarder_status = "DARK_GOS_RETARDER_STATUS"
93
+ solar_gain_gos_retarder_status = "SOLAR_GAIN_GOS_RETARDER_STATUS"
94
+ polcal_gos_retarder_status = "POLCAL_GOS_RETARDER_STATUS"
95
+ dark_gos_retarder_angle = "DARK_GOS_RETARDER_ANGLE"
96
+ solar_gain_gos_retarder_angle = "SOLAR_GAIN_GOS_RETARDER_ANGLE"
97
+ polcal_gos_retarder_angle = "POLCAL_GOS_RETARDER_ANGLE"
98
+ dark_gos_level0_status = "DARK_GOS_LEVEL0_STATUS"
99
+ solar_gain_gos_level0_status = "SOLAR_GAIN_GOS_LEVEL0_STATUS"
100
+ polcal_gos_level0_status = "POLCAL_GOS_LEVEL0_STATUS"
36
101
 
37
102
 
38
103
  class ConstantsBase:
@@ -87,7 +152,7 @@ class ConstantsBase:
87
152
 
88
153
  @property
89
154
  def dataset_id(self) -> str:
90
- """Define the dataset_id constant."""
155
+ """Define the dataset id constant."""
91
156
  return Sqids(min_length=6, alphabet=ascii_uppercase).encode([self._recipe_run_id])
92
157
 
93
158
  @property
@@ -101,45 +166,41 @@ class ConstantsBase:
101
166
  return self._db_dict[BudName.instrument]
102
167
 
103
168
  @property
104
- def num_cs_steps(self):
169
+ def num_cs_steps(self) -> int:
105
170
  """Get the number of calibration sequence steps."""
106
171
  return self._db_dict[BudName.num_cs_steps]
107
172
 
108
173
  @property
109
- def num_modstates(self):
174
+ def num_modstates(self) -> int:
110
175
  """Get the number of modulation states."""
111
176
  return self._db_dict[BudName.num_modstates]
112
177
 
113
178
  @property
114
- def retarder_name(self):
179
+ def retarder_name(self) -> str:
115
180
  """Get the retarder name."""
116
181
  return self._db_dict[BudName.retarder_name]
117
182
 
118
183
  @property
119
184
  def proposal_id(self) -> str:
120
- """Get the proposal_id constant."""
185
+ """Get the proposal ID constant."""
121
186
  return self._db_dict[BudName.proposal_id]
122
187
 
123
188
  @property
124
189
  def contributing_proposal_ids(self) -> [str]:
125
190
  """Return the list of contributing proposal IDs."""
126
191
  proposal_ids = self._db_dict[BudName.contributing_proposal_ids]
127
- if isinstance(proposal_ids, str):
128
- return [proposal_ids]
129
- return proposal_ids
192
+ return list(proposal_ids)
130
193
 
131
194
  @property
132
195
  def experiment_id(self) -> str:
133
- """Get the experiment_id constant."""
196
+ """Get the experiment ID constant."""
134
197
  return self._db_dict[BudName.experiment_id]
135
198
 
136
199
  @property
137
200
  def contributing_experiment_ids(self) -> [str]:
138
201
  """Return the list of contributing experiment IDs."""
139
202
  experiment_ids = self._db_dict[BudName.contributing_experiment_ids]
140
- if isinstance(experiment_ids, str):
141
- return [experiment_ids]
142
- return experiment_ids
203
+ return list(experiment_ids)
143
204
 
144
205
  @property
145
206
  def obs_ip_start_time(self) -> str:
@@ -148,7 +209,7 @@ class ConstantsBase:
148
209
 
149
210
  @property
150
211
  def average_cadence(self) -> float:
151
- """Get the average_cadence constant."""
212
+ """Get the average cadence constant."""
152
213
  return self._db_dict[BudName.average_cadence]
153
214
 
154
215
  @property
@@ -174,14 +235,331 @@ class ConstantsBase:
174
235
  @property
175
236
  def dark_exposure_times(self) -> [float]:
176
237
  """Get a list of exposure times used in the dark calibration."""
177
- return self._db_dict[BudName.dark_exposure_times]
238
+ exposure_times = self._db_dict[BudName.dark_exposure_times]
239
+ return list(exposure_times)
178
240
 
179
241
  @property
180
242
  def dark_readout_exp_times(self) -> [float]:
181
- """Get a list of readout exp times for all DARK frames."""
182
- return self._db_dict[BudName.dark_readout_exp_times]
243
+ """Get a list of readout exp times for all dark frames."""
244
+ readout_times = self._db_dict[BudName.dark_readout_exp_times]
245
+ return list(readout_times)
183
246
 
184
247
  @property
185
248
  def wavelength(self) -> float:
186
249
  """Wavelength."""
187
250
  return self._db_dict[BudName.wavelength]
251
+
252
+ @property
253
+ def camera_id(self) -> str:
254
+ """Return the camera ID constant."""
255
+ return self._db_dict[BudName.camera_id]
256
+
257
+ @property
258
+ def camera_name(self) -> str:
259
+ """Return the camera name for humans constant."""
260
+ return self._db_dict[BudName.camera_name]
261
+
262
+ @property
263
+ def camera_bit_depth(self) -> int:
264
+ """Return the camera bit depth constant."""
265
+ return self._db_dict[BudName.camera_bit_depth]
266
+
267
+ @property
268
+ def hardware_binning_x(self) -> int:
269
+ """Return the x-direction hardware binning constant."""
270
+ return self._db_dict[BudName.hardware_binning_x]
271
+
272
+ @property
273
+ def hardware_binning_y(self) -> int:
274
+ """Return the y-direction hardware binning constant."""
275
+ return self._db_dict[BudName.hardware_binning_y]
276
+
277
+ @property
278
+ def software_binning_x(self) -> int:
279
+ """Return the x-direction software binning constant."""
280
+ return self._db_dict[BudName.software_binning_x]
281
+
282
+ @property
283
+ def software_binning_y(self) -> int:
284
+ """Return the y-direction software binning constant."""
285
+ return self._db_dict[BudName.software_binning_y]
286
+
287
+ @property
288
+ def hls_version(self) -> str:
289
+ """Return the High-Level Software version."""
290
+ return self._db_dict[BudName.hls_version]
291
+
292
+ # Multi-task constants start here:
293
+
294
+ @property
295
+ def dark_observing_program_execution_id(self) -> [str]:
296
+ """Return the observing program execution id constant for the dark task."""
297
+ observing_programs = self._db_dict[BudName.dark_observing_program_execution_id]
298
+ return list(observing_programs)
299
+
300
+ @property
301
+ def solar_gain_observing_program_execution_id(self) -> [str]:
302
+ """Return the observing program execution id constant for the solar_gain task."""
303
+ observing_programs = self._db_dict[BudName.solar_gain_observing_program_execution_id]
304
+ return list(observing_programs)
305
+
306
+ @property
307
+ def polcal_observing_program_execution_id(self) -> [str]:
308
+ """Return the observing program execution id constant."""
309
+ observing_programs = self._db_dict[BudName.polcal_observing_program_execution_id]
310
+ return list(observing_programs)
311
+
312
+ @property
313
+ def dark_date_begin(self) -> str:
314
+ """Return the date begin header constant for the dark task."""
315
+ return self._db_dict[BudName.dark_date_begin]
316
+
317
+ @property
318
+ def solar_gain_date_begin(self) -> str:
319
+ """Return the date begin header constant for the solar gain task."""
320
+ return self._db_dict[BudName.solar_gain_date_begin]
321
+
322
+ @property
323
+ def polcal_date_begin(self) -> str:
324
+ """Return the time obs header constant for the polcal task."""
325
+ return self._db_dict[BudName.polcal_date_begin]
326
+
327
+ @property
328
+ def dark_date_end(self) -> str:
329
+ """Return the date end constant for the dark task."""
330
+ return self._db_dict[BudName.dark_date_end]
331
+
332
+ @property
333
+ def solar_gain_date_end(self) -> str:
334
+ """Return the date end constant for the solar gain task."""
335
+ return self._db_dict[BudName.solar_gain_date_end]
336
+
337
+ @property
338
+ def polcal_date_end(self) -> str:
339
+ """Return the date end constant for the polcal task."""
340
+ return self._db_dict[BudName.polcal_date_end]
341
+
342
+ @property
343
+ def dark_num_raw_frames_per_fpa(self) -> int:
344
+ """Return the number of raw frames per fpa constant for the dark task."""
345
+ return self._db_dict[BudName.dark_num_raw_frames_per_fpa]
346
+
347
+ @property
348
+ def solar_gain_num_raw_frames_per_fpa(self) -> int:
349
+ """Return the number of raw frames per fpa constant for the solar gain task."""
350
+ return self._db_dict[BudName.solar_gain_num_raw_frames_per_fpa]
351
+
352
+ @property
353
+ def polcal_num_raw_frames_per_fpa(self) -> int:
354
+ """Return the num raw frames per fpa constant for the polcal task."""
355
+ return self._db_dict[BudName.polcal_num_raw_frames_per_fpa]
356
+
357
+ @property
358
+ def dark_telescope_tracking_mode(self) -> str:
359
+ """Return the telescope tracking mode constant for the dark task."""
360
+ return self._db_dict[BudName.dark_telescope_tracking_mode]
361
+
362
+ @property
363
+ def solar_gain_telescope_tracking_mode(self) -> str:
364
+ """Return the telescope tracking mode constant for the solar gain task."""
365
+ return self._db_dict[BudName.solar_gain_telescope_tracking_mode]
366
+
367
+ @property
368
+ def polcal_telescope_tracking_mode(self) -> str:
369
+ """Return the telescope tracking mode constant for the polcal task."""
370
+ return self._db_dict[BudName.polcal_telescope_tracking_mode]
371
+
372
+ @property
373
+ def dark_coude_table_tracking_mode(self) -> str:
374
+ """Return the coude table tracking mode constant for the dark task."""
375
+ return self._db_dict[BudName.dark_coude_table_tracking_mode]
376
+
377
+ @property
378
+ def solar_gain_coude_table_tracking_mode(self) -> str:
379
+ """Return the coude table tracking mode constant for the solar gain task."""
380
+ return self._db_dict[BudName.solar_gain_coude_table_tracking_mode]
381
+
382
+ @property
383
+ def polcal_coude_table_tracking_mode(self) -> str:
384
+ """Return the coude table tracking mode constant for the polcal task."""
385
+ return self._db_dict[BudName.polcal_coude_table_tracking_mode]
386
+
387
+ @property
388
+ def dark_telescope_scanning_mode(self) -> str:
389
+ """Return the telescope scanning mode constant for the dark task."""
390
+ return self._db_dict[BudName.dark_telescope_scanning_mode]
391
+
392
+ @property
393
+ def solar_gain_telescope_scanning_mode(self) -> str:
394
+ """Return the telescope scanning mode constant for the solar gain task."""
395
+ return self._db_dict[BudName.solar_gain_telescope_scanning_mode]
396
+
397
+ @property
398
+ def polcal_telescope_scanning_mode(self) -> str:
399
+ """Return the telescope scanning mode constant for the polcal task."""
400
+ return self._db_dict[BudName.polcal_telescope_scanning_mode]
401
+
402
+ @property
403
+ def dark_average_light_level(self) -> float:
404
+ """Return the average light level constant for the dark task."""
405
+ return self._db_dict[BudName.dark_average_light_level]
406
+
407
+ @property
408
+ def solar_gain_average_light_level(self) -> float:
409
+ """Return the average light level constant for the solar gain task."""
410
+ return self._db_dict[BudName.solar_gain_average_light_level]
411
+
412
+ @property
413
+ def polcal_average_light_level(self) -> float:
414
+ """Return the average light level constant for the polcal task."""
415
+ return self._db_dict[BudName.polcal_average_light_level]
416
+
417
+ @property
418
+ def dark_average_telescope_elevation(self) -> float:
419
+ """Return the average telescope elevation constant for the dark task."""
420
+ return self._db_dict[BudName.dark_average_telescope_elevation]
421
+
422
+ @property
423
+ def solar_gain_average_telescope_elevation(self) -> float:
424
+ """Return the average telescope elevation constant for the solar gain task."""
425
+ return self._db_dict[BudName.solar_gain_average_telescope_elevation]
426
+
427
+ @property
428
+ def polcal_average_telescope_elevation(self) -> float:
429
+ """Return the average telescope elevation constant for the polcal task."""
430
+ return self._db_dict[BudName.polcal_average_telescope_elevation]
431
+
432
+ @property
433
+ def dark_average_coude_table_angle(self) -> float:
434
+ """Return the average coude table angle constant for the dark task."""
435
+ return self._db_dict[BudName.dark_average_coude_table_angle]
436
+
437
+ @property
438
+ def solar_gain_average_coude_table_angle(self) -> float:
439
+ """Return the average coude table angle constant for the solar gain task."""
440
+ return self._db_dict[BudName.solar_gain_average_coude_table_angle]
441
+
442
+ @property
443
+ def polcal_average_coude_table_angle(self) -> float:
444
+ """Return the average coude table angle constant for the polcal task."""
445
+ return self._db_dict[BudName.polcal_average_coude_table_angle]
446
+
447
+ @property
448
+ def dark_average_telescope_azimuth(self) -> float:
449
+ """Return the average telescope azimuth constant for the dark task."""
450
+ return self._db_dict[BudName.dark_average_telescope_azimuth]
451
+
452
+ @property
453
+ def solar_gain_average_telescope_azimuth(self) -> float:
454
+ """Return the average telescope azimuth constant for the solar gain task."""
455
+ return self._db_dict[BudName.solar_gain_average_telescope_azimuth]
456
+
457
+ @property
458
+ def polcal_average_telescope_azimuth(self) -> float:
459
+ """Return the average telescope azimuth constant for the polcal task."""
460
+ return self._db_dict[BudName.polcal_average_telescope_azimuth]
461
+
462
+ @property
463
+ def dark_gos_level3_status(self) -> str:
464
+ """Return the gos level3 status constant for the dark task."""
465
+ return self._db_dict[BudName.dark_gos_level3_status]
466
+
467
+ @property
468
+ def solar_gain_gos_level3_status(self) -> str:
469
+ """Return the gos level3 status constant for the solar gain task."""
470
+ return self._db_dict[BudName.solar_gain_gos_level3_status]
471
+
472
+ @property
473
+ def polcal_gos_level3_status(self) -> str:
474
+ """Return the gos level3 status constant for the polcal task."""
475
+ return self._db_dict[BudName.polcal_gos_level3_status]
476
+
477
+ @property
478
+ def dark_gos_level3_lamp_status(self) -> str:
479
+ """Return the gos level3 lamp status constant for the dark task."""
480
+ return self._db_dict[BudName.dark_gos_level3_lamp_status]
481
+
482
+ @property
483
+ def solar_gain_gos_level3_lamp_status(self) -> str:
484
+ """Return the gos level3 lamp status constant for the solar gain task."""
485
+ return self._db_dict[BudName.solar_gain_gos_level3_lamp_status]
486
+
487
+ @property
488
+ def polcal_gos_level3_lamp_status(self) -> str:
489
+ """Return the gos level3 lamp status constant for the polcal task."""
490
+ return self._db_dict[BudName.polcal_gos_level3_lamp_status]
491
+
492
+ @property
493
+ def dark_gos_polarizer_status(self) -> str:
494
+ """Return the gos polarizer status constant for the dark task."""
495
+ return self._db_dict[BudName.dark_gos_polarizer_status]
496
+
497
+ @property
498
+ def solar_gain_gos_polarizer_status(self) -> str:
499
+ """Return the gos polarizer status constant for the solar gain task."""
500
+ return self._db_dict[BudName.solar_gain_gos_polarizer_status]
501
+
502
+ @property
503
+ def polcal_gos_polarizer_status(self) -> str:
504
+ """Return the gos polarizer status constant for the polcal task."""
505
+ return self._db_dict[BudName.polcal_gos_polarizer_status]
506
+
507
+ @property
508
+ def dark_gos_polarizer_angle(self) -> float:
509
+ """Return the gos polarizer angle constant for the dark task."""
510
+ return self._db_dict[BudName.dark_gos_polarizer_angle]
511
+
512
+ @property
513
+ def solar_gain_gos_polarizer_angle(self) -> float:
514
+ """Return the gos polarizer angle constant for the solar gain task."""
515
+ return self._db_dict[BudName.solar_gain_gos_polarizer_angle]
516
+
517
+ @property
518
+ def polcal_gos_polarizer_angle(self) -> float:
519
+ """Return the gos polarizer angle constant for the polcal task."""
520
+ return self._db_dict[BudName.polcal_gos_polarizer_angle]
521
+
522
+ @property
523
+ def dark_gos_retarder_status(self) -> str:
524
+ """Return the gos retarder status constant for the dark task."""
525
+ return self._db_dict[BudName.dark_gos_retarder_status]
526
+
527
+ @property
528
+ def solar_gain_gos_retarder_status(self) -> str:
529
+ """Return the gos retarder status constant for the solar gain task."""
530
+ return self._db_dict[BudName.solar_gain_gos_retarder_status]
531
+
532
+ @property
533
+ def polcal_gos_retarder_status(self) -> str:
534
+ """Return the gos retarder status constant for the polcal task."""
535
+ return self._db_dict[BudName.polcal_gos_retarder_status]
536
+
537
+ @property
538
+ def dark_gos_retarder_angle(self) -> float:
539
+ """Return the gos retarder angle constant for the dark task."""
540
+ return self._db_dict[BudName.dark_gos_retarder_angle]
541
+
542
+ @property
543
+ def solar_gain_gos_retarder_angle(self) -> float:
544
+ """Return the gos retarder angle constant for the solar gain task."""
545
+ return self._db_dict[BudName.solar_gain_gos_retarder_angle]
546
+
547
+ @property
548
+ def polcal_gos_retarder_angle(self) -> float:
549
+ """Return the gos retarder angle constant for the polcal task."""
550
+ return self._db_dict[BudName.polcal_gos_retarder_angle]
551
+
552
+ @property
553
+ def dark_gos_level0_status(self) -> str:
554
+ """Return the gos level0 status constant for the dark task."""
555
+ return self._db_dict[BudName.dark_gos_level0_status]
556
+
557
+ @property
558
+ def solar_gain_gos_level0_status(self) -> str:
559
+ """Return the gos level0 status constant for the solar gain task."""
560
+ return self._db_dict[BudName.solar_gain_gos_level0_status]
561
+
562
+ @property
563
+ def polcal_gos_level0_status(self) -> str:
564
+ """Return the gos level0 status constant for the polcal task."""
565
+ return self._db_dict[BudName.polcal_gos_level0_status]
@@ -3,15 +3,16 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from enum import StrEnum
6
+ from enum import unique
6
7
  from pathlib import Path
7
- from typing import Any
8
8
 
9
9
  import numpy as np
10
10
  from astropy.io import fits
11
11
 
12
- NOT_FOUND_MESSAGE = "_HEADER_KEYWORD_NOT_FOUND"
12
+ HEADER_KEY_NOT_FOUND = "HEADER_KEY_NOT_FOUND"
13
13
 
14
14
 
15
+ @unique
15
16
  class MetadataKey(StrEnum):
16
17
  """Controlled list of names for FITS metadata header keys."""
17
18
 
@@ -39,6 +40,19 @@ class MetadataKey(StrEnum):
39
40
  fpa_exposure_time_ms = "XPOSURE"
40
41
  sensor_readout_exposure_time_ms = "TEXPOSUR"
41
42
  num_raw_frames_per_fpa = "NSUMEXP"
43
+ camera_id = "CAM_ID"
44
+ camera_name = "CAMERA"
45
+ camera_bit_depth = "BITDEPTH"
46
+ hardware_binning_x = "HWBIN1"
47
+ hardware_binning_y = "HWBIN2"
48
+ software_binning_x = "SWBIN1"
49
+ software_binning_y = "SWBIN2"
50
+ observing_program_execution_id = "OBSPR_ID"
51
+ telescope_tracking_mode = "TELTRACK"
52
+ coude_table_tracking_mode = "TTBLTRCK"
53
+ telescope_scanning_mode = "TELSCAN"
54
+ light_level = "LIGHTLVL"
55
+ hls_version = "HLSVERS"
42
56
 
43
57
 
44
58
  class FitsAccessBase:
@@ -68,29 +82,6 @@ class FitsAccessBase:
68
82
  def __repr__(self):
69
83
  return f"{self.__class__.__name__}(hdu={self._hdu!r}, name={self.name!r}, auto_squeeze={self.auto_squeeze})"
70
84
 
71
- def _set_metadata_key_value(
72
- self, key: StrEnum, optional: bool = False, default: Any = NOT_FOUND_MESSAGE
73
- ) -> None:
74
- """
75
- Get the header value and assign it as a metadata key name attribute.
76
-
77
- Parameters
78
- ----------
79
- key
80
- The StrEnum member in attribute_name = fits_keyword structure
81
- optional
82
- If the keyword is optional
83
- default
84
- Value for the attribute if the key is not found
85
- """
86
- if optional:
87
- if default != NOT_FOUND_MESSAGE:
88
- setattr(self, key.name, self.header.get(key, default))
89
- else:
90
- setattr(self, key.name, self.header.get(key, key + NOT_FOUND_MESSAGE))
91
- else:
92
- setattr(self, key.name, self.header[key])
93
-
94
85
  @property
95
86
  def data(self) -> np.ndarray:
96
87
  """
@@ -3,8 +3,8 @@
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
6
- class Progress(BaseModel, validate_assignment=True):
7
- """Container for tracking progress for a metering instrument."""
6
+ class ObservableProgress(BaseModel, validate_assignment=True):
7
+ """Container for tracking progress for a metering instrument e.g. task progress."""
8
8
 
9
9
  current: int = 0
10
10
  total: int = 0
@@ -19,3 +19,10 @@ class Progress(BaseModel, validate_assignment=True):
19
19
  if self.total > 0:
20
20
  return (self.current / self.total) * 100
21
21
  return 0.0
22
+
23
+ def set_complete(self):
24
+ """Set the current progress to the total."""
25
+ if self.total == 0:
26
+ self.total = self.current = 1
27
+ else:
28
+ self.current = self.total
@@ -0,0 +1,48 @@
1
+ """Pre-made flower that reads a single header key from all files with specific task types and returns the average."""
2
+
3
+ from enum import StrEnum
4
+ from statistics import mean
5
+ from typing import Callable
6
+ from typing import Hashable
7
+
8
+ import numpy as np
9
+
10
+ from dkist_processing_common.parsers.near_bud import TaskNearFloatBud
11
+ from dkist_processing_common.parsers.task import passthrough_header_ip_task
12
+
13
+
14
+ class TaskAverageBud(TaskNearFloatBud):
15
+ """
16
+ Pre-made bud that returns the average of a single header key from all files with specific task types.
17
+
18
+ Parameters
19
+ ----------
20
+ constant_name
21
+ The name for the constant to be defined
22
+
23
+ metadata_key
24
+ The metadata key associated with the constant
25
+
26
+ ip_task_types
27
+ Only consider objects whose parsed header IP task type matches a string in this list
28
+
29
+ task_type_parsing_function
30
+ The function used to convert a header into an IP task type
31
+ """
32
+
33
+ key_to_petal_dict: dict[str, float]
34
+
35
+ def __init__(
36
+ self,
37
+ constant_name: str,
38
+ metadata_key: str | StrEnum,
39
+ ip_task_types: str | list[str],
40
+ task_type_parsing_function: Callable = passthrough_header_ip_task,
41
+ ):
42
+ super().__init__(
43
+ constant_name=constant_name,
44
+ metadata_key=metadata_key,
45
+ ip_task_types=ip_task_types,
46
+ tolerance=np.inf,
47
+ task_type_parsing_function=task_type_parsing_function,
48
+ )
@@ -2,16 +2,19 @@
2
2
 
3
3
  from dkist_processing_common.models.constants import BudName
4
4
  from dkist_processing_common.models.fits_access import MetadataKey
5
+ from dkist_processing_common.models.task_name import TaskName
5
6
  from dkist_processing_common.parsers.id_bud import ContributingIdsBud
6
- from dkist_processing_common.parsers.id_bud import IdBud
7
+ from dkist_processing_common.parsers.unique_bud import TaskUniqueBud
7
8
 
8
9
 
9
- class ExperimentIdBud(IdBud):
10
+ class ExperimentIdBud(TaskUniqueBud):
10
11
  """Class to create a Bud for the experiment_id."""
11
12
 
12
13
  def __init__(self):
13
14
  super().__init__(
14
- constant_name=BudName.experiment_id, metadata_key=MetadataKey.experiment_id
15
+ constant_name=BudName.experiment_id,
16
+ metadata_key=MetadataKey.experiment_id,
17
+ ip_task_types=TaskName.observe,
15
18
  )
16
19
 
17
20
 
@@ -20,5 +23,6 @@ class ContributingExperimentIdsBud(ContributingIdsBud):
20
23
 
21
24
  def __init__(self):
22
25
  super().__init__(
23
- stem_name=BudName.contributing_experiment_ids, metadata_key=MetadataKey.experiment_id
26
+ constant_name=BudName.contributing_experiment_ids,
27
+ metadata_key=MetadataKey.experiment_id,
24
28
  )