Skip to content

Commit

Permalink
Merge pull request #393 from spacetelescope/0.18.0x
Browse files Browse the repository at this point in the history
0.18.0x
  • Loading branch information
nden authored Dec 22, 2021
2 parents e8a5ecf + 8e57a1b commit c0ae787
Show file tree
Hide file tree
Showing 57 changed files with 826 additions and 2,141 deletions.
10 changes: 0 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ jobs:
python-version: 3.9
toxenv: py39

- name: Python 3.7
runs-on: ubuntu-latest
python-version: 3.7
toxenv: py37

- name: Python 3.6
runs-on: ubuntu-latest
python-version: 3.6
toxenv: py36

- name: Python 3.8 with coverage
runs-on: ubuntu-latest
python-version: 3.8
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Publish to PyPI

on:
release:
types: [released]

jobs:
publish:
uses: spacetelescope/action-publish_to_pypi/.github/workflows/workflow.yml@master
with:
test: false
build_platform_wheels: false # Set to true if your package contains a C extension
secrets:
user: ${{ secrets.PYPI_USERNAME_STSCI_MAINTAINER }}
password: ${{ secrets.PYPI_PASSWORD_STSCI_MAINTAINER }} # WARNING: Do not hardcode secret values here! If you want to use a different user or password, you can override this secret by creating one with the same name in your Github repository settings.
test_password: ${{ secrets.PYPI_PASSWORD_STSCI_MAINTAINER_TEST }}
20 changes: 19 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
0.18.0 (2021-12-22)
-------------------
Bug Fixes
^^^^^^^^^

- Updated code in ``region.py`` with latest improvements and bug fixes
from ``stsci.skypac.regions.py`` [#382]


New Features
^^^^^^^^^^^^

- Enabled ``CompoundBoundingBox`` support for wcs. [#375]

- Moved schemas to standalone package ``asdf-wcs-schemas``.
Reworked the serialization code to use ASDF converters. [#388]

0.17.1 (2021-11-27)
-------------------

Expand All @@ -22,6 +39,7 @@ Bug Fixes

- Use ``CD`` formalism in ``WCS.to_fits_sip()``. [#380]


New Features
^^^^^^^^^^^^
- ``wcs_from_points`` now includes fitting for the inverse transform. [#349]
Expand All @@ -36,7 +54,7 @@ API Changes
- Modified interface to ``wcs_from_points`` function to better match analogous function
in astropy. [#349]

- ``Model._BoundingBox`` was renamed to ``Model.ModelBoundingBox`. [#376, #377]
- ``Model._BoundingBox`` was renamed to ``Model.ModelBoundingBox``. [#376, #377]

0.16.1 (2020-12-20)
-------------------
Expand Down
33 changes: 0 additions & 33 deletions docs/gwcs/schemas/index.rst

This file was deleted.

23 changes: 14 additions & 9 deletions docs/gwcs/wcs_validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ WCS validation
The WCS is validated when an object is read in or written to a file.
However, this happens transparently to the end user and knowing
the details of the validation machinery is not necessary to use or
construct a WCS object.

GWCS uses the `Advanced Scientific Data Format <https://asdf-standard.readthedocs.io/en/latest/>`__ (ASDF)
to validate the transforms, coordinate frames and the overall WCS object structure.
ASDF makes use of abstract data type
definitions called ``schemas``. The serialization and deserialization happens in classes,
referred to as ``tags``. Most of the transform schemas live in the ``asdf-standard`` package while most of the transform tags live in ``astropy``. :ref:`gwcs-schemas` are available for the WCS object, coordinate frames and some WCS specific transforms.

Packages using GWCS may create their own transforms and schemas and register them as an ``Asdf Extension``. If those are of general use, it is recommended they be included in astropy.
construct a WCS object.

GWCS uses the
`Advanced Scientific Data Format <https://asdf-standard.readthedocs.io/en/latest/>`_
(ASDF) to serialize and deserialize GWCS objects (including transformations
and frames) and to provide validation that the serialization is correct.
ASDF makes use of abstract data type definitions called ``schemas``.
The serialization and deserialization happens in classes, referred to as
``converters`` defined in ``gwcs.converters.*`` modules. Most of the schemas
available for the WCS object, coordinate frames and some WCS specific transforms
live in the
`asdf-wcs-schemas package <http://asdf-wcs-schemas.readthedocs.io/en/latest>`_.

Packages using GWCS may create their own transforms and schemas and register
them as an ``Asdf Extension``. If those are of general use, it is recommended
they be included in `asdf-astropy <https://github.com/astropy/asdf-astropy>`_.
3 changes: 1 addition & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ Save a WCS object as an ASDF extension in a FITS file
1 SCI 1 ImageHDU 71 (600, 550) float32
>>> tree = {"sci": hdul[1].data,
... "wcs": wcsobj}
>>> fa = fits.embed.AsdfInFits(hdul, tree)
>>> fa = fits_embed.AsdfInFits(hdul, tree)
>>> fa.write_to("imaging_with_wcs_in_asdf.fits")
>>> fits.info("imaging_with_wcs_in_asdf.fits")
Filename: example_with_wcs.asdf
Expand Down Expand Up @@ -306,7 +306,6 @@ Using `gwcs`
gwcs/wcstools.rst
gwcs/pure_asdf.rst
gwcs/wcs_validation.rst
gwcs/schemas/index.rst
gwcs/points_to_wcs.rst


Expand Down
2 changes: 2 additions & 0 deletions gwcs/converters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# -*- coding: utf-8 -*-
44 changes: 21 additions & 23 deletions gwcs/tags/geometry_models.py → gwcs/converters/geometry.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
"""
ASDF tags for geometry related models.
"""
from asdf import yamlutil
from ..gwcs_types import GWCSTransformType
from .. geometry import (ToDirectionCosines, FromDirectionCosines,
SphericalToCartesian, CartesianToSpherical)
from asdf_astropy.converters.transform.core import TransformConverterBase


__all__ = ['DirectionCosinesType', 'SphericalCartesianType']
__all__ = ['DirectionCosinesConverter', 'SphericalCartesianConverter']


class DirectionCosinesType(GWCSTransformType):
name = "direction_cosines"
types = [ToDirectionCosines, FromDirectionCosines]
version = "1.1.0"
class DirectionCosinesConverter(TransformConverterBase):
tags = ["tag:stsci.edu:gwcs/direction_cosines-*"]
types = ["gwcs.geometry.ToDirectionCosines",
"gwcs.geometry.FromDirectionCosines"]

@classmethod
def from_tree_transform(cls, node, ctx):
def from_yaml_tree_transform(self, node, tag, ctx):
from ..geometry import ToDirectionCosines, FromDirectionCosines
transform_type = node['transform_type']
if transform_type == 'to_direction_cosines':
return ToDirectionCosines()
Expand All @@ -25,25 +23,25 @@ def from_tree_transform(cls, node, ctx):
else:
raise TypeError(f"Unknown model_type {transform_type}")

@classmethod
def to_tree_transform(cls, model, ctx):
def to_yaml_tree_transform(self, model, tag, ctx):
from ..geometry import ToDirectionCosines, FromDirectionCosines
if isinstance(model, FromDirectionCosines):
transform_type = 'from_direction_cosines'
elif isinstance(model, ToDirectionCosines):
transform_type = 'to_direction_cosines'
else:
raise TypeError(f"Model of type {model.__class__} is not supported.")
node = {'transform_type': transform_type}
return yamlutil.custom_tree_to_tagged_tree(node, ctx)
return node


class SphericalCartesianType(GWCSTransformType):
name = "spherical_cartesian"
types = [SphericalToCartesian, CartesianToSpherical]
version = "1.1.0"
class SphericalCartesianConverter(TransformConverterBase):
tags = ["tag:stsci.edu:gwcs/spherical_cartesian-*"]
types = ["gwcs.geometry.SphericalToCartesian",
"gwcs.geometry.CartesianToSpherical"]

@classmethod
def from_tree_transform(cls, node, ctx):
def from_yaml_tree_transform(self, node, tag, ctx):
from ..geometry import SphericalToCartesian, CartesianToSpherical
transform_type = node['transform_type']
wrap_lon_at = node['wrap_lon_at']
if transform_type == 'spherical_to_cartesian':
Expand All @@ -53,8 +51,8 @@ def from_tree_transform(cls, node, ctx):
else:
raise TypeError(f"Unknown model_type {transform_type}")

@classmethod
def to_tree_transform(cls, model, ctx):
def to_yaml_tree_transform(self, model, tag, ctx):
from ..geometry import SphericalToCartesian, CartesianToSpherical
if isinstance(model, SphericalToCartesian):
transform_type = 'spherical_to_cartesian'
elif isinstance(model, CartesianToSpherical):
Expand All @@ -66,4 +64,4 @@ def to_tree_transform(cls, model, ctx):
'transform_type': transform_type,
'wrap_lon_at': model.wrap_lon_at
}
return yamlutil.custom_tree_to_tagged_tree(node, ctx)
return node
77 changes: 22 additions & 55 deletions gwcs/tags/selectortags.py → gwcs/converters/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,36 @@

from collections import OrderedDict
import numpy as np
from numpy.testing import assert_array_equal
from astropy.modeling import models
from astropy.modeling.core import Model
from astropy.utils.misc import isiterable

from asdf import yamlutil
from asdf.tags.core.ndarray import NDArrayType
from ..gwcs_types import GWCSTransformType
from asdf_astropy.converters.transform.core import TransformConverterBase


from ..selector import *
__all__ = ['LabelMapperConverter', 'RegionsSelectorConverter']


__all__ = ['LabelMapperType', 'RegionsSelectorType']
class LabelMapperConverter(TransformConverterBase):
tags = ["tag:stsci.edu:gwcs/label_mapper-*"]
types = ["gwcs.selector.LabelMapperArray", "gwcs.selector.LabelMapperDict",
"gwcs.selector.LabelMapperRange", "gwcs.selector.LabelMapper"]


class LabelMapperType(GWCSTransformType):
name = "label_mapper"
types = [LabelMapperArray, LabelMapperDict, LabelMapperRange, LabelMapper]
version = "1.1.0"

@classmethod
def from_tree_transform(cls, node, ctx):
def from_yaml_tree_transform(self, node, tag, ctx):
from ..selector import (LabelMapperArray, LabelMapperDict,
LabelMapperRange, LabelMapper)
inputs_mapping = node.get('inputs_mapping', None)
if inputs_mapping is not None and not isinstance(inputs_mapping, models.Mapping):
raise TypeError("inputs_mapping must be an instance"
"of astropy.modeling.models.Mapping.")
mapper = node['mapper']
atol = node.get('atol', 10**-8)
atol = node.get('atol', 1e-8)
no_label = node.get('no_label', np.nan)

if isinstance(mapper, NDArrayType):
if mapper.ndim != 2:
raise NotImplementedError(
"GWCS currently only supports 2x2 masks ")
raise NotImplementedError("GWCS currently only supports 2D masks.")
return LabelMapperArray(mapper, inputs_mapping)
elif isinstance(mapper, Model):
inputs = node.get('inputs')
Expand All @@ -56,8 +51,9 @@ def from_tree_transform(cls, node, ctx):
dict_mapper = dict(zip(labels, transforms))
return LabelMapperDict(inputs, dict_mapper, inputs_mapping, atol=atol)

@classmethod
def to_tree_transform(cls, model, ctx):
def to_yaml_tree_transform(self, model, tag, ctx):
from ..selector import (LabelMapperArray, LabelMapperDict,
LabelMapperRange, LabelMapper)
node = OrderedDict()
node['no_label'] = model.no_label
if model.inputs_mapping is not None:
Expand Down Expand Up @@ -86,31 +82,15 @@ def to_tree_transform(cls, model, ctx):
else:
raise TypeError("Unrecognized type of LabelMapper - {0}".format(model))

return yamlutil.custom_tree_to_tagged_tree(node, ctx)

@classmethod
def assert_equal(cls, a, b):
# TODO: If models become comparable themselves, remove this.
assert (a.__class__ == b.__class__) # nosec
if isinstance(a.mapper, dict):
assert(a.mapper.__class__ == b.mapper.__class__) # nosec
assert(all(np.in1d(list(a.mapper), list(b.mapper)))) # nosec
for k in a.mapper:
assert (a.mapper[k].__class__ == b.mapper[k].__class__) # nosec
assert(all(a.mapper[k].parameters == b.mapper[k].parameters)) # nosec
assert (a.inputs == b.inputs) # nosec
assert (a.inputs_mapping.mapping == b.inputs_mapping.mapping) # nosec
else:
assert_array_equal(a.mapper, b.mapper)
return node


class RegionsSelectorType(GWCSTransformType):
name = "regions_selector"
types = [RegionsSelector]
version = "1.1.0"
class RegionsSelectorConverter(TransformConverterBase):
tags = ["tag:stsci.edu:gwcs/regions_selector-*"]
types = ["gwcs.selector.RegionsSelector"]

@classmethod
def from_tree_transform(cls, node, ctx):
def from_yaml_tree_transform(self, node, tag, ctx):
from ..selector import RegionsSelector
inputs = node['inputs']
outputs = node['outputs']
label_mapper = node['label_mapper']
Expand All @@ -120,8 +100,7 @@ def from_tree_transform(cls, node, ctx):
return RegionsSelector(inputs, outputs,
sel, label_mapper, undefined_transform_value)

@classmethod
def to_tree_transform(cls, model, ctx):
def to_yaml_tree_transform(self, model, tag, ctx):
selector = OrderedDict()
node = OrderedDict()
labels = list(model.selector)
Expand All @@ -135,16 +114,4 @@ def to_tree_transform(cls, model, ctx):
node['selector'] = selector
node['label_mapper'] = model.label_mapper
node['undefined_transform_value'] = model.undefined_transform_value
return yamlutil.custom_tree_to_tagged_tree(node, ctx)

@classmethod
def assert_equal(cls, a, b):
# TODO: If models become comparable themselves, remove this.
assert (a.__class__ == b.__class__) # nosec
LabelMapperType.assert_equal(a.label_mapper, b.label_mapper)
assert_array_equal(a.inputs, b.inputs)
assert_array_equal(a.outputs, b.outputs)
assert_array_equal(a.selector.keys(), b.selector.keys())
for key in a.selector:
assert_array_equal(a.selector[key].parameters, b.selector[key].parameters)
assert_array_equal(a.undefined_transform_value, b.undefined_transform_value)
return node
Loading

0 comments on commit c0ae787

Please sign in to comment.