Skip to main content

The Python reference client

nxr.py is the second client of the protocol: a minimal reference implementation on the Python standard library, python3.10+, nothing to install. It proves the claim the project makes about its own wire format: the protocol is implementable from scratch over bare HTTP, with http.client for the wire and hashlib for the digests. The authoritative text it follows lives in crates/nexus-raw-core/src/protocol.md.

What it covers

Six verbs over the store: get, put, head, sha, ls, channel get/set. Deletion is deliberately absent. The interesting rules are all client-side and all present:

  • put writes the bytes, then the .sha256 marker of the same name, strictly in that order. A crash between the two leaves a markerless object, which every reader refuses. The marker's name field is the percent-decoded final path segment, refused when it is empty, ./.., out of grammar, or .sha256-suffixed.
  • get downloads the bytes and the sibling and refuses unless the digest matches. Completion is bytes plus the sibling: anything less is an exception, never a silent return.
  • A 2xx without Content-Length is present-but-unverifiable, never absent (head reports length=None).
  • 401/403 fail fast with no retries. 5xx and transport failures retry with backoff (4 attempts, 0.5s x 2^n, capped, jittered). A 429 honors its Retry-After pause, clamped to 1..=60 seconds, in place of the backoff.
  • Redirects are never followed: a 301 surfaces as HttpError with the status.
  • The per-operation socket timeout is the stall watchdog: a frozen server aborts the attempt, a slow-but-moving transfer never trips it.
  • ls walks /service/rest/v1/search/assets with continuation tokens, capped at 100 pages, and diagnoses a repository-scoped 400 as "missing or not raw".
  • Markers parse strictly (sha256sum -c shape: LF only, exactly two spaces, 64 lowercase hex, trailing newline), because a loose parse would bless foreign markers. The reference decodes marker bytes as ASCII, one notch stricter than the Rust core's lossy UTF-8: harmless today, since both sides compare digests only, but a porter may loosen it the same way.

Every error is an exception carrying .status (the HTTP status, None for pure transport failures) and .hint (the action line a CLI would print). Every attempt lands in .requests as a (method, path) pair, the record the conformance suite asserts on.

Run the conformance suite

cargo build -q -p mock-nexus
python3 -m unittest discover clients/python

The suite spawns mock-nexus itself, one process per test on a free port, and reads the scenario list live from mock-nexus --print-scenarios. To point it at another binary, set MOCK_NEXUS_BIN to the path.

The scenario contract and the skip table

The mock's scenario list is the conformance contract, and the suite refuses to drift from it: test_unit_every_scenario_is_classified requires every listed scenario to have a test method named test_<scenario with dashes as underscores> or a documented row in SKIP, in both directions. A scenario added to crates/mock-nexus/src/scenario.rs fails this suite until it is classified, which is the point.

The current skip rows, with the reasons:

Scenario Reason
doc-drift The drift toggle is a library-only knob (MockNexus::enable_drift), so the binary serves plain storage. the client-side half, version.json being an ordinary name, is pinned under atomic
no-service The scenario only breaks /service/rest/v1/repositories, and the client has no service-repos surface
readonly The scenario only answers 403 to DELETE, and the client implements no delete

Lint, types and the suite

The client is gated like the rest of the repository. just check runs just test-python, which builds the mock binary and runs the suite below, and the prek hooks run ruff (lint plus format check) and ty over the module.

Ruff's width is 120 and E501 is off on purpose: the repository mandates unwrapped sentences in comments and docstrings, and a line-length complaint would fight that rule on exactly those lines. The configuration lives in pyproject.toml. Only the shipped module nxr.py is type-checked, the suite is lint-checked, so a loose fixture in a test never blocks a commit.

Porting note

What a real integrator must implement, at minimum, beyond the verbs:

  1. Basic auth attached to every request, resolved once per invocation.
  2. The retry classification: retry transport failures and 5xx with bounded backoff, honor Retry-After on 429, never retry 401/403, never follow redirects.
  3. An attempt-level stall bound (a read/write timeout), because a server can hold a connection forever.
  4. The marker order on upload, the digest check on download, and the strict marker parse.
  5. The lengthless-answer rule: a 2xx without Content-Length is unverifiable, never empty.
  6. Accept-Encoding: identity on every request, unless the client also implements the zstd GET decoding, so digests always describe the stored bytes.

Deliberate simplifications of this reference, safe to outgrow: bodies are held in memory (no streaming, no Range resume, no part files), one connection per attempt (no keep-alive), and TLS is whatever the runtime verifies by default (the protocol's --tls-insecure escape hatch has no equivalent here).

Metadata

Release files for nexus-raw 0.19.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nexus-raw 0.19.0
File Size Uploaded Provenance
nexus_raw-0.19.0.tar.gz 19.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nexus-raw 0.19.0
File Interpreter ABI Platform
nexus_raw-0.19.0-py3-none-any.whl Python 3 none any Details

Total release size: 30.3 kB

Release files / nexus_raw-0.19.0.tar.gz

Download URL nexus_raw-0.19.0.tar.gz
Size 19.2 kB
Tags Source
SHA-256 checksum
How to use checksums
39df31298bd66f2e3af35f6bcba35a4b3fa5a43b858267ade9b0e5802f8b2951
BLAKE2b-256 checksum
How to use checksums
55077e37460bfd33b41e75b00a0a56e90018cb3b6727a5d5760697c4c3b1c407
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 18, 2026.

Transparency log

Release files / nexus_raw-0.19.0-py3-none-any.whl

Download URL nexus_raw-0.19.0-py3-none-any.whl
Size 11.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d98595ace7c941dd50d138e8ef26c5a7a54f2623da38a5c47a21cc53ca8b1c79
BLAKE2b-256 checksum
How to use checksums
93793f640eef57ce77ddaa20b725b297e72b69b614fb5be8e07418ee704e6e20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 18, 2026.

Transparency log

Security for nexus-raw 0.19.0

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.

Select from 2 files

Attestation for nexus_raw-0.19.0.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 18, 2026.

Transparency log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page