ndlike
NumPy arrays, JAX arrays, and PyTorch tensors provide similar primitives for
indexing, reshaping, stacking, and numerical operations. ndlike provides tools
to build wrappers around these types that behave like the underlying arrays,
but whose elements represent custom composite values—such as vectors or
distributions—instead of individual numbers.
Protocols and reusable base classes handle array interfaces and backend function dispatch. Protected axes distinguish collection dimensions from each element's internal dimensions, so indexing, reshaping, or stacking a collection preserves the structure of its elements.
Installation
Requires Python 3.12 or newer.
pip install ndlike
pip install 'ndlike[torch]'
pip install 'ndlike[jax]'
NumPy and flextype are core dependencies. Torch and JAX are optional and are never imported by the backend-independent modules. Import backend modules explicitly.
Array protocols and base classes
ndlike.array_like.ArrayLike describes indexing, shape, and metadata rather than
just convertibility to an array (as in numpy.typing.ArrayLike). It does not
require the full numerical Array API. ArrayLikeWithoutSize covers the shared
interface without NumPy/JAX's integer size property, since Torch uses a method.
Backend-specific APIs build on these protocols:
| Module | Protocol | Conversion helper | Conversion hook |
|---|---|---|---|
ndlike.array_like |
NumpyLike |
to_numpy_like |
__array_like__ |
ndlike.torch_like |
TorchLike |
to_torch_like |
__torch_like__ |
ndlike.jax_like |
JaxLike |
to_jax_like |
__jax_like__ |
Each module also provides matching Implementation and Convertible classes,
such as NumpyLikeImplementation and NumpyLikeConvertible.
Use the array protocols to type inputs, or subclass an implementation base to
reuse convenience methods while supplying your representation's metadata and
operation-dispatch hooks. NumPy uses __array_function__ / __array_ufunc__,
Torch uses __torch_function__, and ndlike supplies __jax_function__ for JAX.
Conversion helpers call the conversion hook when an input satisfies the matching
convertible protocol: the core array interface plus the hook, not the hook alone.
This lets custom types preserve their structure instead of becoming raw arrays.
Otherwise, the helpers fall back to numpy.asanyarray, torch.as_tensor, and
jax.numpy.asarray, respectively. NumPy retains __array_like__ for backward
compatibility and consistency with NumPy's __array__.
Protected axes
Protected-axis base classes give structured objects array-like behavior over
their batch dimensions while preserving trailing internal dimensions. For
example, a batch of six 3D vectors should have logical shape (6,), not (6, 3):
from dataclasses import dataclass
from typing import ClassVar
import numpy as np
from ndlike.protected_axis.numpy import NumpyAxisProtected
@dataclass
class Vectors(NumpyAxisProtected[np.ndarray]):
array: np.ndarray
protected_axes: ClassVar[dict[str, int]] = {"array": 1}
vectors = Vectors(np.ones((6, 3)))
assert vectors.shape == (6,)
assert vectors.protected_shape == (3,)
assert vectors[0].array.shape == (3,)
grid = vectors.reshape(2, 3)
assert grid.shape == (2, 3)
assert grid.array.shape == (2, 3, 3)
stacked = np.stack([vectors, vectors])
assert isinstance(stacked, Vectors)
assert stacked.shape == (2, 6)
protected_axes maps field names to the number of trailing axes to preserve.
Multiple fields can have different internal shapes while sharing the same batch
shape; indexing and supported shape operations update them together. Dataclasses
work out of the box; other classes can override with_protected_values to
reconstruct results.
Numerical operations are opt-in: use permitted_functions (for example,
{np.mean}) and, for NumPy ufuncs, permitted_ufuncs (for example,
{np.add: ["__call__", "reduce"]}). Supported reductions operate on batch axes,
leaving internal axes intact.
The corresponding backend classes are TorchAxisProtected in
ndlike.protected_axis.torch and JaxAxisProtected in
ndlike.protected_axis.jax.
JAX function dispatch
JAX has no native equivalent of NumPy's __array_function__. For custom objects,
use wrappers from ndlike.jax_functions, such as jax_reshape, jax_stack, and
jax_mean, instead of the corresponding jax.numpy functions. They dispatch to
__jax_function__ on custom types and call JAX normally for native arrays.
jax_function_dispatch lets you add the same dispatch behavior to your own
functions. JaxLikeImplementation also provides dataclass-based pytree support
for JAX transformations such as jax.jit and jax.vmap.
Development
uv sync --all-extras
uv run pytest
uv run prek install
uv run prek run --all-files
uv build
Dependency groups follow flextype: lint contains Ruff and ty, test contains
pytest, and dev includes both groups plus prek. Development Torch wheels use
the CPU index on Linux and Windows. Type checking requires both backend extras.
scripts/check_backend_naming.py enforces backend prefixes on definitions
(BKN001) and restricts runtime Torch/JAX imports to their respective
backend-prefixed modules (BKN002). Type-only imports are exempt. Intentional
exceptions use an explicit # noqa: BKN001 or # noqa: BKN002 on the opening line.
Metadata
Release files for ndlike 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ndlike-0.1.1.tar.gz | 49.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ndlike-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 105.0 kB
Release files / ndlike-0.1.1.tar.gz
| Download URL | ndlike-0.1.1.tar.gz |
|---|---|
| Size | 49.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c2bc1afac4e5b60a4cdaa76fa2e6e443c73d73f95e45da60e01c70f99fdb3eb9
|
|
BLAKE2b-256 checksum How to use checksums |
6a309570eb3bb7eb93b0c30286eee673a26c745136827cedef69c78c5821b838
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / ndlike-0.1.1-py3-none-any.whl
| Download URL | ndlike-0.1.1-py3-none-any.whl |
|---|---|
| Size | 55.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e37273e2857418a5d93f9577c9fd788c03d10c5f329b10a6ca9a3c8be599e1bd
|
|
BLAKE2b-256 checksum How to use checksums |
614bb244c5de15f4733dc681f69d2ea56ee2fe3ec7e45816943c11bfb9868061
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for ndlike 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ndlike-0.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.