Skip to main content

Async-first Python testing framework

Project description

Apte

CI codecov docs

Write your tests and your LLM evals in one async-first framework.

An eval is just a test that returns a value - scored, not asserted. Your evals get real fixtures, dependency injection and parallelism, and live right next to the tests they ship with. Python 3.10+, installs lean (Rich UI optional).


Why Apte?

Explicit Injection (IDE-Ready)

Ctrl+Click works. Your IDE knows every type. No guessing where fixtures come from.

def test_user(db: Annotated[Database, Use(database)]): ...

Native Async & Parallelism

Tests run as coroutines on a single event loop. No plugin needed.

apte run tests:session -n 10

Smart Tagging (Tag Propagation)

Tag a fixture once, every test using it inherits the tag automatically.

@fixture(tags=["database"])
def db(): ...

session.bind(db)

@session.test()
def test_users(repo: Annotated[Repo, Use(user_repo)]): ...  # Also tagged "database"
apte run tests:session --no-tag database  # Skips ALL tests touching DB

Infra vs Code Errors (Error ≠ Fail)

✗ test_create_user: AssertionError       # Your bug - TEST FAILED
⚠ test_with_db: [FIXTURE] ConnectionError  # Infra issue - SETUP ERROR

Typed Parameterization

CODES = ForEach([200, 201])

@session.test()
def test_status(code: Annotated[int, From(CODES)]): ...

Native LLM Evals

Score model outputs alongside your tests - same fixtures, same parallelism, same apte CLI. Cases get pass/fail + numeric metrics, persisted to JSONL for run-over-run comparison.

from typing import Annotated
from apte import ForEach, From, ApteSession
from apte.evals import EvalCase, EvalSuite
from apte.evals.evaluators import contains_keywords

session = ApteSession()
chatbot_suite = EvalSuite("chatbot")
session.add_suite(chatbot_suite)

cases = ForEach([
    EvalCase(name="capital_fr", inputs="Capital of France?", expected="Paris"),
])

@chatbot_suite.eval(evaluators=[contains_keywords(keywords=["paris"])])
async def chatbot(case: Annotated[EvalCase, From(cases)]) -> str:
    return await my_agent(case.inputs)  # your LLM call
apte eval evals.session:session   # runs are recorded to .apte/history.jsonl

See Evals docs for evaluators, judges, and scoring.


Quick Start

from apte import ApteSession

session = ApteSession()


def inc(x):
    return x + 1


@session.test()
def test_answer():
    assert inc(3) == 4
apte run test_sample:session

Installation

Apte is not yet on PyPI. Install directly from GitHub:

# With uv (recommended)
uv add git+https://github.com/renaudcepre/apte.git

# With pip
pip install git+https://github.com/renaudcepre/apte.git

CLI

apte run module:session                    # Run tests
apte run module:session -n 4               # Parallel (4 workers)
apte run module:session --lf               # Re-run failed tests only
apte run module:session --collect-only     # List tests without running
apte run module:session --cache-clear      # Clear cache before run
apte run module:session --app-dir src      # Look for module in src/
apte run module:session --ctrf-output r.json  # CTRF report for CI/CD

apte eval module:session                   # Run LLM evals
apte eval module:session --tag safety      # Filter by case tag
apte eval module:session --last-failed     # Re-run failed cases only

Features

  • Explicit DI - No guessing which fixture you're using
  • Async native - No plugin needed, just async def
  • Parallel execution - Built-in with -n 4
  • Scoped fixtures - SESSION, SUITE, TEST
  • Mix sync/async - They just work together
  • Factory fixtures - Callables to create instances on-demand
  • Plugin system - Custom reporters, filters
  • Last-failed mode - Re-run only failed tests with --lf
  • CTRF reports - Standardized JSON for CI/CD integration
  • Native LLM evals - Scored cases, JSONL history, apte eval (see evals docs)

Why Not pytest?

pytest Apte
Fixtures Implicit (by name) Explicit (Use(fixture))
Params Hidden in fixture Visible in test (From() + factory)
Async Plugin required Native
Parallel Plugin required Built-in
Cycles Runtime error Prevented at registration
Evals External (deepeval, pydantic-…) Native (apte eval, JSONL history)

pytest has a large ecosystem and extensive community. Apte is an alternative if you prefer FastAPI-style explicit dependencies and native async in your tests.

Documentation

Full API reference, guides, and examples: renaudcepre.github.io/apte

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apte-0.3.0.tar.gz (110.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apte-0.3.0-py3-none-any.whl (131.9 kB view details)

Uploaded Python 3

File details

Details for the file apte-0.3.0.tar.gz.

File metadata

  • Download URL: apte-0.3.0.tar.gz
  • Upload date:
  • Size: 110.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apte-0.3.0.tar.gz
Algorithm Hash digest
SHA256 c48a5015b0693fc764d4b6a2aa57e07202385ea214ef53cbf86450e2ee46a068
MD5 40c4f0e11f98ddd9142064a3966aaa2a
BLAKE2b-256 45e8bc66519a592f506937f5559deb3cae2c57cc6832e40eb3a0d7d43b902842

See more details on using hashes here.

Provenance

The following attestation bundles were made for apte-0.3.0.tar.gz:

Publisher: publish.yml on renaudcepre/apte

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apte-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: apte-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 131.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apte-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2000993adc018efd5111d1b10f48b4f944aad772fd0b2182d0b932f7bd344883
MD5 c036bcf41fae75ca1bbc9b2fbce06130
BLAKE2b-256 fc0a6dacc6afa0256f881824523effd0727caba12bf0204ea9d0e406cd9e1253

See more details on using hashes here.

Provenance

The following attestation bundles were made for apte-0.3.0-py3-none-any.whl:

Publisher: publish.yml on renaudcepre/apte

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page