ADR-029: hurray-python is interchange-first — drop the Array API conformance claim
Status
Proposed (2026-08-06)
Supersedes ADR-022 (hurray-python Runtime Compliance Modes).
Context
hurray-python currently declares itself a strict reference implementation of the
Python Array API Standard for Tier 1 element types (see docs/impl/python-bindings.md
and ADR-022). A review of the actual surface and of the standard's conformance model
shows this claim is not tenable and does not serve the format's purpose:
-
The claim is unmet.
hurray-pythonimplements the Array API's creation and inspection surface (and returns thehurraymodule from__array_namespace__advertising version2025.12), but implements none of the mandatory compute core — no elementwise functions, reductions, manipulation, linear algebra, searching/sorting/set functions, indexing (__getitem__), or operator dunders. A consumer that obtains the namespace via__array_namespace__()and calls, e.g.,xp.reshape,xp.sum,xp.matmul, or usesx[0], fails. -
Partial implementation is only sanctioned along designated seams. The standard permits omitting the optional extensions (
linalg,fft— "Each array library supporting this standard may, but is not required to, implement an extension") and negotiating capabilities/dtypes/devices (__array_namespace_info__().capabilities()). It does not sanction dropping the mandatory core while still presenting a conforming namespace. Conformance is defined operationally by thearray-api-testssuite, which exercises the full specified surface. -
Exposing
__array_namespace__without the core is actively harmful. Array-agnostic consumers (scikit-learn, SciPy's array-api support, einops, …) treat__array_namespace__as the promise that the full core exists; ahurray.Tensorbreaks them at runtime rather than being cleanly rejected. -
Compute is not hurray's purpose.
hurray-pythonis the Python face of the Hurray interchange format — a codec and zero-copy bridge (produce / consume / hand off), in the same spirit as the Python packages of other data formats. It is not, and should not become, a numerical library. Numerical work belongs to the frameworks the buffer is handed to (NumPy, PyTorch, JAX, …). -
DLPack is not the Array API. DLPack is an independent, header-only ABI + PyCapsule protocol that the Array API merely adopts.
from_dlpackworks on any object exposing__dlpack__without requiring__array_namespace__. The valuable zero-copy interop hook and the conformance claim were never coupled; dropping the claim does not cost us DLPack reach. -
The runtime modes exist only to serve the claim. ADR-022's strict/relaxed modes (
set_strict/is_strict/strict/relaxed,modes.rs) exist for the sole purpose of gating__array_namespace__visibility by dtype tier (Tier 1 vs Tier 2 / quantized). With the claim removed, they gate nothing.
Decision
hurray-python is positioned as interchange-first: a codec and zero-copy bridge for
the Hurray format, not an Array API implementation.
-
Drop the Array API conformance claim.
hurray-pythonMUST NOT describe itself as an Array API implementation, reference implementation, or conforming namespace. -
Remove
__array_namespace__.hurray.TensorMUST NOT implement__array_namespace__(for any dtype tier). Thehurraymodule is not an Array API namespace. -
Remove the runtime compliance modes.
set_strict,is_strict,strict,relaxed,StrictCtx,RelaxedCtx, and the_strict_modecarrier are removed. ADR-022 is superseded. (Pre-1.0, no compatibility guarantee applies; seedocs/spec/versioning.md.) -
Keep the interchange and producer/consumer surface, which never depended on the claim:
- Zero-copy interop protocols:
__dlpack__/__dlpack_device__,__array__/__array_interface__, and the native__hurray_buffer__/from_hurray_buffer. - Structural/inspection surface on
Tensor:shape,dtype,device,ndim,size,T. - Construction and ingest:
zeros/ones/full/empty(+_like),arange/linspace/eye,asarray,from_dlpack,from_numpy,from_torch,to_torch,from_scipy,save/load. These are framed as standalone interop protocols, not as Array API surface.
- Zero-copy interop protocols:
-
Dtype identity. Tier 1 and Tier 2 / quantized dtypes remain first-class
hurray.dtype.*objects. They are no longer described in terms of "Array API dtype" mapping; the NumPy/DLPack dtype correspondence is documented purely as an interop detail (what a given Hurray type becomes when handed to NumPy/PyTorch, and which types cannot cross a given bridge — e.g.boolover DLPack). -
Validation. The conformance anchor for
hurray-pythonis the shared golden test-vector corpus (conformance/vectors/, cross-checked Rust ↔ Python) plus the binding's own unit/integration tests.array-api-testsis not used — it targets a whole conforming namespace and presupposes the compute core, which is the wrong shape for a producer/consumer-only surface.
Consequences
Positive
- The binding's advertised behaviour matches its actual behaviour; no consumer is
misled by
__array_namespace__. - Smaller, more coherent surface; the modes machinery and its thread-safety caveats disappear.
- DLPack /
__array__reach to NumPy/PyTorch/JAX/CuPy is fully retained. - Positioning is honest and defensible: "Array-API-interoperable (via DLPack), not Array-API-implementing."
Negative / cost
- User-facing API removal:
__array_namespace__and theset_strict/relaxedfamily are gone. Acceptable pre-1.0 (no compatibility guarantee), but must be called out in the changelog. - A consumer that wants an Array API namespace from Hurray data must first hand the
buffer to a real backend (zero-copy), e.g.
xp = array_namespace(np.from_dlpack(t)). This is documented as the recommended pattern.
Follow-up work (sequenced; each user-approved)
- This ADR.
- Spec / impl docs:
docs/impl/python-bindings.md(rewrite the normative Array API sections),docs/impl/README.md,docs/spec/element-types.mdanddocs/spec/README.md(reframe Tier-1 "Array API dtype" language as interop),docs/SUMMARY.md. - Code: remove
__array_namespace__andmodes.rs; keep interop; drop dependent tests. - Cookbook / examples: retire or rewrite
docs/cookbook/hurray-python-array-api.mdanddocs/cookbook/hurray-python-runtime-modes.md, and theexamples/array_api.pyexample; refreshhurray-python/COMPAT-MATRIX.md.
Notes (non-normative)
The docs/impl/python-bindings.md Rationale section (added 2026-08-06) already
states the interchange-first motivation; this ADR makes it normative and reconciles the
surrounding requirements.