Metadata-Version: 2.5
Name: tempest-cli
Version: 0.2.0
Summary: Framework-agnostic quality gate for Python projects: ruff + mypy + pytest behind one command, with a typing-strictness dial and a PR-description prompt generator.
Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-cli
Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-cli
Project-URL: Issues, https://github.com/mauriciobenjamin700/tempest-cli/issues
Project-URL: Documentation, https://mauriciobenjamin700.github.io/tempest-cli/
Author-email: Mauricio Benjamin <mauricio.benjamin@reloverelations.com>
License: MIT
License-File: LICENSE
Keywords: cli,lint,mypy,pytest,quality,ruff,typing
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: typer>=0.12.0
Provides-Extra: tools
Requires-Dist: mypy>=1.13.0; extra == 'tools'
Requires-Dist: pytest>=8.3.3; extra == 'tools'
Requires-Dist: ruff>=0.8.0; extra == 'tools'
Description-Content-Type: text/markdown

# tempest-cli

[![PyPI](https://img.shields.io/pypi/v/tempest-cli.svg)](https://pypi.org/project/tempest-cli/)
[![Python](https://img.shields.io/pypi/pyversions/tempest-cli.svg)](https://pypi.org/project/tempest-cli/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**Documentação: [Português (BR)](https://mauriciobenjamin700.github.io/tempest-cli/) · [English (US)](https://mauriciobenjamin700.github.io/tempest-cli/en/)**

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. The only runtime dependency is `typer`.

```bash
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` then `ruff format` (`--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` |
| `tempest-cli check` | all four, in order, stopping at the first failure |
| `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

```toml
[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`.

## PR descriptions from the branch itself

```bash
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

```python
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:

```python
import typer

from tempest_cli.main import register_commands

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

## Installing the tools

`tempest-cli` shells out to whatever `ruff`, `mypy` and `pytest` it
finds — it does not pin them, so your project chooses the versions. The
lookup runs in this order:

1. the environments of the run — the interpreter's own directory, then
   `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
2. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
   that answers `pyenv: ruff: command not found`);
3. `uv run --with <tool> <tool>`, when `uv` is available.

To install the three alongside it:

```bash
uv add --dev "tempest-cli[tools]"
```

## Relationship with tempest-fastapi-sdk

This package was extracted from
[`tempest-fastapi-sdk`](https://github.com/mauriciobenjamin700/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](LICENSE).
