Skip to main content

nimax

CI codecov PyPI

Record and replay niquests HTTP and WebSocket interactions in pytest.

nimax is a VCR-style cassette library built natively for niquests — supporting lazy responses, multiplexed connections, AsyncSession, and WebSockets. It is to niquests what betamax is to requests.

Installation

pip install nimax

Quick start

Automatic fixture

nimax registers a nimax_session pytest fixture automatically. Use it instead of niquests.Session() in your tests:

def test_my_api(nimax_session):
    resp = nimax_session.get("https://api.example.com/users")
    assert resp.status_code == 200

On the first run nimax records the real HTTP response to a cassette file under cassettes/<test_module>/<test_name>.json. Subsequent runs replay from the cassette — no network required.

Async sessions

import pytest
import niquests


async def test_async(nimax_session):
    async with niquests.AsyncSession() as session:
        with NimaxRecorder(session).use_cassette("my_cassette.json"):
            resp = await session.get("https://api.example.com/data")
            assert resp.status_code == 200

Programmatic API

import niquests
from nimax import NimaxRecorder, RecordMode


def test_programmatic(tmp_path):
    session = niquests.Session()
    cassette_path = tmp_path / "my_cassette.json"
    with NimaxRecorder(session).use_cassette(cassette_path, record_mode=RecordMode.ONCE):
        resp = session.get("https://api.example.com/users")
        assert resp.status_code == 200

Record modes

Mode Behaviour
once Record on first run, replay on subsequent runs (default)
none Never record — raise an error if no matching interaction exists
new_episodes Replay existing interactions; record any unmatched requests
all Always record, overwriting the cassette each run

WebSocket support

WebSocket connections opened through a cassette-backed session are recorded and replayed automatically, alongside HTTP interactions, in the same cassette file:

def test_ws_echo(nimax_session):
    resp = nimax_session.get("wss://echo.example.com")
    resp.extension.send_payload('{"id": "1", "op": "ping"}')
    reply = resp.extension.next_payload()

On replay, a recv frame only releases once the real send_payload() call it depends on has actually happened — matching how a real socket can't deliver a response before its triggering request went out. By default this is tracked by position (send count) in the recorded log, which is correct as long as your live send order doesn't diverge from the recorded order.

Correlating responses by id

If your protocol embeds a correlation id in its messages (e.g. JSON-RPC-style {"id": ..., ...}) and you dispatch responses from a background reader task — so concurrent, in-flight requests can legitimately resolve out of order — pass ws_id_extractor to correlate replay by that id instead of by position:

with NimaxRecorder(session).use_cassette("my_cassette.json", ws_id_extractor="id"):
    ...

ws_id_extractor accepts:

  • A dotted JSON path string, e.g. "id" or "params.id" for a nested field.
  • A callable (payload: str | bytes) -> Any | None for anything else (non-JSON protocols, custom shapes).

A message whose id doesn't resolve (e.g. valid JSON with no id field) falls back to the position-based gate. A payload the extractor can't parse at all (e.g. malformed JSON when JSON was expected) raises — that means the extractor doesn't match the actual protocol, which is worth surfacing rather than silently ignoring.

With the automatic nimax_session/nimax_async_session fixtures, set a dotted-path string project-wide via [tool.nimax] in pyproject.toml:

[tool.nimax]
ws_id_extractor = "id"

A callable can't live in static config, so to use one with the automatic fixtures, override the nimax_ws_id_extractor fixture in your own conftest.py:

import pytest


@pytest.fixture
def nimax_ws_id_extractor():
    return my_custom_extractor

Placeholders

Scrub sensitive values (tokens, API keys) from cassettes before they are written:

from nimax import Placeholder

recorder = NimaxRecorder(
    session,
    placeholders=[
        Placeholder(placeholder="<AUTH_TOKEN>", replace="Bearer secret123"),
    ],
)

Custom matchers and serializers

from nimax import BaseMatcher, NimaxRecorder


class BodyMatcher(BaseMatcher):
    name = "body"

    def match(self, recorded: dict, live: object) -> bool:
        return recorded.get("body") == live.body  # type: ignore[union-attr]


NimaxRecorder.register_matcher(BodyMatcher)

YAML cassettes are supported out of the box — use a .yaml extension for the cassette path.

Requirements

  • Python ≥ 3.11
  • niquests ≥ 3
  • pytest ≥ 8
  • PyYAML ≥ 6

License

MIT

Metadata

Release files for nimax 1.1.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 nimax 1.1.1
File Size Uploaded
nimax-1.1.1.tar.gz 30.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nimax 1.1.1
File Interpreter ABI Platform
nimax-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 51.5 kB

Release files / nimax-1.1.1.tar.gz

Download URL nimax-1.1.1.tar.gz
Size 30.7 kB
Tags Source
SHA-256 checksum
How to use checksums
dfea909da0cb3b3c068f25a2d3d9f10a15850dd19150bd4027c5b00aaf24ef23
BLAKE2b-256 checksum
How to use checksums
7a8f71abd473081fa4a00009018a6bc0dd6e1ad94b7cf8fffa6acd325f8f400d
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 Sep 16, 2026.

Transparency log

Release files / nimax-1.1.1-py3-none-any.whl

Download URL nimax-1.1.1-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d36f814edb46d81922fe1640e0293e0faee7a7f3ef628b4fb675adb54e1c7d5b
BLAKE2b-256 checksum
How to use checksums
1a4120c497a146e71d2b5d9dba64474a5a7c6fb502bfb44cc9cfa0bbe49062c3
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 Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 release files

1.1.0

2 release files

1.0.0

2 release files

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