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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ astro = ["coordinaxs.astro>=0.24"]
benchmark = ["pytest-benchmark>=5.2.3", "pytest-codspeed>=5.0.3"]
curveframes = ["coordinaxs.curveframes>=0.24"]
interop-astropy = ["coordinaxs.interop.astropy>=0.24"]
parametric = ["unxts.parametric>=2.0"]
workspace = [
"coordinaxs.api>=0.24",
"coordinaxs.astro>=0.24",
Expand Down
13 changes: 12 additions & 1 deletion src/coordinax/distances/_src/register_parametric.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
"""`from_` overloads for `unxts.parametric`; imported only when it is installed.
"""Registrations for `unxts.parametric`; imported only when it is installed.

A `ParametricQuantity["length"|"angle"|"mag"]` carries its physical type in the
*type*, so plum can pick the branch statically and prefers these over the
`AbstractQuantity` catch-all in `measures`, which has to read
`u.dimension_of(q)` at runtime. Plain `unxt.Quantity` still takes that path.

It is also not a `unxt.Q` subclass, so the `AbstractDistance`/`Q` promotion
rules in `base` never reach it; the rule below closes that.
"""

__all__: tuple[str, ...] = ()

from typing import Any

from plum import add_promotion_rule

# Optional dependency: absent from the lint environment by design.
from unxts.parametric import PQ # ty: ignore[unresolved-import]

from .base import AbstractDistance
from .measures import Distance, _from_angle, _from_length, _from_mag


Expand All @@ -32,3 +38,8 @@ def from_(cls: type[Distance], q: PQ["angle"], /, **kw: Any) -> Distance:
def from_(cls: type[Distance], q: PQ["mag"], /, **kw: Any) -> Distance:
"""Construct a distance from a parametric magnitude quantity."""
return _from_mag(cls, q, **kw)


# Degrade to the parametric quantity, as the `AbstractDistance`/`Q` rules in
# `base` do.
add_promotion_rule(AbstractDistance, PQ, PQ)
19 changes: 19 additions & 0 deletions tests/unit/distances/test_parametric.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import jax.numpy as jnp
import plum
import pytest

import unxt as u
Expand Down Expand Up @@ -69,3 +70,21 @@ def test_dispatches_by_type_not_by_dimension(self, value: float, unit: str) -> N
parametric = _resolved_from_(cxd.Distance, PQ(value, unit))
plain = _resolved_from_(cxd.Distance, u.Q(value, unit))
assert parametric is not plain


class TestParametricPromotion:
"""A distance and a `PQ` promote to the `PQ`."""

def test_promotes_to_parametric_quantity(self) -> None:
"""`plum.promote` degrades the distance, as it does for `Q`."""
promoted = plum.promote(cxd.Distance(1, "pc"), PQ(1.0, "rad"))
assert all(isinstance(x, PQ) for x in promoted)

def test_arithmetic_is_order_independent(self) -> None:
"""Both operand orders give the same `PQ`; `Distance * PQ` used to raise."""
d, pq = cxd.Distance(1, "pc"), PQ(1.0, "rad")
forward, reverse = d * pq, pq * d
assert isinstance(forward, PQ)
assert isinstance(reverse, PQ)
assert forward.unit == reverse.unit
assert jnp.allclose(forward.value, reverse.value)
6 changes: 5 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading