Commands¶
Eight commands. All take an optional path and return the underlying tool's exit code.
| Command | Runs |
|---|---|
lint |
ruff check |
fix |
ruff check --fix then ruff format |
format |
ruff format (writes) |
fmt-check |
ruff format --check (read-only) |
type |
mypy |
test |
pytest |
check |
the four above, in order, stopping at the first failure |
pr-prompt |
builds the PR-description prompt — its own page |
tc is the short form
The package installs tempest-cli and tc pointing at the same
program. The examples use the long name; tc check, tc fix and
tc type -s strict work exactly the same.
The full gate¶
tempest-cli check # the whole project
tempest-cli check src/ # a single path
tempest-cli check -s strict # with raised typing strictness for this run
The order is deliberate: lint → formatting → types → tests. What fails fastest and is cheapest to fix comes first, and the run stops at the first failure — there is no point running the whole suite when the imports are unsorted.
Fixing what can be fixed¶
tempest-cli fix # safe autofixes + formatting
tempest-cli fix --unsafe # also ruff's risky autofixes
fix makes two passes: ruff check --fix (sorts and dedupes imports,
drops unused ones, normalizes quotes) and then ruff format
(indentation, line length, blank lines).
--unsafe can change behavior
Ruff's "unsafe" autofixes are the ones that may alter semantics.
They are off by default. Turned them on? Read the git diff before
committing.
One at a time¶
test forwards the path to pytest as a filter; with no argument it runs
the whole suite.
The suite in parallel: --fast¶
A suite whose tests are already isolated (a database per test, no global
state) pays the serial time and buys nothing for it. --fast spreads the
suite across the cores with
pytest-xdist:
tempest-cli test --fast # -n auto: one worker per core
tempest-cli test --fast -w 4 # four workers
tempest-cli test tests/unit --fast # the target is still forwarded
tempest-cli check --fast # the full gate, with the test step in parallel
Underneath it becomes pytest -n <workers> -p no:cacheprovider [target].
-p no:cacheprovider is there because several workers writing
.pytest_cache at once is a race that buys nothing — and that cache is
what --lf / --ff read, so those two remain a serial-run affair.
--workers (-w) takes what pytest -n takes: an integer, auto (the
default) or logical. Without --fast it is a usage error (exit 2)
instead of being silently ignored.
auto counts physical cores when psutil is installed
pytest-xdist decides: with psutil importable, auto is the number of
physical cores; without it, the number of logical CPUs. On a machine
with 6 cores and 12 threads, with psutil in the environment, auto
started created: 6/6 workers. Want the 12 threads? -w logical or
-w 12.
Why a flag, not tempest-cli test fast
test already takes a positional path. test fast keeps meaning
"run pytest on the fast/ folder" — a subcommand by that name would
break anyone who has one.
Without pytest-xdist¶
Before running anything, the CLI asks the very interpreter that will
run pytest whether it can import xdist — not the CLI's own
interpreter, which under uv tool install or pipx lives in a different
environment. When it is missing, the message names what to install and
the exit code is 127, with no traceback:
$ tempest-cli test --fast
error: --fast needs pytest-xdist, which is not installed in the environment pytest runs in (.venv/bin/pytest). Install it with 'uv add --dev pytest-xdist' — or a bundle that carries it, 'uv add --dev "tempest-cli[tools]"' or 'uv add --dev "tempest-fastapi-sdk[tests]"' — and retry, or drop --fast to run the suite serially.
$ echo $?
127
Under check --fast the check happens before the first step: there
is no point waiting for lint and mypy to finish to learn the tests will
not run.
A test that fails only in parallel¶
Parallelism exposes tests that depend on order or on an idle machine:
two tests writing the same file, the same port, a module-level global, a
fixed sleep waiting for something that takes longer once every core is
busy. Before treating the failure as a regression, run the test alone
and serially:
- It passes alone: the defect is the test's isolation, not the change
under review. Fix the test (a file under
tmp_path, a free port, wait on a condition instead of asleep). - It fails alone too: it is a real regression.
What each returns¶
The exit code is the tool's own, untranslated:
There is exactly one code of its own: 127, when the tool is in none
of the places the CLI looks — the run's environment, PATH, uv run
--with — and the message then names what was missing and how to install
it. The lookup order is in
Installation.
The same 127 comes out of --fast when pytest-xdist is not in pytest's
environment.
Recap¶
checkis lint + fmt-check + type + test, in order, stopping at the first failure.fixis the pass that repairs;--unsafeonly when you will review.test --fast/check --fastrun the suite with pytest-xdist (-n auto,-w Nto choose); a test that fails only in parallel is checked by running it alone.- Exit codes are the tools'; 127 means a missing tool (or the
pytest-xdist
--fastneeds).