dkist-header-validator 4.1.0__tar.gz → 5.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dkist-header-validator-4.1.0/dkist_header_validator.egg-info → dkist-header-validator-5.0.0}/PKG-INFO +1 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/bitbucket-pipelines.yml +5 -4
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/base_validator.py +56 -8
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/spec_validators.py +4 -2
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/conftest.py +37 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_spec214_validation-.py +29 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/translator.py +2 -2
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/utils/expansions.py +2 -2
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/version.py +1 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0/dkist_header_validator.egg-info}/PKG-INFO +1 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator.egg-info/requires.txt +1 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/setup.cfg +1 -1
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/.gitignore +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/.pre-commit-config.yaml +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/.readthedocs.yml +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/README.rst +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/__init__.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/api/__init__.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/api/validate.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/exceptions.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/__init__.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_base_validator.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_spec122_translation.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_spec122_validation+.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_spec122_validation-.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_spec214_validation+.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/tests/test_translator.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/utils/__init__.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator.egg-info/SOURCES.txt +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator.egg-info/dependency_links.txt +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator.egg-info/entry_points.txt +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator.egg-info/top_level.txt +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/docs/Makefile +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/docs/conf.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/docs/index.rst +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/docs/make.bat +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/docs/requirements.txt +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/setup.py +0 -0
- {dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/tox.ini +0 -0
|
@@ -49,13 +49,14 @@ definitions:
|
|
|
49
49
|
pipelines:
|
|
50
50
|
default:
|
|
51
51
|
- step: *lint
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
- parallel:
|
|
53
|
+
- step: *test
|
|
54
|
+
- step: *docs
|
|
55
|
+
- step: *scan
|
|
55
56
|
tags:
|
|
56
57
|
'v*':
|
|
58
|
+
- step: *lint
|
|
57
59
|
- parallel:
|
|
58
|
-
- step: *lint
|
|
59
60
|
- step: *test
|
|
60
61
|
- step: *docs
|
|
61
62
|
- step: *scan
|
|
@@ -9,7 +9,9 @@ from numbers import Integral
|
|
|
9
9
|
from numbers import Real
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
|
+
from typing import Callable
|
|
12
13
|
from typing import IO
|
|
14
|
+
from typing import Optional
|
|
13
15
|
from typing import Type
|
|
14
16
|
|
|
15
17
|
import astropy.time as t
|
|
@@ -453,21 +455,14 @@ class SpecValidator:
|
|
|
453
455
|
"""
|
|
454
456
|
try:
|
|
455
457
|
with fits.open(input_headers) as hdul:
|
|
456
|
-
if len(hdul) > 2:
|
|
457
|
-
raise ValidationException(
|
|
458
|
-
"Too many HDUs in your HDUList! May only have two HDUs at most."
|
|
459
|
-
)
|
|
460
458
|
# verify fits headers with astropy verify library
|
|
461
459
|
hdul.verify("exception")
|
|
462
460
|
# normalize headers into a dict
|
|
463
461
|
try:
|
|
464
|
-
hdus = self._headers_to_dict(hdul[1].header)
|
|
465
462
|
data = hdul[1].data
|
|
466
463
|
except IndexError: # non-compressed
|
|
467
|
-
hdus = self._headers_to_dict(hdul[0].header)
|
|
468
464
|
data = hdul[0].data
|
|
469
|
-
fits_cards = self.
|
|
470
|
-
verified_headers = self.verify_headers(hdus, extra)
|
|
465
|
+
verified_headers, fits_cards = self._validate_headers(hdul, extra)
|
|
471
466
|
return verified_headers, fits_cards, data
|
|
472
467
|
except (ValueError, FileNotFoundError, OSError, IndexError) as exc:
|
|
473
468
|
logger.debug(f"Cannot parse headers: detail = {exc}")
|
|
@@ -702,3 +697,56 @@ class SpecValidator:
|
|
|
702
697
|
return self._format_output(
|
|
703
698
|
return_type, translated_headers, input_headers, data, fits_cards
|
|
704
699
|
)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
class ProcessedSpecValidator(SpecValidator):
|
|
703
|
+
"""
|
|
704
|
+
Validates FITS Headers against a schema that is updated based on the actual headers.
|
|
705
|
+
|
|
706
|
+
The two current examples of a "processed" spec are keys that are updated based on expansion or on conditional
|
|
707
|
+
requiredness.
|
|
708
|
+
|
|
709
|
+
Parameters
|
|
710
|
+
----------
|
|
711
|
+
spec_processor_function
|
|
712
|
+
A function that can process a spec based on an input header. Probably `load_processed_spec214`.
|
|
713
|
+
|
|
714
|
+
SchemaValidationException
|
|
715
|
+
SpecValidationException or subclass of SpecValidationException
|
|
716
|
+
to raise if spec_validator validation fails
|
|
717
|
+
|
|
718
|
+
"""
|
|
719
|
+
|
|
720
|
+
def __init__(
|
|
721
|
+
self,
|
|
722
|
+
spec_processor_function: Callable,
|
|
723
|
+
SchemaValidationException: Type[SpecValidationException] = SpecValidationException,
|
|
724
|
+
):
|
|
725
|
+
self.spec_processor_function = spec_processor_function
|
|
726
|
+
|
|
727
|
+
# Use an unprocessed (i.e., no header given) spec to initialize the base Validator.
|
|
728
|
+
base_schema = self.spec_processor_function()
|
|
729
|
+
super().__init__(
|
|
730
|
+
spec_schema=base_schema, SchemaValidationException=SchemaValidationException
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
def verify_headers(self, headers, extra) -> dict:
|
|
734
|
+
"""
|
|
735
|
+
Validates file headers against the instance spec_validator
|
|
736
|
+
|
|
737
|
+
Parameters
|
|
738
|
+
----------
|
|
739
|
+
headers
|
|
740
|
+
file headers
|
|
741
|
+
extra
|
|
742
|
+
switch for validation to allow extra keys in schema
|
|
743
|
+
Returns
|
|
744
|
+
-------
|
|
745
|
+
dict of headers
|
|
746
|
+
|
|
747
|
+
Raises
|
|
748
|
+
------
|
|
749
|
+
SchemaValidationException
|
|
750
|
+
"""
|
|
751
|
+
self.spec_schema = SpecSchema(self.spec_processor_function(**headers))
|
|
752
|
+
return super().verify_headers(headers, extra)
|
|
@@ -4,7 +4,9 @@ Validators configured for specific Fits Specs
|
|
|
4
4
|
from dkist_fits_specifications import spec122
|
|
5
5
|
from dkist_fits_specifications import spec214
|
|
6
6
|
from dkist_fits_specifications.spec214 import level0
|
|
7
|
+
from dkist_fits_specifications.spec214 import load_processed_spec214
|
|
7
8
|
|
|
9
|
+
from dkist_header_validator.base_validator import ProcessedSpecValidator
|
|
8
10
|
from dkist_header_validator.base_validator import SpecValidator
|
|
9
11
|
from dkist_header_validator.exceptions import SpecSchemaDefinitionException
|
|
10
12
|
from dkist_header_validator.exceptions import SpecValidationException
|
|
@@ -49,7 +51,7 @@ spec214_l0_validator = SpecValidator(
|
|
|
49
51
|
SchemaValidationException=Spec214ValidationException,
|
|
50
52
|
)
|
|
51
53
|
|
|
52
|
-
spec214_validator =
|
|
53
|
-
|
|
54
|
+
spec214_validator = ProcessedSpecValidator(
|
|
55
|
+
spec_processor_function=load_processed_spec214,
|
|
54
56
|
SchemaValidationException=Spec214ValidationException,
|
|
55
57
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
+
from random import choice
|
|
2
3
|
from uuid import uuid4
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
@@ -7,6 +8,7 @@ from astropy.io import fits
|
|
|
7
8
|
from astropy.wcs import WCS
|
|
8
9
|
from dkist_data_simulator.spec122 import Spec122Dataset
|
|
9
10
|
from dkist_data_simulator.spec214 import Spec214Dataset
|
|
11
|
+
from dkist_fits_specifications.spec214 import load_spec214
|
|
10
12
|
|
|
11
13
|
FITS_OBJECT_TYPES = [
|
|
12
14
|
"fits",
|
|
@@ -536,7 +538,6 @@ class BaseSpec214DatasetCaseSensitive(Spec214Dataset):
|
|
|
536
538
|
time_delta=1,
|
|
537
539
|
instrument=instrument,
|
|
538
540
|
)
|
|
539
|
-
self.add_remove_key("VBISYNCM")
|
|
540
541
|
self.add_constant_key("VBISYNCM", "fIxED")
|
|
541
542
|
|
|
542
543
|
@property
|
|
@@ -556,3 +557,38 @@ def valid_spec_214_casesensitive(tmpdir, request):
|
|
|
556
557
|
yield get_fits_object(
|
|
557
558
|
object_type=request.param, tmpdir=tmpdir, ds=BaseSpec214DatasetCaseSensitive()
|
|
558
559
|
)
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
class InvalidPolarimetricSpec214Dataset(BaseSpec214Dataset):
|
|
563
|
+
def __init__(self):
|
|
564
|
+
super().__init__(instrument="visp")
|
|
565
|
+
self.add_constant_key("VSPPOLMD", "observe_polarimetric")
|
|
566
|
+
self.add_remove_key("POL_SENS")
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
@pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
|
|
570
|
+
def invalid_polarimetric_spec_214_object(tmpdir, request):
|
|
571
|
+
yield get_fits_object(
|
|
572
|
+
object_type=request.param, tmpdir=tmpdir, ds=InvalidPolarimetricSpec214Dataset()
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
class InvalidInstrumentTableSpec214Dataset(BaseSpec214Dataset):
|
|
577
|
+
def __init__(self, instrument: str):
|
|
578
|
+
super().__init__(instrument=instrument)
|
|
579
|
+
|
|
580
|
+
# Remove a random key from the instrument table
|
|
581
|
+
glob_name = instrument.lower().replace(
|
|
582
|
+
"-", ""
|
|
583
|
+
) # For cryo and dl b/c the yamls don't have dashes
|
|
584
|
+
instrument_keys = load_spec214(glob=glob_name)[glob_name]
|
|
585
|
+
removal_candidates = [k for k, v in instrument_keys.items() if "instrument_required" in v]
|
|
586
|
+
removed_key = choice(removal_candidates)
|
|
587
|
+
self.add_remove_key(removed_key)
|
|
588
|
+
self.removed_key = removed_key
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
@pytest.fixture(scope="function", params=FITS_OBJECT_TYPES)
|
|
592
|
+
def invalid_instrument_table_spec_214_object(tmpdir, request, instrument):
|
|
593
|
+
dataset = InvalidInstrumentTableSpec214Dataset(instrument)
|
|
594
|
+
yield get_fits_object(object_type=request.param, tmpdir=tmpdir, ds=dataset), dataset.removed_key
|
|
@@ -3,10 +3,12 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pytest
|
|
6
|
+
from dkist_fits_specifications.spec214 import load_processed_spec214
|
|
6
7
|
|
|
7
8
|
from dkist_header_validator import spec214_l0_validator
|
|
8
9
|
from dkist_header_validator import spec214_validator
|
|
9
10
|
from dkist_header_validator import Spec214ValidationException
|
|
11
|
+
from dkist_header_validator.base_validator import ProcessedSpecValidator
|
|
10
12
|
from dkist_header_validator.exceptions import ReturnTypeException
|
|
11
13
|
from dkist_header_validator.exceptions import ValidationException
|
|
12
14
|
|
|
@@ -168,3 +170,30 @@ def test_validate_toomanyHDUs(valid_spec_214_too_many_HDUs):
|
|
|
168
170
|
# raises exception on failure
|
|
169
171
|
with pytest.raises(ValidationException):
|
|
170
172
|
spec214_validator.validate(valid_spec_214_too_many_HDUs)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_polarimetric_required_key_missing(invalid_polarimetric_spec_214_object):
|
|
176
|
+
"""
|
|
177
|
+
Given: Polarimetric headers with a missing `polarimetric_required` key
|
|
178
|
+
When: Validating headers
|
|
179
|
+
Then: The correct Error is raised
|
|
180
|
+
"""
|
|
181
|
+
with pytest.raises(
|
|
182
|
+
Spec214ValidationException,
|
|
183
|
+
match="'POL_SENS': 'required key not provided. Required keyword not present'",
|
|
184
|
+
):
|
|
185
|
+
spec214_validator.validate(invalid_polarimetric_spec_214_object)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@pytest.mark.parametrize("instrument", ["cryo-nirsp", "dlnirsp", "vbi", "visp", "vtf"])
|
|
189
|
+
def test_instrument_required_key_missing(invalid_instrument_table_spec_214_object):
|
|
190
|
+
"""
|
|
191
|
+
Given: Headers from a specific instrument, but with one of the required header keys removed
|
|
192
|
+
When: Validating headers
|
|
193
|
+
Then: The correct Error is raised
|
|
194
|
+
"""
|
|
195
|
+
fits_object, missing_key = invalid_instrument_table_spec_214_object
|
|
196
|
+
with pytest.raises(
|
|
197
|
+
Spec214ValidationException, match=f"'{missing_key}': 'required key not provided"
|
|
198
|
+
):
|
|
199
|
+
spec214_validator.validate(fits_object)
|
{dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/translator.py
RENAMED
|
@@ -7,7 +7,7 @@ from typing import IO
|
|
|
7
7
|
from astropy.io import fits
|
|
8
8
|
from astropy.io.fits.hdu.hdulist import HDUList
|
|
9
9
|
from dkist_fits_specifications.spec214 import level0
|
|
10
|
-
from dkist_fits_specifications.spec214 import
|
|
10
|
+
from dkist_fits_specifications.spec214 import load_processed_spec214
|
|
11
11
|
from dkist_fits_specifications.spec214 import load_spec214
|
|
12
12
|
|
|
13
13
|
from dkist_header_validator.utils.expansions import expand_index_d
|
|
@@ -67,7 +67,7 @@ def sanitize_to_spec214_level1(
|
|
|
67
67
|
input_headers, input_data = _parse_fits_like_input(input_headers)
|
|
68
68
|
header = fits.Header(input_headers)
|
|
69
69
|
# convert headers
|
|
70
|
-
expanded_214 =
|
|
70
|
+
expanded_214 = load_processed_spec214(**dict(input_headers))
|
|
71
71
|
all_214_keys = reduce(list.__add__, map(list, expanded_214.values()))
|
|
72
72
|
|
|
73
73
|
for keyword in tuple(header.keys()):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from dkist_fits_specifications.utils import expand_schema
|
|
2
|
-
from dkist_fits_specifications.utils import ExpansionIndex
|
|
3
1
|
from dkist_fits_specifications.utils import schema_type_hint
|
|
2
|
+
from dkist_fits_specifications.utils.spec_processors.expansion import expand_schema
|
|
3
|
+
from dkist_fits_specifications.utils.spec_processors.expansion import ExpansionIndex
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def expand_naxis(naxis: int, schema: schema_type_hint) -> schema_type_hint:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/__init__.py
RENAMED
|
File without changes
|
{dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/api/__init__.py
RENAMED
|
File without changes
|
{dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/api/validate.py
RENAMED
|
File without changes
|
{dkist-header-validator-4.1.0 → dkist-header-validator-5.0.0}/dkist_header_validator/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|