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 retryable status (429 or 5xx) 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 1000 pages, and diagnoses a repository-scoped 400 as "missing or not raw". With directory, it scopes the walk the way a directory listing does: the search asks with q=<directory>/ and the client keeps the paths under that whole-segment prefix, so the server's loose q can only widen the pages, never the answer.
  • 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 any retryable status, 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.22.1

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.22.1
File Size Uploaded Provenance
nexus_raw-0.22.1.tar.gz 20.3 kB With provenance Details

Built distribution (wheel)

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

Total release size: 32.1 kB

Release files / nexus_raw-0.22.1.tar.gz

Download URL nexus_raw-0.22.1.tar.gz
Size 20.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a0faef45c34373de90a71a73d405715996fc30bf3bd2cec4a7d962e0aa459392
BLAKE2b-256 checksum
How to use checksums
4094778858bf6bce0c95f0dca4e594e89a1103f2805fbb0e31017a726e55dd44
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 21, 2026.

Transparency log

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

Download URL nexus_raw-0.22.1-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0259d5db945637c2a734de1510127c720d9dc8fe912727769f0069bb4ce780a4
BLAKE2b-256 checksum
How to use checksums
49476ee9b1cf6ae3d0eb89035d64c048e385070ad71aeba3bd92f6eefc1dd515
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 21, 2026.

Transparency log

Security for nexus-raw 0.22.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.

Select from 2 files

Attestation for nexus_raw-0.22.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 21, 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.

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