Source code for gwcs.wcs._step
import sys
import warnings
from typing import NamedTuple, Self, TypeAlias, Union
from astropy.modeling.core import Model
from gwcs.coordinate_frames import (
BaseCoordinateFrame,
CoordinateFrame,
CoordinateFrameProtocol,
EmptyFrame,
)
__all__ = [
"IndexedStep",
"Mdl",
"Step",
"StepTuple",
]
Mdl: TypeAlias = Union[Model, None] # noqa: UP007
StepTuple: TypeAlias = tuple[CoordinateFrameProtocol, Union[Model, None]] # noqa: UP007
# Runtime checkable isinstance check evaluates the actual properties of the object
# in Python 3.11, so EmptyFrame causes an error to be raised if we attempt to
# check if it is a CoordinateFrameProtocol. In Python 3.12+, the check does not
# evaluate the properties of the object, so it does not cause an error.
if sys.version_info >= (3, 12):
def _is_coordinate_frame(frame: str | CoordinateFrameProtocol) -> bool:
return isinstance(frame, CoordinateFrameProtocol)
else:
def _is_coordinate_frame(frame: str | CoordinateFrameProtocol) -> bool:
return isinstance(frame, BaseCoordinateFrame | CoordinateFrame | EmptyFrame)
[docs]
class Step:
"""
Represents a ``step`` in the WCS pipeline.
Parameters
----------
frame : `~gwcs.coordinate_frames.CoordinateFrameProtocol` or str
A gwcs coordinate frame object.
transform : `~astropy.modeling.Model` or None
A transform from this step's frame to next step's frame.
The transform of the last step should be `None`.
"""
def __init__(
self, frame: str | CoordinateFrameProtocol, transform: Mdl = None
) -> None:
# Allow for a string to be passed in for the frame but be turned into a
# frame object
# This is correct type-wise, but the Python 3.11 bugfix causes a MyPy error
self.frame = (
frame
if _is_coordinate_frame(frame)
else EmptyFrame.from_transform(frame, transform) # type: ignore[assignment, arg-type]
)
self.transform = transform
@property
def frame(self) -> CoordinateFrameProtocol:
return self._frame
@frame.setter
def frame(self, val: CoordinateFrameProtocol) -> None:
if not _is_coordinate_frame(val):
msg = '"frame" should be an instance of CoordinateFrameProtocol.'
raise TypeError(msg)
self._frame = val
@property
def transform(self) -> Mdl:
return self._transform
@transform.setter
def transform(self, val: Mdl) -> None:
if val is not None and not isinstance(val, Model):
msg = '"transform" should be an instance of astropy.modeling.Model.'
raise TypeError(msg)
self._transform = val
@property
def frame_name(self) -> str:
return self.frame.name
@property
def inverse(self) -> Mdl:
if self.transform is None:
return None
try:
return self.transform.inverse
except NotImplementedError:
return None
def __str__(self) -> str:
return (
f"{self.frame_name}\t "
f"{getattr(self.transform, 'name', 'None') or type(self.transform).__name__}" # noqa: E501
)
def __repr__(self) -> str:
return (
f"Step(frame={self.frame_name}, "
f"transform={getattr(self.transform, 'name', 'None') or type(self.transform).__name__})" # noqa: E501
)
[docs]
def copy(self) -> Self:
return type(self)(self.frame, self.transform)
def __getitem__(self, ind):
warnings.warn(
"Indexing a WCS.pipeline step is deprecated. "
"Use the `frame` and `transform` attributes instead.",
DeprecationWarning,
stacklevel=2,
)
if ind not in (0, 1):
msg = "Allowed inices are 0 (frame) and 1 (transform)."
raise IndexError(msg)
if ind == 0:
return self.frame
return self.transform
class IndexedStep(NamedTuple):
"""
Class to handle a step and its index in the pipeline.
"""
idx: int
step: Step