Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- Add support for asdf-transform-schemas 0.6 and asdf-coordinates-schemas 0.4. [#279]
- Ignore UnitsWarnings emitted by astropy when converting units to VO format. [#281]
- Add support for new astronomy-1.1.0 manifest. [#282]
- Serialize ``pixel_shape`` on ``astropy.wcs.WCS``. [#276]
- Accept a gwcs object when serializing ``SlicedLowLevelWCS``. [#276]

0.7.1 (2025-02-12)
------------------
Expand Down
13 changes: 10 additions & 3 deletions asdf_astropy/converters/wcs/tests/test_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
from astropy.utils.data import get_pkg_data_filename, get_pkg_data_filenames
from astropy.wcs import WCS, DistortionLookupTable, FITSFixedWarning, Sip

from asdf_astropy.exceptions import InconsistentWCSError
from asdf_astropy.testing.helpers import assert_wcs_roundtrip

_astropy_test_header_filenames = list(get_pkg_data_filenames("tests/data/maps", "astropy.wcs", "*.hdr")) + list(
get_pkg_data_filenames("tests/data/spectra", "astropy.wcs", "*.hdr"),
)
_astropy_test_header_filenames = list(get_pkg_data_filenames("tests/data/maps", "astropy.wcs", "*.hdr"))

_astropy_test_fits_filenames = [
get_pkg_data_filename(f"tests/data/{fn}", "astropy.wcs")
Expand Down Expand Up @@ -118,3 +117,11 @@ def test_astropy_data_fits_roundtrip(fn, tmp_path, version):
wcs = WCS(ff[0].header, ff)

assert_wcs_roundtrip(wcs, tmp_path, version)


@pytest.mark.parametrize("attr", ["pixel_shape", "pixel_bounds"])
def test_failure_to_convert_inconsistent(tmp_path, attr):
wcs = create_wcs_with_attrs()
wcs.naxis -= 1
with pytest.raises(InconsistentWCSError, match="does not match naxis"):
assert_wcs_roundtrip(wcs, tmp_path)
20 changes: 18 additions & 2 deletions asdf_astropy/converters/wcs/wcs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from asdf.extension import Converter

from asdf_astropy.exceptions import InconsistentWCSError

# These attributes don't end up in the hdulist and
# instead will be stored in "attrs"
_WCS_ATTRS = ("naxis", "colsel", "keysel", "key", "pixel_bounds")
_WCS_ATTRS = ("naxis", "colsel", "keysel", "key", "pixel_bounds", "pixel_shape")


class WCSConverter(Converter):
Expand All @@ -18,20 +20,34 @@ def from_yaml_tree(self, node, tag, ctx):
if naxis := attrs.pop("naxis"):
hdulist[0].header["naxis"] = naxis

# pop attrs that are not valid kwargs
pixel_shape = attrs.pop("pixel_shape")
pixel_bounds = attrs.pop("pixel_bounds")

wcs = WCS(hdulist[0].header, fobj=hdulist, **attrs)

wcs.pixel_shape = pixel_shape
wcs.pixel_bounds = pixel_bounds

if wcs.sip is not None:
# work around a bug in astropy where sip headers lose precision
# see https://github.com/astropy/astropy/issues/17334
wcs.sip = wcs._read_sip_kw(hdulist[0].header, attrs.get("key", " "))
wcs.wcs.set()

wcs.pixel_bounds = pixel_bounds
return wcs

def to_yaml_tree(self, wcs, tag, ctx):
# Check that wcs is consistent. Astropy inconsistently checks
# that certain expected attributes match. We need to check this
# here to prevent writing inconsistent files that would be problematic
# to open.
if naxis := wcs.naxis:
for attr in ("pixel_shape", "pixel_bounds"):
if value := getattr(wcs, attr):
if len(value) != naxis:
msg = f"{attr} shape ({len(value)}) does not match naxis ({naxis})"
raise InconsistentWCSError(msg)
hdulist = wcs.to_fits(relax=True)
attrs = {a: getattr(wcs, a) for a in _WCS_ATTRS if hasattr(wcs, a)}
return {"hdulist": hdulist, "attrs": attrs}
4 changes: 4 additions & 0 deletions asdf_astropy/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class InconsistentWCSError(ValueError):
"""
An error for a WCS with inconsistent attributes.
"""
1 change: 1 addition & 0 deletions asdf_astropy/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@


_ASTROPY_EXTENSION_MANIFEST_URIS = [
"asdf://astropy.org/astropy/manifests/astropy-1.4.0",
"asdf://astropy.org/astropy/manifests/astropy-1.3.0",
"asdf://astropy.org/astropy/manifests/astropy-1.2.0",
"asdf://astropy.org/astropy/manifests/astropy-1.1.0",
Expand Down
73 changes: 73 additions & 0 deletions asdf_astropy/resources/manifests/astropy-1.4.0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
id: asdf://astropy.org/astropy/manifests/astropy-1.4.0
extension_uri: asdf://astropy.org/astropy/extensions/astropy-1.4.0
title: Astropy extension 1.4.0
description: |-
A set of tags for serializing astropy objects. This does not include most
model classes, which are handled by an implementation of the ASDF
transform extension.
asdf_standard_requirement:
gte: 1.6.0
tags:
- tag_uri: tag:astropy.org:astropy/time/timedelta-1.1.0
schema_uri: http://astropy.org/schemas/astropy/time/timedelta-1.1.0
title: Represents an instance of TimeDelta from astropy
description: |-
Represents the time difference between two times.
- tag_uri: tag:astropy.org:astropy/fits/fits-1.1.0
schema_uri: http://astropy.org/schemas/astropy/fits/fits-1.1.0
title: A FITS file inside of an ASDF file.
description: |-
This schema is useful for distributing ASDF files that can
automatically be converted to FITS files by specifying the exact
content of the resulting FITS file.

Not all kinds of data in FITS are directly representable in ASDF.
For example, applying an offset and scale to the data using the
`BZERO` and `BSCALE` keywords. In these cases, it will not be
possible to store the data in the native format from FITS and also
be accessible in its proper form in the ASDF file.

Only image and binary table extensions are supported.
- tag_uri: tag:astropy.org:astropy/table/table-1.2.0
schema_uri: http://astropy.org/schemas/astropy/table/table-1.2.0
title: A table.
description: |-
A table is represented as a list of columns, where each entry is a
[column](ref:http://stsci.edu/schemas/asdf/table/column-1.1.0)
object, containing the data and some additional information.

The data itself may be stored inline as text, or in binary in either
row- or column-major order by use of the `strides` property on the
individual column arrays.

Each column in the table must have the same first (slowest moving)
dimension.
- tag_uri: tag:astropy.org:astropy/transform/units_mapping-1.1.0
schema_uri: http://astropy.org/schemas/astropy/transform/units_mapping-1.1.0
title: Mapper that operates on the units of the input.
description: |-
This transform operates on the units of the input, first converting to
the expected input units, then assigning replacement output units without
further conversion.
- tag_uri: tag:astropy.org:astropy/table/ndarraymixin-1.0.0
schema_uri: http://astropy.org/schemas/astropy/table/ndarraymixin-1.0.0
title: NdarrayMixin column.
description: |-
Represents an astropy.table.NdarrayMixin instance.
- tag_uri: tag:astropy.org:astropy/wcs/slicedwcs-1.1.0
schema_uri: http://astropy.org/schemas/astropy/wcs/slicedwcs-1.1.0
title: Represents an instance of SlicedLowLevelWCS
description: |-
The SlicedLowLevelWCS class is a wrapper class for WCS that applies slices
to the WCS, allowing certain pixel and world dimensions to be retained or
dropped.

It manages the slicing and coordinate transformations while preserving
the underlying WCS object.
- tag_uri: tag:astropy.org:astropy/wcs/wcs-1.0.0
schema_uri: http://astropy.org/schemas/astropy/wcs/wcs-1.0.0
title: FITS WCS (World Coordinate System) Converter
description: |-
Represents the FITS WCS object, the HDUlist of the FITS header is preserved
during serialization and during deserialization the WCS object is recreated
from the HDUlist.
52 changes: 52 additions & 0 deletions asdf_astropy/resources/schemas/wcs/slicedwcs-1.1.0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
%YAML 1.1
---
$schema: "http://stsci.edu/schemas/yaml-schema/draft-01"
id: "http://astropy.org/schemas/astropy/wcs/slicedwcs-1.1.0"

title: Represents the SlicedLowLevelWCS object

description: >-
The SlicedLowLevelWCS class is a wrapper class for WCS that applies slices
to the WCS, allowing certain pixel and world dimensions to be retained or
dropped.
It manages the slicing and coordinate transformations while preserving
the underlying WCS object.

allOf:
- type: object
properties:
wcs:
anyOf:
# Known WCS objects
- tag: "tag:astropy.org:astropy/wcs/wcs-1*"
- tag: "tag:stsci.edu:gwcs/wcs-*"
- tag: "tag:astropy.org:astropy/wcs/slicedwcs-*"
- tag: "tag:sunpy.org:ndcube/resampledwcs-*"
- tag: "tag:sunpy.org:ndcube/ndcubesequence-*"
- tag: "tag:sunpy.org:ndcube/reorderedwcs-*"
- tag: "tag:sunpy.org:ndcube/compoundwcs-*"
# Allow anything else because any APE-14 compliant object is valid
- {}

slices_array:
type: array
items:
- oneOf:
- type: integer
- type: object
properties:
start:
anyOf:
- type: integer
- type: "null"
stop:
anyOf:
- type: integer
- type: "null"
step:
anyOf:
- type: integer
- type: "null"


required: ["wcs", "slices_array"]
Loading