Skip to main content

tempest-cli

PyPI Python License: MIT

Documentação: Português (BR) · English (US)

One command for the quality gate of any Python project — ruff + mypy + pytest, with a typing-strictness dial that lives in your pyproject.toml instead of in four different Makefile targets.

Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a library, a script. It brings ruff along, so the gate runs the moment you install it; typer is the only other runtime dependency.

uv add --dev tempest-cli

tempest-cli check          # lint + fmt-check + type + test, in order, stops at the first failure
tempest-cli fix            # every ruff autofix, then format
tempest-cli type -s strict # override the configured strictness for one run

tc check                   # `tc` is the short alias for the same program

Why it exists

The four commands are always the same, and every project rewrites them slightly differently — a Makefile here, a tox.ini there, a CI job that drifts from what runs locally. tempest-cli check is the same gate on your machine and in CI, and --strictness makes "how much typing do we enforce" a value in pyproject.toml rather than a flag someone remembered to pass.

Commands

Command Runs
tempest-cli lint ruff check
tempest-cli fix ruff check --fix-only, ruff format, wraps long comments and splits long strings the formatter leaves alone, then a final ruff check that explains what is left (--unsafe for the risky autofixes)
tempest-cli format ruff format (writes)
tempest-cli fmt-check ruff format --check (read-only)
tempest-cli type mypy
tempest-cli test pytest (--fast spreads it across cores with pytest-xdist: -n auto -p no:cacheprovider, -w N to choose)
tempest-cli check all four, in order, stopping at the first failure (--fast runs the test step in parallel; a host CLI can add steps between mypy and pytest)
tempest-cli pr-prompt builds the prompt that makes an AI write this branch's PR description

Every command takes an optional path (tempest-cli lint src/) and returns the underlying tool's exit code, so CI reads it exactly as it would read ruff directly.

Typing strictness

[tool.tempest]
typing_strictness = "strict"   # lenient | standard | strict

The level adds flags on top of your own [tool.ruff] / [tool.mypy] — it never relaxes what you already configured:

Level ruff (extra ANN rules) mypy
lenient none none
standard ANN001, ANN201, ANN202, ANN205, ANN206 --disallow-untyped-defs --disallow-incomplete-defs
strict the above plus ANN204 --strict

ANN401 is never enabled at any level: Any is a legitimate annotation. The levels enforce that things are annotated, never that they avoid Any.

Override per run with --strictness / -s. Absent config means standard.

Everything that is not typing — silencing an untyped library, skipping generated code, dropping a rule that does not fit your framework — is ordinary [tool.ruff] / [tool.mypy] configuration. The recipes, including the one that takes a legacy Django project to a green gate, are in Tuning the rules (EN).

PR descriptions from the branch itself

tempest-cli pr-prompt | claude -p
tempest-cli pr-prompt develop --lang en --out pr_prompt.txt

The prompt carries the repository's own pull-request template (or a bundled PT-BR / EN-US default), the rules that stop a model from handing back the template with its placeholders intact, and the branch context: commit subjects, changed files, and a bounded excerpt of each patch.

Diffs are read as base...head — the merge-base diff the forge shows — so commits that landed on the base after the branch started are not attributed to it. Whatever the bounds leave out is stated inside the prompt, so a partial diff reads as partial.

Use it as a library

from tempest_cli import load_tempest_config, run_full_check

config = load_tempest_config()
exit_code = run_full_check(".", config=config)

And to expose the same gate from your own CLI, without copying command bodies:

import typer

from tempest_cli.main import register_commands

cli: typer.Typer = typer.Typer(name="mytool")
register_commands(cli)

A framework that wants its own rules in check passes them as CheckSteps — they run after mypy and before pytest, and the first non-zero exit code stops the gate:

import typer

from tempest_cli import CheckStep
from tempest_cli.main import register_commands


def layers(target: str) -> int:
    """Return 0 when every module under ``target`` follows the layering."""
    return 0


cli: typer.Typer = typer.Typer(name="mytool")
register_commands(cli, extra_steps=[CheckStep(name="layers", run=layers)])

run_full_check(".", extra_steps=[...]) takes the same list.

Where the tools come from

ruff comes with the package — six of the eight commands are ruff, so lint, fix, format and fmt-check work straight after uv add --dev tempest-cli, with nothing else to install. It is a static binary wheel with no Python dependencies of its own, so nothing of its propagates into your resolution.

mypy and pytest are deliberately left to you — a mypy bump changes which errors your code reports, and pytest has to match your plugins and your suite. Add them yourself, or take the bundle:

uv add --dev "tempest-cli[tools]"   # mypy + pytest + pytest-xdist

pytest-xdist is what test --fast runs the suite with; its requires-dist (execnet>=2.1, pytest>=7.0.0) carries no upper bound.

Whatever you pin wins over the bundled ruff. The lookup runs in this order:

  1. the project's environment — $VIRTUAL_ENV, then the nearest .venv up the tree;
  2. the environment tempest-cli itself runs from (where the bundled ruff lives);
  3. PATH, skipping a pyenv/asdf shim that dispatches nowhere (the one that answers pyenv: ruff: command not found);
  4. uv run --with <tool> <tool>, when uv is available.

Relationship with tempest-fastapi-sdk

This package was extracted from tempest-fastapi-sdk, where the same gate shipped as tempest check. Getting it meant installing FastAPI, SQLAlchemy, Alembic and Pydantic — 38.7 MB of dependencies and roughly 0.5 s of import time per invocation, for four commands that never touch any of it.

tempest check keeps working: the SDK depends on this package and registers the same commands. Both stay in sync because there is now one implementation.

License

MIT — see LICENSE.

Metadata

Release files for tempest-cli 0.5.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 tempest-cli 0.5.1
File Size Uploaded Provenance
tempest_cli-0.5.1.tar.gz 168.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for tempest-cli 0.5.1
File Interpreter ABI Platform
tempest_cli-0.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 211.9 kB

Release files / tempest_cli-0.5.1.tar.gz

Download URL tempest_cli-0.5.1.tar.gz
Size 168.6 kB
Tags Source
SHA-256 checksum
How to use checksums
44ed67f2d8862bd8078b119360e8a8ae19c4c4a24c2f6d4691b6acc16d461ac2
BLAKE2b-256 checksum
How to use checksums
8700699124dab2bbfe7bbd247be325e5632902816ad3347b65637434b836ffed
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 16, 2026.

Transparency log

Release files / tempest_cli-0.5.1-py3-none-any.whl

Download URL tempest_cli-0.5.1-py3-none-any.whl
Size 43.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
18050e4729a1ecb7b5067ede873deb0ac315620bf4419587da673b605822405d
BLAKE2b-256 checksum
How to use checksums
63eb826683aff6e4ba7363d17e1df869548339749c21e7c4c6d90119fd584c3f
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 16, 2026.

Transparency log

Security for tempest-cli 0.5.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 tempest_cli-0.5.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 16, 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