dkist-header-validator 5.2.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.
@@ -0,0 +1,639 @@
1
+ from pathlib import Path
2
+ from random import choice
3
+ from uuid import uuid4
4
+
5
+ import numpy as np
6
+ import pytest
7
+ from astropy.io import fits
8
+ from astropy.wcs import WCS
9
+ from dkist_data_simulator.spec122 import Spec122Dataset
10
+ from dkist_data_simulator.spec214 import Spec214Dataset
11
+ from dkist_fits_specifications.spec122 import load_spec122
12
+ from dkist_fits_specifications.spec214 import load_spec214
13
+ from dkist_fits_specifications.spec214.level0 import load_level0_spec214
14
+
15
+ FITS_OBJECT_TYPES = [
16
+ "fits",
17
+ "dict",
18
+ "hdulist",
19
+ "header",
20
+ "multiple_fits_cards_fits",
21
+ "multiple_fits_cards_hdulist",
22
+ "multiple_fits_cards_header",
23
+ ]
24
+
25
+
26
+ def get_fits_object(
27
+ object_type: str, tmpdir: Path, ds, required_only: bool = False, expected_only: bool = False
28
+ ) -> str | dict | fits.HDUList | fits.header.Header:
29
+ """
30
+ Build up the required object type from the given simulated Dataset
31
+
32
+ TYPES
33
+ -----
34
+ fits : a fits file on disk
35
+ compressed : a compressed fits file on disk
36
+ dict : headers formatted as a python dict
37
+ hdulist : headers built into a PrimaryHDU presented in an HDUList
38
+ header : headers formatted as a fits.header.Header
39
+ second_hdu: a fits file on disk with the headers located in the second hdu
40
+
41
+ multiple_fits_cards_fits: a fits file on disk that has multiple fits_cards
42
+ multiple_fits_cards_hdulist: headers built into a PrimaryHDU presented in an HDUList with multiple fits_cards
43
+ multiple_fits_cards_header: headers formatted as a fits.header.Header with multiple fits_cards
44
+ """
45
+ header_dict = [d.header(required_only=required_only, expected_only=expected_only) for d in ds][
46
+ 0
47
+ ]
48
+ data = np.ones(shape=ds.array_shape)
49
+ hdu = fits.PrimaryHDU(data=data)
50
+ for key, value in header_dict.items():
51
+ hdu.header[key] = value
52
+
53
+ if object_type == "fits":
54
+ file_name = tmpdir / f"{uuid4().hex}.fits"
55
+ hdu_list = fits.HDUList([hdu])
56
+ hdu_list.writeto(str(file_name))
57
+ return str(file_name)
58
+
59
+ if object_type == "compressed":
60
+ file_name = tmpdir / f"{uuid4().hex}.fits"
61
+ hdu_list = fits.HDUList(
62
+ [fits.PrimaryHDU(), fits.CompImageHDU(data=data, header=hdu.header)]
63
+ )
64
+ hdu_list.writeto(str(file_name))
65
+ return str(file_name)
66
+
67
+ if object_type == "dict":
68
+ return header_dict
69
+
70
+ if object_type == "hdulist":
71
+ return fits.HDUList([hdu])
72
+
73
+ if object_type == "header":
74
+ return hdu.header
75
+
76
+ if object_type == "second_hdu":
77
+ file_name = tmpdir / f"{uuid4().hex}.fits"
78
+ hdu_list = fits.HDUList([fits.PrimaryHDU(), fits.ImageHDU(data=data, header=hdu.header)])
79
+ hdu_list.writeto(str(file_name))
80
+ return str(file_name)
81
+
82
+ if object_type == "third_hdu":
83
+ file_name = tmpdir / f"{uuid4().hex}.fits"
84
+ hdu_list = fits.HDUList(
85
+ [
86
+ fits.PrimaryHDU(),
87
+ fits.ImageHDU(data=data, header=hdu.header),
88
+ fits.ImageHDU(data=data, header=hdu.header),
89
+ ]
90
+ )
91
+ hdu_list.writeto(str(file_name))
92
+ return str(file_name)
93
+
94
+ history_card1 = "history card 1"
95
+ history_card2 = "history card 2"
96
+ hdu.header.add_history(history_card1)
97
+ hdu.header.add_history(history_card2)
98
+ if object_type == "multiple_fits_cards_header":
99
+ return hdu.header
100
+
101
+ hdu_list = fits.HDUList([hdu])
102
+ if object_type == "multiple_fits_cards_hdulist":
103
+ return hdu_list
104
+
105
+ if object_type == "multiple_fits_cards_fits":
106
+ file_name = tmpdir / f"{uuid4().hex}.fits"
107
+ hdu_list.writeto(str(file_name))
108
+ return str(file_name)
109
+
110
+
111
+ class BaseSpec122Dataset(Spec122Dataset):
112
+ def __init__(self, instrument="vbi"):
113
+ self.array_shape = (1, 10, 10)
114
+ super().__init__(
115
+ dataset_shape=(2, 10, 10),
116
+ array_shape=self.array_shape,
117
+ time_delta=1,
118
+ instrument=instrument,
119
+ )
120
+
121
+
122
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
123
+ def valid_spec_122_object(tmpdir, request):
124
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset())
125
+
126
+
127
+ @pytest.fixture(scope="function", params=["dict", "header", "multiple_fits_cards_header"])
128
+ def valid_translator_object(tmpdir, request):
129
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset())
130
+
131
+
132
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
133
+ def valid_spec_122_object_required_only(tmpdir, request):
134
+ yield get_fits_object(
135
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset(), required_only=True
136
+ )
137
+
138
+
139
+ @pytest.fixture(scope="function", params=["dict", "header"])
140
+ def valid_translator_object_required_only(tmpdir, request):
141
+ yield get_fits_object(
142
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset(), required_only=True
143
+ )
144
+
145
+
146
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
147
+ def valid_spec_122_object_expected_only(tmpdir, request):
148
+ yield get_fits_object(
149
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset(), expected_only=True
150
+ )
151
+
152
+
153
+ @pytest.fixture(scope="function", params=["dict", "header"])
154
+ def valid_translator_object_expected_only(tmpdir, request):
155
+ yield get_fits_object(
156
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset(), expected_only=True
157
+ )
158
+
159
+
160
+ @pytest.fixture(scope="function")
161
+ def valid_spec_122_file(tmpdir):
162
+ yield get_fits_object(object_type="fits", tmpdir=tmpdir, ds=BaseSpec122Dataset())
163
+
164
+
165
+ @pytest.fixture(scope="function")
166
+ def valid_spec_122_compressed(tmpdir):
167
+ yield get_fits_object(object_type="compressed", tmpdir=tmpdir, ds=BaseSpec122Dataset())
168
+
169
+
170
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
171
+ def valid_spec_122_visp(tmpdir, request):
172
+ yield get_fits_object(
173
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset(instrument="visp")
174
+ )
175
+
176
+
177
+ @pytest.fixture(scope="function", params=["dict", "header", "hdulist"])
178
+ def valid_spec_122_no_file(tmpdir, request):
179
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122Dataset())
180
+
181
+
182
+ @pytest.fixture(scope="function")
183
+ def valid_spec_122_dict_only(tmpdir):
184
+ yield get_fits_object(object_type="dict", tmpdir=tmpdir, ds=BaseSpec122Dataset())
185
+
186
+
187
+ @pytest.fixture(scope="function")
188
+ def valid_spec_122_hdulist_only(tmpdir):
189
+ yield get_fits_object(object_type="hdulist", tmpdir=tmpdir, ds=BaseSpec122Dataset())
190
+
191
+
192
+ @pytest.fixture(scope="function")
193
+ def valid_spec_122_second_hdu(tmpdir):
194
+ yield get_fits_object(object_type="second_hdu", tmpdir=tmpdir, ds=BaseSpec122Dataset())
195
+
196
+
197
+ @pytest.fixture(scope="function")
198
+ def valid_spec_122_too_many_HDUs(tmpdir):
199
+ yield get_fits_object(object_type="third_hdu", tmpdir=tmpdir, ds=BaseSpec122Dataset())
200
+
201
+
202
+ class Spec122DatasetExtraKeys(BaseSpec122Dataset):
203
+ def __init__(self):
204
+ super().__init__()
205
+ self.add_constant_key("XTRAKEY1", "ABCDEFG")
206
+ self.add_constant_key("XTRAKEY2", "HIJKLMN")
207
+ self.add_constant_key("XTRAKEY3", "OPQRSTU")
208
+ self.add_constant_key("XTRAKEY4", "VWXYZAB")
209
+
210
+
211
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
212
+ def valid_spec_122_object_extra_keys(tmpdir, request):
213
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=Spec122DatasetExtraKeys())
214
+
215
+
216
+ class InvalidBaseSpec122Dataset(Spec122Dataset):
217
+ def __init__(self, instrument="vbi"):
218
+ self.array_shape = (1, 10, 10)
219
+ super().__init__(
220
+ dataset_shape=(2, 10, 10),
221
+ array_shape=self.array_shape,
222
+ time_delta=1,
223
+ instrument=instrument,
224
+ )
225
+ self.add_remove_key("NAXIS1")
226
+ self.add_remove_key("NXAIS2")
227
+ self.add_remove_key("WAVELNTH")
228
+ self.add_remove_key("DATE-OBS")
229
+ self.add_remove_key("ID___002")
230
+ self.add_remove_key("ID___003")
231
+ self.add_remove_key("ID___012")
232
+ self.add_remove_key("DKIST003")
233
+ self.add_remove_key("DKIST004")
234
+ self.add_remove_key("HISTORY")
235
+
236
+
237
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
238
+ def invalid_spec_122_object(tmpdir, request):
239
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=InvalidBaseSpec122Dataset())
240
+
241
+
242
+ class InvalidInstrumentTableSpec122Dataset(BaseSpec122Dataset):
243
+ def __init__(self, instrument: str):
244
+ super().__init__(instrument=instrument)
245
+
246
+ # Remove a random key from the instrument table
247
+ glob_name = instrument.lower().replace(
248
+ "-", ""
249
+ ) # For cryo and dl b/c the yamls don't have dashes
250
+ instrument_keys = load_spec122(glob=glob_name)[glob_name]
251
+ removal_candidates = [k for k, v in instrument_keys.items() if "instrument_required" in v]
252
+ removed_key = choice(removal_candidates)
253
+ self.add_remove_key(removed_key)
254
+ self.removed_key = removed_key
255
+
256
+
257
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
258
+ def invalid_instrument_table_spec_122_object(tmpdir, request, instrument):
259
+ dataset = InvalidInstrumentTableSpec122Dataset(instrument)
260
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=dataset), dataset.removed_key
261
+
262
+
263
+ class BaseSpec122DatasetCaseSensitive(Spec122Dataset):
264
+ def __init__(self, instrument="vbi"):
265
+ self.array_shape = (1, 10, 10)
266
+ super().__init__(
267
+ dataset_shape=(2, 10, 10),
268
+ array_shape=self.array_shape,
269
+ time_delta=1,
270
+ instrument=instrument,
271
+ )
272
+ self.add_constant_key("DKIST004", "oBSErve")
273
+
274
+
275
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
276
+ def valid_spec_122_casesensitive(tmpdir, request):
277
+ yield get_fits_object(
278
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec122DatasetCaseSensitive()
279
+ )
280
+
281
+
282
+ class BaseSpec214l0Dataset(Spec122Dataset):
283
+ def __init__(self, instrument="vbi"):
284
+ self.array_shape = (1, 10, 10)
285
+ super().__init__(
286
+ dataset_shape=(2, 10, 10),
287
+ array_shape=self.array_shape,
288
+ time_delta=1,
289
+ instrument=instrument,
290
+ file_schema="level0_spec214",
291
+ )
292
+
293
+
294
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
295
+ def valid_spec_214l0_object(tmpdir, request):
296
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
297
+
298
+
299
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
300
+ def valid_spec_214l0_object_required_only(tmpdir, request):
301
+ yield get_fits_object(
302
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0Dataset(), required_only=True
303
+ )
304
+
305
+
306
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
307
+ def valid_spec_214l0_object_expected_only(tmpdir, request):
308
+ yield get_fits_object(
309
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0Dataset(), expected_only=True
310
+ )
311
+
312
+
313
+ @pytest.fixture(scope="function")
314
+ def valid_spec_214l0_file(tmpdir):
315
+ yield get_fits_object(object_type="fits", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
316
+
317
+
318
+ @pytest.fixture(scope="function")
319
+ def valid_spec_214l0_compressed(tmpdir):
320
+ yield get_fits_object(object_type="compressed", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
321
+
322
+
323
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
324
+ def valid_spec_214l0_visp(tmpdir, request):
325
+ yield get_fits_object(
326
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0Dataset(instrument="visp")
327
+ )
328
+
329
+
330
+ @pytest.fixture(scope="function", params=["dict", "header", "hdulist"])
331
+ def valid_spec_214l0_no_file(tmpdir, request):
332
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
333
+
334
+
335
+ @pytest.fixture(scope="function")
336
+ def valid_spec_214l0_dict_only(tmpdir):
337
+ yield get_fits_object(object_type="dict", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
338
+
339
+
340
+ @pytest.fixture(scope="function")
341
+ def valid_spec_214l0_hdulist_only(tmpdir):
342
+ yield get_fits_object(object_type="hdulist", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
343
+
344
+
345
+ @pytest.fixture(scope="function")
346
+ def valid_spec_214l0_second_hdu(tmpdir):
347
+ yield get_fits_object(object_type="second_hdu", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
348
+
349
+
350
+ @pytest.fixture(scope="function")
351
+ def valid_spec_214_l0_too_many_HDUs(tmpdir):
352
+ yield get_fits_object(object_type="third_hdu", tmpdir=tmpdir, ds=BaseSpec214l0Dataset())
353
+
354
+
355
+ class Spec214l0DatasetExtraKeys(BaseSpec214l0Dataset):
356
+ def __init__(self):
357
+ super().__init__()
358
+ self.add_constant_key("XTRAKEY1", "ABCDEFG")
359
+ self.add_constant_key("XTRAKEY2", "HIJKLMN")
360
+ self.add_constant_key("XTRAKEY3", "OPQRSTU")
361
+ self.add_constant_key("XTRAKEY4", "VWXYZAB")
362
+
363
+
364
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
365
+ def valid_spec_214l0_object_extra_keys(tmpdir, request):
366
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=Spec214l0DatasetExtraKeys())
367
+
368
+
369
+ class InvalidBaseSpec214l0Dataset(Spec122Dataset):
370
+ def __init__(self, instrument="vbi"):
371
+ self.array_shape = (1, 10, 10)
372
+ super().__init__(
373
+ dataset_shape=(2, 10, 10),
374
+ array_shape=self.array_shape,
375
+ time_delta=1,
376
+ instrument=instrument,
377
+ file_schema="level0_spec214",
378
+ )
379
+ self.add_remove_key("NAXIS1")
380
+ self.add_remove_key("NXAIS2")
381
+ self.add_remove_key("LINEWAV")
382
+ self.add_remove_key("DATE-OBS")
383
+ self.add_remove_key("FILE_ID")
384
+ self.add_remove_key("EXPER_ID")
385
+
386
+
387
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
388
+ def invalid_spec_214l0_object(tmpdir, request):
389
+ yield get_fits_object(
390
+ object_type=request.param, tmpdir=tmpdir, ds=InvalidBaseSpec214l0Dataset()
391
+ )
392
+
393
+
394
+ @pytest.fixture(scope="function")
395
+ def invalid_spec_214l0_compressed(tmpdir):
396
+ yield get_fits_object(object_type="compressed", tmpdir=tmpdir, ds=InvalidBaseSpec214l0Dataset())
397
+
398
+
399
+ class InvalidInstrumentTableSpec214l0Dataset(BaseSpec214l0Dataset):
400
+ def __init__(self, instrument: str):
401
+ super().__init__(instrument=instrument)
402
+
403
+ # Remove a random key from the instrument table
404
+ glob_name = instrument.lower().replace(
405
+ "-", ""
406
+ ) # For cryo and dl b/c the yamls don't have dashes
407
+ instrument_keys = load_level0_spec214(glob=glob_name)[glob_name]
408
+ removal_candidates = [k for k, v in instrument_keys.items() if "instrument_required" in v]
409
+ removed_key = choice(removal_candidates)
410
+ self.add_remove_key(removed_key)
411
+ self.removed_key = removed_key
412
+
413
+
414
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
415
+ def invalid_instrument_table_spec_214l0_object(tmpdir, request, instrument):
416
+ dataset = InvalidInstrumentTableSpec214l0Dataset(instrument)
417
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=dataset), dataset.removed_key
418
+
419
+
420
+ class BaseSpec214l0DatasetCaseSensitive(Spec122Dataset):
421
+ def __init__(self, instrument="vbi"):
422
+ self.array_shape = (1, 10, 10)
423
+ super().__init__(
424
+ dataset_shape=(2, 10, 10),
425
+ array_shape=self.array_shape,
426
+ time_delta=1,
427
+ instrument=instrument,
428
+ file_schema="level0_spec214",
429
+ )
430
+ self.add_constant_key("VBISYNCM", "fIxED")
431
+
432
+
433
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
434
+ def valid_spec_214l0_casesensitive(tmpdir, request):
435
+ yield get_fits_object(
436
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214l0DatasetCaseSensitive()
437
+ )
438
+
439
+
440
+ class BaseSpec214Dataset(Spec214Dataset):
441
+ def __init__(self, instrument="vbi"):
442
+ self.array_shape = (10, 10)
443
+ super().__init__(
444
+ dataset_shape=(2, 10, 10),
445
+ array_shape=self.array_shape,
446
+ time_delta=1,
447
+ instrument=instrument,
448
+ )
449
+
450
+ @property
451
+ def fits_wcs(self):
452
+ w = WCS(naxis=2)
453
+ w.wcs.crpix = self.array_shape[1] / 2, self.array_shape[0] / 2
454
+ w.wcs.crval = 0, 0
455
+ w.wcs.cdelt = 1, 1
456
+ w.wcs.cunit = "arcsec", "arcsec"
457
+ w.wcs.ctype = "HPLN-TAN", "HPLT-TAN"
458
+ w.wcs.pc = np.identity(self.array_ndim)
459
+ return w
460
+
461
+
462
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
463
+ def valid_spec_214_object(tmpdir, request):
464
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214Dataset())
465
+
466
+
467
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
468
+ def valid_spec_214_object_required_only(tmpdir, request):
469
+ yield get_fits_object(
470
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214Dataset(), required_only=True
471
+ )
472
+
473
+
474
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
475
+ def valid_spec_214_object_expected_only(tmpdir, request):
476
+ yield get_fits_object(
477
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214Dataset(), expected_only=True
478
+ )
479
+
480
+
481
+ @pytest.fixture(scope="function")
482
+ def valid_spec_214_file(tmpdir):
483
+ yield get_fits_object(object_type="fits", tmpdir=tmpdir, ds=BaseSpec214Dataset())
484
+
485
+
486
+ @pytest.fixture(scope="function")
487
+ def valid_spec_214_compressed(tmpdir):
488
+ yield get_fits_object(object_type="compressed", tmpdir=tmpdir, ds=BaseSpec214Dataset())
489
+
490
+
491
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
492
+ def valid_spec_214_visp(tmpdir, request):
493
+ yield get_fits_object(
494
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214Dataset(instrument="visp")
495
+ )
496
+
497
+
498
+ @pytest.fixture(
499
+ scope="function", params=["dict", "header", "hdulist", "multiple_fits_cards_header"]
500
+ )
501
+ def valid_spec_214_no_file(tmpdir, request):
502
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214Dataset())
503
+
504
+
505
+ @pytest.fixture(scope="function")
506
+ def valid_spec_214_dict_only(tmpdir):
507
+ yield get_fits_object(object_type="dict", tmpdir=tmpdir, ds=BaseSpec214Dataset())
508
+
509
+
510
+ @pytest.fixture(scope="function")
511
+ def valid_spec_214_hdulist_only(tmpdir):
512
+ yield get_fits_object(object_type="hdulist", tmpdir=tmpdir, ds=BaseSpec214Dataset())
513
+
514
+
515
+ @pytest.fixture(scope="function")
516
+ def valid_spec_214_second_hdu(tmpdir):
517
+ yield get_fits_object(object_type="second_hdu", tmpdir=tmpdir, ds=BaseSpec214Dataset())
518
+
519
+
520
+ @pytest.fixture(scope="function")
521
+ def valid_spec_214_too_many_HDUs(tmpdir):
522
+ yield get_fits_object(object_type="third_hdu", tmpdir=tmpdir, ds=BaseSpec214Dataset())
523
+
524
+
525
+ class Spec214DatasetExtraKeys(BaseSpec214Dataset):
526
+ def __init__(self):
527
+ super().__init__()
528
+ self.add_constant_key("XTRAKEY1", "ABCDEFG")
529
+ self.add_constant_key("XTRAKEY2", "HIJKLMN")
530
+ self.add_constant_key("XTRAKEY3", "OPQRSTU")
531
+ self.add_constant_key("XTRAKEY4", "VWXYZAB")
532
+
533
+
534
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
535
+ def valid_spec_214_object_extra_keys(tmpdir, request):
536
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=Spec214DatasetExtraKeys())
537
+
538
+
539
+ class InvalidBaseSpec214Dataset(Spec214Dataset):
540
+ def __init__(self, instrument="vbi"):
541
+ self.array_shape = (10, 10)
542
+ super().__init__(
543
+ dataset_shape=(2, 10, 10),
544
+ array_shape=self.array_shape,
545
+ time_delta=1,
546
+ instrument=instrument,
547
+ )
548
+ self.add_remove_key("NAXIS1")
549
+ self.add_remove_key("NXAIS2")
550
+ self.add_remove_key("LINEWAV")
551
+ self.add_remove_key("DATE-OBS")
552
+ self.add_remove_key("FILE_ID")
553
+ self.add_remove_key("EXPER_ID")
554
+
555
+ @property
556
+ def fits_wcs(self):
557
+ w = WCS(naxis=2)
558
+ w.wcs.crpix = self.array_shape[1] / 2, self.array_shape[0] / 2
559
+ w.wcs.crval = 0, 0
560
+ w.wcs.cdelt = 1, 1
561
+ w.wcs.cunit = "arcsec", "arcsec"
562
+ w.wcs.ctype = "HPLN-TAN", "HPLT-TAN"
563
+ w.wcs.pc = np.identity(self.array_ndim)
564
+ return w
565
+
566
+
567
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
568
+ def invalid_spec_214_object(tmpdir, request):
569
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=InvalidBaseSpec214Dataset())
570
+
571
+
572
+ @pytest.fixture(scope="function")
573
+ def invalid_spec_214_compressed(tmpdir):
574
+ yield get_fits_object(object_type="compressed", tmpdir=tmpdir, ds=InvalidBaseSpec214Dataset())
575
+
576
+
577
+ class BaseSpec214DatasetCaseSensitive(Spec214Dataset):
578
+ def __init__(self, instrument="vbi"):
579
+ self.array_shape = (10, 10)
580
+ super().__init__(
581
+ dataset_shape=(2, 10, 10),
582
+ array_shape=self.array_shape,
583
+ time_delta=1,
584
+ instrument=instrument,
585
+ )
586
+ self.add_constant_key("VBISYNCM", "fIxED")
587
+
588
+ @property
589
+ def fits_wcs(self):
590
+ w = WCS(naxis=2)
591
+ w.wcs.crpix = self.array_shape[1] / 2, self.array_shape[0] / 2
592
+ w.wcs.crval = 0, 0
593
+ w.wcs.cdelt = 1, 1
594
+ w.wcs.cunit = "arcsec", "arcsec"
595
+ w.wcs.ctype = "HPLN-TAN", "HPLT-TAN"
596
+ w.wcs.pc = np.identity(self.array_ndim)
597
+ return w
598
+
599
+
600
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
601
+ def valid_spec_214_casesensitive(tmpdir, request):
602
+ yield get_fits_object(
603
+ object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214DatasetCaseSensitive()
604
+ )
605
+
606
+
607
+ class InvalidPolarimetricSpec214Dataset(BaseSpec214Dataset):
608
+ def __init__(self):
609
+ super().__init__(instrument="visp")
610
+ self.add_constant_key("VSPPOLMD", "observe_polarimetric")
611
+ self.add_remove_key("POL_SENS")
612
+
613
+
614
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
615
+ def invalid_polarimetric_spec_214_object(tmpdir, request):
616
+ yield get_fits_object(
617
+ object_type=request.param, tmpdir=tmpdir, ds=InvalidPolarimetricSpec214Dataset()
618
+ )
619
+
620
+
621
+ class InvalidInstrumentTableSpec214Dataset(BaseSpec214Dataset):
622
+ def __init__(self, instrument: str):
623
+ super().__init__(instrument=instrument)
624
+
625
+ # Remove a random key from the instrument table
626
+ glob_name = instrument.lower().replace(
627
+ "-", ""
628
+ ) # For cryo and dl b/c the yamls don't have dashes
629
+ instrument_keys = load_spec214(glob=glob_name)[glob_name]
630
+ removal_candidates = [k for k, v in instrument_keys.items() if "instrument_required" in v]
631
+ removed_key = choice(removal_candidates)
632
+ self.add_remove_key(removed_key)
633
+ self.removed_key = removed_key
634
+
635
+
636
+ @pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
637
+ def invalid_instrument_table_spec_214_object(tmpdir, request, instrument):
638
+ dataset = InvalidInstrumentTableSpec214Dataset(instrument)
639
+ yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=dataset), dataset.removed_key