Skip to main content

Hypothesis strategies for unxt

Project description

unxt-hypothesis

Hypothesis strategies for property-based testing with unxt.

This package provides Hypothesis strategies for generating random Quantity, Unit, and UnitSystem objects for property-based testing.

Quick Start

from hypothesis import given

import unxt as u
import unxt_hypothesis as ust


@given(q=ust.quantities(unit="km/s"))
def test_quantity_property(q):
    """Test that all quantities have value and unit."""
    assert q.value is not None
    assert q.unit is not None


@given(u=ust.units("length"))
def test_unit_property(u):
    """Test that units can be converted to strings."""
    assert str(u) is not None


@given(sys=ust.unitsystems("m", "s", "kg", "rad"))
def test_unitsystem_property(sys):
    """Test that unit systems have expected base units."""
    assert len(sys) == 4

Strategies

derived_units(base, *, integer_powers=True, max_complexity=3)

Generate units that are dimensionally equivalent to a given base unit.

Parameters:

  • base (str | apyu.UnitBase | SearchStrategy): Base unit (e.g., "m", "s", "kg") or a hypothesis strategy that generates such units.
  • integer_powers (bool): If True, only generate units with integer powers of base units (default: True).
  • max_complexity (int): Maximum number of additional base unit factors to combine (default: 3).

Returns: unxt.AbstractUnit

units(dimension=None, *, max_complexity=2, allow_non_integer_powers=False)

Generate random Unit objects from astropy.

Parameters:

  • dimension (str | apyu.PhysicalType | None): The physical dimension of the unit. If None, generates units from various dimensions. Examples: "length", "velocity", "energy".
  • max_complexity (int): Maximum complexity of compound units (default: 2).
  • allow_non_integer_powers (bool): Whether to allow non-integer powers in units (default: False).

Returns: unxt.AbstractUnit

quantities(*, shape=None, dtype=None, unit=None)

Generate random Quantity objects.

Parameters:

  • shape (int | tuple[int, ...] | st.SearchStrategy | None): Shape of the array. Can be:
    • None (default): Generates small arrays with various shapes
    • int: Scalar shape specification (e.g., 3 for shape (3,))
    • tuple: Explicit shape (e.g., (3, 3) for a 3×3 matrix)
    • Strategy: A Hypothesis strategy that generates shapes
  • dtype (np.dtype | st.SearchStrategy | None): Data type of the array. Defaults to float32.
  • unit (str | apyu.UnitBase | st.SearchStrategy | None): Unit for the quantity. Can be:
    • None (default): Generates quantities with various common units
    • str: Specific unit string (e.g., "m", "km/s")
    • apyu.UnitBase: Specific unit object
    • Strategy: A Hypothesis strategy that generates units (e.g., from units())

Returns: unxt.Quantity

unitsystems(*units)

Generate random UnitSystem objects.

Parameters:

  • *units (str | apyu.UnitBase | st.SearchStrategy[apyu.UnitBase]): Variable number of unit specifications. Each can be:
    • str: Fixed unit string (e.g., "m", "kg")
    • apyu.UnitBase: Fixed unit object
    • Strategy: A Hypothesis strategy that generates units

Returns: unxt.AbstractUnitSystem

Type Strategy Registration

The package automatically registers type strategies for Hypothesis's st.from_type() function, enabling automatic strategy generation for unxt types:

from hypothesis import given, strategies as st

import unxt as u
import unxt_hypothesis as ust  # Import to register strategies


# Hypothesis automatically uses the registered strategies
@given(q=st.from_type(u.AbstractQuantity))
def test_quantity_via_from_type(q):
    """Test quantities generated via st.from_type()."""
    assert isinstance(q, u.AbstractQuantity)
    assert u.dimension_of(q) is not None


@given(q=st.from_type(u.Quantity))
def test_quantity_class_via_from_type(q):
    """Test Quantity instances generated via st.from_type()."""
    assert isinstance(q, u.Quantity)


@given(bq=st.from_type(u.quantity.BareQuantity))
def test_bare_quantity_via_from_type(bq):
    """Test BareQuantity instances generated via st.from_type()."""
    assert isinstance(bq, u.quantity.BareQuantity)


@given(sq=st.from_type(u.quantity.StaticQuantity))
def test_static_quantity_via_from_type(sq):
    """Test StaticQuantity instances generated via st.from_type()."""
    assert isinstance(sq, u.quantity.StaticQuantity)
    # StaticQuantity uses StaticValue wrapper
    assert isinstance(sq.value, u.quantity.StaticValue)


@given(a=st.from_type(u.Angle))
def test_angle_via_from_type(a):
    """Test angles generated via st.from_type()."""
    assert isinstance(a, u.Angle)
    assert u.dimension_of(a) == u.dimension("angle")


@given(usys=st.from_type(u.AbstractUnitSystem))
def test_unitsystem_via_from_type(usys):
    """Test unit systems generated via st.from_type()."""
    assert isinstance(usys, u.AbstractUnitSystem)

Registered Types

The following types are automatically registered:

  • u.AbstractQuantity → generates Quantity instances
  • u.Quantity → generates Quantity instances with dimension checking
  • u.quantity.BareQuantity → generates BareQuantity instances (no dimension checking)
  • u.quantity.StaticQuantity → generates StaticQuantity instances with StaticValue wrapper (for non-traced values)
  • u.Angle → generates Angle instances with angle dimension
  • u.AbstractUnitSystem → generates unit systems

This integration allows you to use type annotations directly in your tests without explicitly importing the strategy functions, making tests more concise and easier to read.

Examples

Generate quantities with specific shapes

from hypothesis import given, strategies as st

import unxt_hypothesis as ust


@given(q=ust.quantities(shape=(3, 3)))
def test_matrix_quantity(q):
    assert q.shape == (3, 3)


@given(q=ust.quantities(shape=()))
def test_scalar_quantity(q):
    assert q.ndim == 0

Generate quantities with specific dimensions

from hypothesis import given

import unxt as u
import unxt_hypothesis as ust


@given(q=ust.quantities(unit=ust.units("length")))
def test_length_quantity(q):
    assert u.dimension_of(q) == u.dimension("length")


@given(q=ust.quantities(unit=ust.units("energy")))
def test_energy_quantity(q):
    assert u.dimension_of(q) == u.dimension("energy")

Testing Unitful Functions

Here's a complete example of using these strategies to test a physics function:

import jax.numpy as jnp
from hypothesis import given

import unxt as u
import unxt_hypothesis as ust


def kinetic_energy(mass, velocity):
    """Calculate kinetic energy: KE = 0.5 * m * v^2"""
    return 0.5 * mass * velocity**2


@given(
    mass=ust.quantities(unit="kg", shape=()),
    velocity=ust.quantities(unit="m/s", shape=()),
)
def test_kinetic_energy_positive(mass, velocity):
    """Kinetic energy is always non-negative."""
    ke = kinetic_energy(mass, velocity)
    assert jnp.all(ke.value >= 0)
    # Check resulting unit is energy
    assert u.dimension_of(ke) == u.dimension("energy")


@given(
    mass=ust.quantities(unit="kg", shape=(10,)),
    velocity=ust.quantities(unit="m/s", shape=(10,)),
)
def test_kinetic_energy_vectorized(mass, velocity):
    """Kinetic energy works with arrays."""
    ke = kinetic_energy(mass, velocity)
    assert ke.shape == (10,)
    assert jnp.all(ke.value >= 0)

Combining Strategies

The strategies are designed to work together seamlessly:

from hypothesis import given, strategies as st

import unxt as u
import unxt_hypothesis as ust


# Create quantities with units from a unit strategy
@given(unit=ust.units("length"), q=ust.quantities(unit=ust.units("length")))
def test_consistent_length_units(unit, q):
    """Both unit and q have length dimension."""
    assert u.dimension_of(unit) == u.dimension("length")
    assert u.dimension_of(q) == u.dimension("length")


# Create unit systems with varying complexity
@given(
    sys=ust.unitsystems(
        ust.units("length", max_complexity=1),
        ust.units("time", max_complexity=1),
        ust.units("mass", max_complexity=1),
        "rad",
    )
)
def test_simple_unit_system(sys):
    """Generate systems with simple base units only."""
    assert len(sys) == 4

Documentation

For full documentation and advanced examples, see:

Contributing

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

Documentation

For comprehensive documentation, examples, and guides, see the unxt documentation.

License

BSD 3-Clause License. See LICENSE for details.

Contributing

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unxt_hypothesis-1.9.2.tar.gz (24.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unxt_hypothesis-1.9.2-py3-none-any.whl (12.2 kB view details)

Uploaded Python 3

File details

Details for the file unxt_hypothesis-1.9.2.tar.gz.

File metadata

  • Download URL: unxt_hypothesis-1.9.2.tar.gz
  • Upload date:
  • Size: 24.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for unxt_hypothesis-1.9.2.tar.gz
Algorithm Hash digest
SHA256 41a586b78a07c8f117020f581a08d692b5e64730a4972172800af8fac67ed24e
MD5 5e60cf05d3ebe1e1f057931e436805e8
BLAKE2b-256 fa328ad20570d410b95781882bdd41b315a3461ac319ff36e7981e35f185f99f

See more details on using hashes here.

Provenance

The following attestation bundles were made for unxt_hypothesis-1.9.2.tar.gz:

Publisher: cd-unxt-hypothesis.yml on GalacticDynamics/unxt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file unxt_hypothesis-1.9.2-py3-none-any.whl.

File metadata

File hashes

Hashes for unxt_hypothesis-1.9.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9e14dd55f62237a8a610622201ab99e416ea930c7c586f5a8fe866eb412b8352
MD5 9b9b97ed8b2383f99f81a7f797e4668b
BLAKE2b-256 8adcf47b37528bebf1ddc1cf2982ea4e006db1e1f9f8b1b0601bc224e4589e5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for unxt_hypothesis-1.9.2-py3-none-any.whl:

Publisher: cd-unxt-hypothesis.yml on GalacticDynamics/unxt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page