Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ New Features
scale is computed in closed form, and the elliptical and rectangular
annuli convert both of their shapes with one WCS evaluation in each
direction. [#707]
- Add serialization of regions to ASDF files. [#702]

Bug Fixes
---------
Expand Down
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ requires-python = '>=3.11'
dependencies = [
'astropy >= 7.0',
'numpy >= 2.0',
'asdf',
]

[project.urls]
Expand All @@ -39,6 +40,7 @@ all = [
'shapely >= 2.1',
]
test = [
'pytest-asdf-plugin',
'gwcs >= 0.22',
'pytest-arraydiff >= 0.6.1',
'pytest-astropy >= 0.12',
Expand Down Expand Up @@ -80,9 +82,13 @@ include-package-data = false
namespaces = false

[tool.setuptools.package-data]
'regions.io.asdf.resources' = [
'**/*.yaml'
]
'*' = [
'data/*',
]

'regions.shapes.tests' = [
'reference/*.txt',
'data/*.fits',
Expand All @@ -97,6 +103,11 @@ namespaces = false
'data/*.fits',
]


[project.entry-points]
'asdf.extensions' = {regions = 'regions.io.asdf.extension:get_extensions'}
'asdf.resource_mappings' = {regions = 'regions.io.asdf.extension:get_resource_mappings'}

[tool.pytest.ini_options]
minversion = "8.0"
testpaths = [
Expand All @@ -117,6 +128,9 @@ addopts = [
'--strict-config',
'--strict-markers',
]
asdf_schema_root = 'regions/io/asdf/resources/schemas'
asdf_schema_tests_enabled = true

log_level = 'INFO'
log_cli_level = 'INFO'
xfail_strict = true
Expand All @@ -142,6 +156,7 @@ omit = [
'*/regions/*/tests/*',
'*/regions/extern/*',
'*/regions/version*',
'regions/io/asdf/converters/tests/*',
]

[tool.coverage.report]
Expand Down Expand Up @@ -224,6 +239,8 @@ exclude = [
'\._.*', # private functions/methods
'^test_*', # test code
'^conftest.*$', # pytest configuration
'to_yaml_tree', # ASDF converter
'from_yaml_tree', # ASDF converter
]

[tool.ruff]
Expand Down
1 change: 1 addition & 0 deletions regions/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
from .fits.core import * # noqa: F401, F403
from .fits.read import * # noqa: F401, F403
from .fits.write import * # noqa: F401, F403
from .asdf import extension # noqa: F401
Empty file added regions/io/asdf/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions regions/io/asdf/converters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
ASDF converters.
"""

from .pixel_coords import PixCoordConverter

__all__ = [
'PixCoordConverter',
]
33 changes: 33 additions & 0 deletions regions/io/asdf/converters/pixel_coords.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst

"""
ASDF converter for PixCoord object.
"""
from asdf.extension import Converter

__all__ = [
'PixCoordConverter',
]


class PixCoordConverter(Converter):
"""
ASDF converter for pixel coordinates.
"""

tags = ('tag:astropy.org:regions/pixcoord-*',)
types = ('regions.core.pixcoord.PixCoord',)

def to_yaml_tree(self, obj, tag, ctx): # noqa: ARG002

return {
'x': obj.x,
'y': obj.y,
}

def from_yaml_tree(self, node, tag, ctx): # noqa: ARG002
from regions.core.pixcoord import PixCoord
return PixCoord(
x=node['x'],
y=node['y'],
)
Empty file.
21 changes: 21 additions & 0 deletions regions/io/asdf/converters/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst

import pytest

from regions.io.asdf.converters.tests import examples


@pytest.fixture
def test_pixcoord():
"""
Test that PixCoord can be serialized and deserialized correctly.
"""
return examples.pixcoord()


@pytest.fixture
def test_pixcoord_array():
"""
Test that PixCoord can be serialized and deserialized correctly.
"""
return examples.pixcoord_array()
16 changes: 16 additions & 0 deletions regions/io/asdf/converters/tests/examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import numpy as np

from regions.core import PixCoord

parameters = {
'PixCoord': ['x', 'y'],
}


def pixcoord():
return PixCoord(1, 2), parameters['PixCoord']


def pixcoord_array():
return PixCoord(np.array([1, 2]), np.array([3, 4])), parameters['PixCoord']
37 changes: 37 additions & 0 deletions regions/io/asdf/converters/tests/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst

import asdf
import pytest
from numpy.testing import assert_array_equal


@pytest.fixture
def obj(request):
"""
A pytest fixture that returns a 'Region' instance and the
list of parameters to test.
"""
return request.getfixturevalue(request.param)


region_params = pytest.mark.parametrize('obj', [
'test_pixcoord',
'test_pixcoord_array',
], indirect=True)


@region_params
def test_region_converters(tmp_path, obj):
"""
Test that the Region converters can round-trip a Region object.
"""
region, pars = obj
with asdf.AsdfFile() as af:
af['region'] = region
af.write_to(tmp_path / 'region.asdf')

with asdf.open(tmp_path / 'region.asdf') as af:
region2 = af['region']
for parameter in pars:
assert_array_equal(getattr(region, parameter),
getattr(region2, parameter))
66 changes: 66 additions & 0 deletions regions/io/asdf/extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
ASDF extension for regions.
"""
import importlib.resources as importlib_resources

from asdf.extension import ManifestExtension
from asdf.resource import DirectoryResourceMapping

from regions.io.asdf.converters.pixel_coords import PixCoordConverter

__all__ = ['PixCoordConverter']


REGIONS_CONVERTERS = [
PixCoordConverter(),
]

# The order here is important; asdf will prefer to use extensions
# that occur earlier in the list.
REGIONS_MANIFEST_URIS = [
'asdf://astropy.org/regions/manifests/regions-1.0.0',
]


def get_extensions():
"""
Get the regions extension.
This method is registered with the asdf.extensions entry point.

Returns
-------
list
A list of ASDF extensions.
"""
return [
ManifestExtension.from_uri(
uri,
converters=REGIONS_CONVERTERS,
)
for uri in REGIONS_MANIFEST_URIS
]


def get_resource_mappings():
"""
Get the resource mapping instances for the regions schemas
and manifests. This method is registered with the
asdf.resource_mappings entry point.

Returns
-------
list
A list of collections.abc.Mapping of ASDF resource mappings.
"""
from regions.io.asdf import resources

resources_root = importlib_resources.files(resources)

return [
DirectoryResourceMapping(resources_root / 'schemas',
'asdf://astropy.org/regions/schemas',
recursive=True),
DirectoryResourceMapping(resources_root / 'manifests',
'asdf://astropy.org/regions/manifests'),
]
Empty file.
10 changes: 10 additions & 0 deletions regions/io/asdf/resources/manifests/regions-1.0.0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
id: asdf://astropy.org/regions/manifests/regions-1.0.0
extension_uri: asdf://astropy.org/regions/extensions/regions-1.0.0
title: Regions extension 1.0.0
description: |-
A set of tags for serializing astropy regions objects.
tags:
- tag_uri: tag:astropy.org:regions/pixcoord-1.0.0
schema_uri: asdf://astropy.org/regions/schemas/pixcoord-1.0.0
title: PixCoord schema
description: Pixel coordinates for regions.
33 changes: 33 additions & 0 deletions regions/io/asdf/resources/schemas/pixcoord-1.0.0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
%YAML 1.1
---
$schema: 'http://stsci.edu/schemas/yaml-schema/draft-01'
id: 'asdf://astropy.org/regions/schemas/pixcoord-1.0.0'
title: Pixel coordinates
description: |
ASDF schema for serializing a pixel coordinate.

examples:
- - A 'PixCoord' object with x=1.0 and y=2.0
- |
!<tag:astropy.org:regions/pixcoord-1.0.0%22> {x: 1, y: 2}

type: object
properties:
x:
title: X coordinate.
anyOf:
- type: number
- type: array
- tag: 'tag:stsci.edu:asdf/core/ndarray-1.*'
description: |
The x coordinate of the pixel.
y:
title: Y coordinate.
anyOf:
- type: number
- type: array
- tag: 'tag:stsci.edu:asdf/core/ndarray-1.*'
description: |
The y coordinate of the pixel.
required: [x, y]
...
Loading