unxt-api#

Abstract dispatch API for unxt.

unxt-api defines the abstract dispatch interfaces that unxt and other packages implement. It provides a minimal dependency foundation for packages that want to define or use unxt’s multiple-dispatch-based API without pulling in the full unxt implementation.

The unxt-api package serves several important purposes:

  1. Minimal Dependencies: Depends only on plum-dispatch, not on jax, numpy, or astropy

  2. Extensibility: Allows third-party packages to register their own implementations

  3. Type Safety: Provides a clear contract for what functions exist and what they should do

  4. Separation of Concerns: API definitions are separate from implementation details

Installation#

pip install unxt-api
uv add unxt-api

Core API#

The unxt-api package defines abstract dispatch functions organized by domain:

  • Dimensions (dimension(), dimension_of()) - Working with physical dimensions

  • Units (unit(), unit_of()) - Constructing and inspecting units

  • Quantities (uconvert(), uconvert_value(), ustrip(), is_unit_convertible(), wrap_to()) - Unit conversion and quantity operations

  • Unit Systems (unitsystem_of()) - Inspecting unit systems

Using Multiple Dispatch#

All functions in unxt-api use plum for multiple dispatch. This means:

  1. Functions can have multiple implementations based on argument types

  2. You can register your own implementations for custom types

  3. Type annotations drive dispatch - the runtime types of arguments determine which implementation runs

Viewing All Implementations#

To see all registered implementations of a function:

import unxt_api as uapi

# View all dimension() implementations
uapi.dimension.methods

# View all uconvert() implementations
uapi.uconvert.methods

# View all unit_of() implementations
uapi.unit_of.methods

Registering Custom Implementations#

You can extend unxt-api’s dispatch system with your own types:

from plum import dispatch
import unxt_api as uapi


class MyCustomQuantity:
    def __init__(self, value, unit_str):
        self.value = value
        self.unit_str = unit_str


# Register implementation for your type
@dispatch
def unit_of(obj: MyCustomQuantity, /):
    """Get unit from MyCustomQuantity."""
    return uapi.unit(obj.unit_str)


# Now it works with the dispatch system
my_q = MyCustomQuantity(5.0, "m")
uapi.unit_of(my_q)  # Unit("m")

Integration with unxt#

The unxt package provides the concrete implementations of all unxt-api functions. When you use:

import unxt as u

q = u.Q(5, "m")
u.uconvert("km", q)

The u.uconvert function is the implementation registered by unxt for the abstract unxt_api.uconvert function.

For Package Authors#

If you’re writing a package that works with physical quantities:

Minimal Dependency Approach#

Depend on unxt-api to use the dispatch system without pulling in JAX:

# pyproject.toml
[project]
dependencies = ["unxt-api>=X.Y.Z"]

Then register your implementations:

from plum import dispatch


# Define a custom type (example)
class YourType:
    def __init__(self, value, unit_str, dim_str):
        self.value = value
        self.unit = unit_str
        self.dimension = dim_str


@dispatch
def unit_of(obj: YourType, /):
    """Get unit from your type."""
    return obj.unit


@dispatch
def dimension_of(obj: YourType, /):
    """Get dimension from your type."""
    return obj.dimension

Full Integration Approach#

If you need JAX and want full unxt functionality:

# pyproject.toml
[project]
dependencies = [
    "unxt>=X.Y.Z",  # Includes unxt-api transitively
]

Then use unxt’s types directly:

import unxt as u


@dispatch
def your_function(q: u.Quantity, /):
    """Work with unxt quantities."""
    return q * 2

See Also#

License#

BSD 3-Clause License. See LICENSE for details.

Contributing#

Contributions are welcome! Please see the main unxt repository for contributing guidelines.