tempest-cli 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/CHANGELOG.md +23 -0
  2. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/PKG-INFO +24 -14
  3. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/README.md +22 -12
  4. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/changelog.en.md +17 -0
  5. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/changelog.md +17 -0
  6. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/index.en.md +3 -1
  7. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/index.md +3 -1
  8. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/installation.en.md +42 -25
  9. tempest_cli-0.3.0/docs/installation.md +107 -0
  10. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/pyproject.toml +13 -6
  11. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/__init__.py +6 -4
  12. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/lint.py +15 -8
  13. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/test_lint_runners.py +25 -4
  14. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/uv.lock +3 -3
  15. tempest_cli-0.2.0/docs/installation.md +0 -89
  16. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/.github/workflows/ci.yml +0 -0
  17. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/.github/workflows/docs.yml +0 -0
  18. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/.github/workflows/release-pypi.yml +0 -0
  19. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/.gitignore +0 -0
  20. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/LICENSE +0 -0
  21. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/Makefile +0 -0
  22. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/commands.en.md +0 -0
  23. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/commands.md +0 -0
  24. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/configuration.en.md +0 -0
  25. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/configuration.md +0 -0
  26. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/library.en.md +0 -0
  27. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/library.md +0 -0
  28. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/pr-prompt.en.md +0 -0
  29. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/pr-prompt.md +0 -0
  30. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/reference.en.md +0 -0
  31. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/docs/reference.md +0 -0
  32. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/mkdocs.yml +0 -0
  33. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/_templates/pull_request_template.en-US.md +0 -0
  34. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/_templates/pull_request_template.pt-BR.md +0 -0
  35. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/config.py +0 -0
  36. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/main.py +0 -0
  37. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/pr_prompt.py +0 -0
  38. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tempest_cli/py.typed +0 -0
  39. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/__init__.py +0 -0
  40. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/test_cli.py +0 -0
  41. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/test_config.py +0 -0
  42. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/test_lint_strictness.py +0 -0
  43. {tempest_cli-0.2.0 → tempest_cli-0.3.0}/tests/test_pr_prompt.py +0 -0
@@ -5,6 +5,29 @@ All notable changes to **tempest-cli** are listed below.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.0] — 2026-08-15
9
+
10
+ ### Changed
11
+
12
+ - **`ruff` now ships with the package.** It moved from the `[tools]`
13
+ extra into the runtime dependencies, so `uv add --dev tempest-cli` is
14
+ enough for `lint`, `fix`, `format` and `fmt-check` to run — no second
15
+ install, and no dependency on `uv` being around to fetch one. The cost
16
+ is nil: ruff is a static binary wheel with no Python dependencies of
17
+ its own, so no bound of its reaches a consumer's resolution.
18
+
19
+ `mypy` and `pytest` stay out on purpose. A mypy bump changes which
20
+ errors a codebase reports and pytest has to match the suite and its
21
+ plugins — those are the project's call. `[tools]` now installs exactly
22
+ those two.
23
+
24
+ - **The project's environment is searched before the CLI's own.** With
25
+ ruff bundled, the CLI's environment always has one; looking there
26
+ first would silently override a version the project pinned whenever
27
+ `tempest-cli` is installed apart from it (`uv tool install`, pipx).
28
+ The order is now `$VIRTUAL_ENV` → nearest `.venv` → the CLI's own
29
+ environment → `PATH` → `uv run --with`.
30
+
8
31
  ## [0.2.0] — 2026-08-15
9
32
 
10
33
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tempest-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  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.
5
5
  Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-cli
6
6
  Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-cli
@@ -22,11 +22,11 @@ Classifier: Topic :: Software Development :: Quality Assurance
22
22
  Classifier: Topic :: Utilities
23
23
  Classifier: Typing :: Typed
24
24
  Requires-Python: >=3.11
25
+ Requires-Dist: ruff>=0.8.0
25
26
  Requires-Dist: typer>=0.12.0
26
27
  Provides-Extra: tools
27
28
  Requires-Dist: mypy>=1.13.0; extra == 'tools'
28
29
  Requires-Dist: pytest>=8.3.3; extra == 'tools'
29
- Requires-Dist: ruff>=0.8.0; extra == 'tools'
30
30
  Description-Content-Type: text/markdown
31
31
 
32
32
  # tempest-cli
@@ -42,7 +42,8 @@ One command for the quality gate of any Python project — `ruff` +
42
42
  `pyproject.toml` instead of in four different Makefile targets.
43
43
 
44
44
  Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
45
- library, a script. The only runtime dependency is `typer`.
45
+ library, a script. It brings `ruff` along, so the gate runs the moment
46
+ you install it; `typer` is the only other runtime dependency.
46
47
 
47
48
  ```bash
48
49
  uv add --dev tempest-cli
@@ -141,24 +142,33 @@ cli: typer.Typer = typer.Typer(name="mytool")
141
142
  register_commands(cli)
142
143
  ```
143
144
 
144
- ## Installing the tools
145
+ ## Where the tools come from
145
146
 
146
- `tempest-cli` shells out to whatever `ruff`, `mypy` and `pytest` it
147
- finds — it does not pin them, so your project chooses the versions. The
148
- lookup runs in this order:
147
+ **`ruff` comes with the package** — six of the eight commands are ruff,
148
+ so `lint`, `fix`, `format` and `fmt-check` work straight after
149
+ `uv add --dev tempest-cli`, with nothing else to install. It is a static
150
+ binary wheel with no Python dependencies of its own, so nothing of its
151
+ propagates into your resolution.
149
152
 
150
- 1. the environments of the run — the interpreter's own directory, then
151
- `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
152
- 2. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
153
- that answers `pyenv: ruff: command not found`);
154
- 3. `uv run --with <tool> <tool>`, when `uv` is available.
155
-
156
- To install the three alongside it:
153
+ `mypy` and `pytest` are deliberately left to you — a mypy bump changes
154
+ which errors your code reports, and pytest has to match your plugins and
155
+ your suite. Add them yourself, or take the bundle:
157
156
 
158
157
  ```bash
159
158
  uv add --dev "tempest-cli[tools]"
160
159
  ```
161
160
 
161
+ Whatever you pin wins over the bundled ruff. The lookup runs in this
162
+ order:
163
+
164
+ 1. the project's environment — `$VIRTUAL_ENV`, then the nearest `.venv`
165
+ up the tree;
166
+ 2. the environment `tempest-cli` itself runs from (where the bundled
167
+ ruff lives);
168
+ 3. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
169
+ that answers `pyenv: ruff: command not found`);
170
+ 4. `uv run --with <tool> <tool>`, when `uv` is available.
171
+
162
172
  ## Relationship with tempest-fastapi-sdk
163
173
 
164
174
  This package was extracted from
@@ -11,7 +11,8 @@ One command for the quality gate of any Python project — `ruff` +
11
11
  `pyproject.toml` instead of in four different Makefile targets.
12
12
 
13
13
  Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
14
- library, a script. The only runtime dependency is `typer`.
14
+ library, a script. It brings `ruff` along, so the gate runs the moment
15
+ you install it; `typer` is the only other runtime dependency.
15
16
 
16
17
  ```bash
17
18
  uv add --dev tempest-cli
@@ -110,24 +111,33 @@ cli: typer.Typer = typer.Typer(name="mytool")
110
111
  register_commands(cli)
111
112
  ```
112
113
 
113
- ## Installing the tools
114
+ ## Where the tools come from
114
115
 
115
- `tempest-cli` shells out to whatever `ruff`, `mypy` and `pytest` it
116
- finds — it does not pin them, so your project chooses the versions. The
117
- lookup runs in this order:
116
+ **`ruff` comes with the package** — six of the eight commands are ruff,
117
+ so `lint`, `fix`, `format` and `fmt-check` work straight after
118
+ `uv add --dev tempest-cli`, with nothing else to install. It is a static
119
+ binary wheel with no Python dependencies of its own, so nothing of its
120
+ propagates into your resolution.
118
121
 
119
- 1. the environments of the run — the interpreter's own directory, then
120
- `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
121
- 2. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
122
- that answers `pyenv: ruff: command not found`);
123
- 3. `uv run --with <tool> <tool>`, when `uv` is available.
124
-
125
- To install the three alongside it:
122
+ `mypy` and `pytest` are deliberately left to you — a mypy bump changes
123
+ which errors your code reports, and pytest has to match your plugins and
124
+ your suite. Add them yourself, or take the bundle:
126
125
 
127
126
  ```bash
128
127
  uv add --dev "tempest-cli[tools]"
129
128
  ```
130
129
 
130
+ Whatever you pin wins over the bundled ruff. The lookup runs in this
131
+ order:
132
+
133
+ 1. the project's environment — `$VIRTUAL_ENV`, then the nearest `.venv`
134
+ up the tree;
135
+ 2. the environment `tempest-cli` itself runs from (where the bundled
136
+ ruff lives);
137
+ 3. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
138
+ that answers `pyenv: ruff: command not found`);
139
+ 4. `uv run --with <tool> <tool>`, when `uv` is available.
140
+
131
141
  ## Relationship with tempest-fastapi-sdk
132
142
 
133
143
  This package was extracted from
@@ -3,6 +3,23 @@
3
3
  The full history lives in the repository's
4
4
  [`CHANGELOG.md`](https://github.com/mauriciobenjamin700/tempest-cli/blob/main/CHANGELOG.md).
5
5
 
6
+ ## [0.3.0] — 2026-08-15
7
+
8
+ ### Changed
9
+
10
+ - **`ruff` now ships with the package.** It left the `[tools]` extra for
11
+ the runtime dependencies, so `uv add --dev tempest-cli` is enough for
12
+ `lint`, `fix`, `format` and `fmt-check` to run. The cost is nil: ruff
13
+ is a static binary wheel with no Python dependencies of its own, so no
14
+ bound of its reaches a consumer's resolution. `mypy` and `pytest` stay
15
+ out on purpose; `[tools]` now installs exactly those two.
16
+ - **The project's environment is searched before the CLI's own.** With
17
+ ruff bundled, the CLI's environment always has one — looking there
18
+ first would silently override a version the project pinned whenever
19
+ `tempest-cli` lives apart from it (`uv tool install`, pipx). The order
20
+ is now `$VIRTUAL_ENV` → nearest `.venv` → the CLI's environment →
21
+ `PATH` → `uv run --with`.
22
+
6
23
  ## [0.2.0] — 2026-08-15
7
24
 
8
25
  ### Added
@@ -4,6 +4,23 @@ O histórico completo vive no
4
4
  [`CHANGELOG.md`](https://github.com/mauriciobenjamin700/tempest-cli/blob/main/CHANGELOG.md)
5
5
  do repositório.
6
6
 
7
+ ## [0.3.0] — 2026-08-15
8
+
9
+ ### Mudado
10
+
11
+ - **O `ruff` agora vem junto com o pacote.** Saiu do extra `[tools]` e
12
+ virou dependência: `uv add --dev tempest-cli` já basta para `lint`,
13
+ `fix`, `format` e `fmt-check` rodarem. Custo zero — o ruff é binário
14
+ estático, sem dependência Python, então nenhum limite dele entra na
15
+ resolução de quem instala. `mypy` e `pytest` continuam de fora de
16
+ propósito; `[tools]` agora instala exatamente esses dois.
17
+ - **O ambiente do projeto passa a ser procurado antes do da CLI.** Com o
18
+ ruff embutido, o ambiente da CLI sempre tem um — procurar ali primeiro
19
+ sobrescreveria em silêncio a versão que o projeto fixou quando o
20
+ `tempest-cli` mora fora dele (`uv tool install`, pipx). A ordem agora é
21
+ `$VIRTUAL_ENV` → `.venv` mais próximo → ambiente da CLI → `PATH` →
22
+ `uv run --with`.
23
+
7
24
  ## [0.2.0] — 2026-08-15
8
25
 
9
26
  ### Adicionado
@@ -5,7 +5,9 @@ and `pytest` — with the typing strictness living in `pyproject.toml`
5
5
  instead of spread across four Makefile targets.
6
6
 
7
7
  Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
8
- library, a script. The only runtime dependency is `typer`.
8
+ library, a script. There are two runtime dependencies: `typer` and
9
+ `ruff` — the latter ships along, so the gate runs the moment you install
10
+ it.
9
11
 
10
12
  ```bash
11
13
  uv add --dev tempest-cli
@@ -5,7 +5,9 @@ Um comando para o gate de qualidade de qualquer projeto Python — `ruff`,
5
5
  em vez de espalhado por quatro alvos de Makefile.
6
6
 
7
7
  Agnóstico de framework de propósito: Django, Flask, Litestar, FastAPI,
8
- uma biblioteca, um script. A única dependência de runtime é o `typer`.
8
+ uma biblioteca, um script. As dependências de runtime são duas: o
9
+ `typer` e o `ruff` — que já vem junto, para o gate rodar assim que
10
+ instala.
9
11
 
10
12
  ```bash
11
13
  uv add --dev tempest-cli
@@ -10,7 +10,9 @@ Or with pip:
10
10
  pip install tempest-cli
11
11
  ```
12
12
 
13
- Requires **Python 3.11+**. The only runtime dependency is `typer`.
13
+ Requires **Python 3.11+**. It brings `ruff` along — six of the eight
14
+ commands are ruff, so the gate runs the moment the package installs. The
15
+ other runtime dependency is `typer`.
14
16
 
15
17
  It installs **two executables**: `tempest-cli` and the short alias `tc`.
16
18
  They are the same program — everything in these docs applies to both.
@@ -26,15 +28,42 @@ tc check # identical to tempest-cli check
26
28
 
27
29
  ## Where ruff, mypy and pytest come from
28
30
 
29
- `tempest-cli` does **not** pin any of the three: it runs whatever it
30
- finds, in this order:
31
+ **`ruff` comes with the package**: install it and `lint`, `fix`,
32
+ `format` and `fmt-check` already work — nothing else to install.
31
33
 
32
- 1. **the environments of the run** — the directory of the interpreter
33
- running the CLI (where the `[tools]` extra installs all three), then
34
- `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
35
- 2. **`PATH`** — skipping a version-manager shim that dispatches nowhere
34
+ ```bash
35
+ uv add --dev tempest-cli
36
+ tempest-cli fix # runs right away
37
+ ```
38
+
39
+ `mypy` and `pytest` stay with you. A mypy bump changes which errors your
40
+ code starts reporting, and pytest has to match your plugins and your
41
+ suite — those versions are the project's call. Add them yourself, or
42
+ take the bundle:
43
+
44
+ ```bash
45
+ uv add --dev "tempest-cli[tools]" # mypy + pytest
46
+ ```
47
+
48
+ !!! question "Why ruff is a dependency and the other two are not"
49
+ Six of the eight commands are ruff — a `tempest-cli` without ruff is
50
+ a gate that cannot run. And it costs nothing: ruff is a static
51
+ binary with no Python dependencies at all, so no bound of its enters
52
+ your project's resolution. mypy and pytest, in contrast, run through
53
+ your code and your suite; pinning them here would be deciding for
54
+ you.
55
+
56
+ ### The lookup order
57
+
58
+ What your project pins **wins** over the bundled ruff. The CLI runs the
59
+ first thing it finds, in this order:
60
+
61
+ 1. **the project's environment** — `$VIRTUAL_ENV`, then the nearest
62
+ `.venv` up the tree;
63
+ 2. **the CLI's own environment** — where the bundled ruff lives;
64
+ 3. **`PATH`** — skipping a version-manager shim that dispatches nowhere
36
65
  (see below);
37
- 3. **`uv run --with <tool> <tool>`** when `uv` is available — the
66
+ 4. **`uv run --with <tool> <tool>`** when `uv` is available — the
38
67
  project's environment plus the tool, with no activation and no prior
39
68
  `uv sync` required.
40
69
 
@@ -46,22 +75,10 @@ tool and how to install it, instead of raising a traceback.
46
75
  globally and holds a stub for every tool any installed version ever
47
76
  provided. Looking up `ruff` there finds `~/.pyenv/shims/ruff` even
48
77
  when the project has no ruff at all — and running it prints
49
- `pyenv: ruff: command not found`. So the run's own environment wins
78
+ `pyenv: ruff: command not found`. So the run's own environments win
50
79
  over `PATH`, and a shim is only accepted after proving it dispatches
51
80
  (`<tool> --version` exiting `0`).
52
81
 
53
- !!! tip "Why the versions are not pinned"
54
- A ruff version pinned here would become the ceiling for every
55
- project installing this package — and upgrading the linter is a
56
- decision for whoever writes the code, not for whoever packages the
57
- gate.
58
-
59
- If you would rather install all three alongside:
60
-
61
- ```bash
62
- uv add --dev "tempest-cli[tools]"
63
- ```
64
-
65
82
  ## Verifying
66
83
 
67
84
  ```bash
@@ -82,9 +99,9 @@ it exactly as it would read `ruff` directly:
82
99
 
83
100
  ## Recap
84
101
 
85
- - `uv add --dev tempest-cli`, Python 3.11+, `typer` as the only
86
- dependency.
102
+ - `uv add --dev tempest-cli`, Python 3.11+, `ruff` already included.
103
+ - `mypy` and `pytest` are yours — or take `"tempest-cli[tools]"`.
87
104
  - Two executables: `tempest-cli` and the `tc` alias.
88
- - Tools come from the run's environment, from `PATH` (never a dead
89
- shim), or through `uv run --with`.
105
+ - What the project pins beats the bundled ruff; then come `PATH` (never
106
+ a dead shim) and `uv run --with`.
90
107
  - A missing tool means exit 127 with a message, not a traceback.
@@ -0,0 +1,107 @@
1
+ # Instalação
2
+
3
+ ```bash
4
+ uv add --dev tempest-cli
5
+ ```
6
+
7
+ Ou com pip:
8
+
9
+ ```bash
10
+ pip install tempest-cli
11
+ ```
12
+
13
+ Requer **Python 3.11+**. Vem com o `ruff` junto — seis dos oito
14
+ comandos são ruff, então o gate roda assim que o pacote instala. A outra
15
+ dependência de runtime é o `typer`.
16
+
17
+ Ficam instalados **dois executáveis**: `tempest-cli` e o apelido curto
18
+ `tc`. São o mesmo programa — tudo nesta documentação vale para os dois.
19
+
20
+ ```bash
21
+ tc check # idêntico a tempest-cli check
22
+ ```
23
+
24
+ !!! warning "`tc` também é o `tc(8)` do iproute2"
25
+ Enquanto o ambiente que instalou o pacote estiver no `PATH`, `tc`
26
+ resolve para esta CLI. Para o controlador de tráfego do Linux, chame
27
+ pelo caminho absoluto (`/usr/sbin/tc`) ou use `tempest-cli` e deixe
28
+ o `tc` livre.
29
+
30
+ ## De onde vêm o ruff, o mypy e o pytest
31
+
32
+ O **`ruff` já vem junto**: instalou o pacote, `lint`, `fix`, `format` e
33
+ `fmt-check` funcionam — nada mais a instalar.
34
+
35
+ ```bash
36
+ uv add --dev tempest-cli
37
+ tempest-cli fix # roda agora mesmo
38
+ ```
39
+
40
+ O `mypy` e o `pytest` ficam com você. Um bump de mypy muda quais erros o
41
+ seu código passa a reportar, e o pytest precisa casar com os seus plugins
42
+ e a sua suíte — versão dessas duas é decisão do projeto. Adicione você
43
+ mesmo, ou pegue o pacote pronto:
44
+
45
+ ```bash
46
+ uv add --dev "tempest-cli[tools]" # mypy + pytest
47
+ ```
48
+
49
+ !!! question "Por que o ruff é dependência e as outras duas não"
50
+ Seis dos oito comandos são ruff — um `tempest-cli` sem ruff é um
51
+ gate que não roda. E o custo é zero: o ruff é um binário estático,
52
+ sem dependência Python nenhuma, então nenhum limite dele entra na
53
+ resolução do seu projeto. Já mypy e pytest atravessam o seu código e
54
+ a sua suíte; fixá-los aqui seria decidir por você.
55
+
56
+ ### A ordem de busca
57
+
58
+ O que o seu projeto fixa **ganha** do ruff que veio junto. A CLI executa
59
+ o que encontrar primeiro, nesta ordem:
60
+
61
+ 1. **o ambiente do projeto** — `$VIRTUAL_ENV`, depois o `.venv` mais
62
+ próximo subindo a árvore;
63
+ 2. **o ambiente da própria CLI** — onde mora o ruff que veio junto;
64
+ 3. **o `PATH`** — pulando um *shim* de gerenciador de versão que não
65
+ despacha para lugar nenhum (veja abaixo);
66
+ 4. **`uv run --with <ferramenta> <ferramenta>`**, quando o `uv` está
67
+ disponível — o ambiente do projeto mais a ferramenta, sem exigir
68
+ ativação nem `uv sync` prévio.
69
+
70
+ Se nada resolver, o comando sai com **127** e diz qual ferramenta faltou
71
+ e como instalá-la, em vez de estourar um traceback.
72
+
73
+ !!! info "Por que o `PATH` não vem primeiro"
74
+ Em máquina com pyenv/asdf, o diretório `shims` está no `PATH`
75
+ globalmente e tem um stub para toda ferramenta que qualquer versão
76
+ instalada já forneceu. Procurar `ruff` ali acha
77
+ `~/.pyenv/shims/ruff` mesmo quando o projeto não tem ruff nenhum — e
78
+ rodá-lo dá `pyenv: ruff: command not found`. Por isso os ambientes da
79
+ execução ganham do `PATH`, e um shim só é aceito depois de provar que
80
+ despacha (`<ferramenta> --version` saindo `0`).
81
+
82
+ ## Verificando
83
+
84
+ ```bash
85
+ tempest-cli --version
86
+ tc --version # o mesmo programa
87
+ tempest-cli check --help
88
+ ```
89
+
90
+ ## Em CI
91
+
92
+ Cada comando devolve o código de saída da ferramenta por baixo, então o
93
+ job lê exatamente como leria o `ruff` direto:
94
+
95
+ ```yaml
96
+ - name: Quality gate
97
+ run: uv run tempest-cli check
98
+ ```
99
+
100
+ ## Recap
101
+
102
+ - `uv add --dev tempest-cli`, Python 3.11+, com o `ruff` já junto.
103
+ - `mypy` e `pytest` são seus — ou pegue `"tempest-cli[tools]"`.
104
+ - Dois executáveis: `tempest-cli` e o apelido `tc`.
105
+ - O que o projeto fixa ganha do ruff embutido; depois vêm o `PATH` (sem
106
+ shim morto) e o `uv run --with`.
107
+ - Ferramenta ausente = saída 127 com mensagem, não traceback.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tempest-cli"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "Framework-agnostic quality gate for Python projects: ruff + mypy + pytest behind one command, with a typing-strictness dial and a PR-description prompt generator."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -31,18 +31,25 @@ classifiers = [
31
31
  "Typing :: Typed",
32
32
  ]
33
33
  dependencies = [
34
+ # `ruff` ships with the package: six of the eight commands are ruff,
35
+ # so a tempest-cli without one is a gate that cannot run. It costs
36
+ # nothing to depend on — a static binary wheel with no Python
37
+ # dependencies of its own, so no bound of its propagates to anyone.
38
+ # The lookup still prefers a ruff the project pinned; this one is the
39
+ # fallback for a project that pinned none.
40
+ "ruff>=0.8.0",
34
41
  "typer>=0.12.0",
35
42
  ]
36
43
 
37
44
  [project.optional-dependencies]
38
- # The gate shells out to whatever `ruff` / `mypy` / `pytest` it finds on
39
- # PATH or in the active environment, so none of them is required to
40
- # install this package. `[tools]` is the convenience bundle for a project
41
- # that would rather pin them here than in its own dev group.
45
+ # `mypy` and `pytest` are deliberately NOT dependencies. A mypy bump
46
+ # changes which errors a codebase reports, and pytest has to match the
47
+ # plugins and the test suite it runs — both are the project's call, not
48
+ # this package's. `[tools]` is the convenience bundle for whoever would
49
+ # rather pin them here than in their own dev group.
42
50
  tools = [
43
51
  "mypy>=1.13.0",
44
52
  "pytest>=8.3.3",
45
- "ruff>=0.8.0",
46
53
  ]
47
54
 
48
55
  [project.urls]
@@ -5,9 +5,11 @@ typing-strictness dial read from ``[tool.tempest]`` in the project's
5
5
  ``pyproject.toml`` — and a generator for the prompt that makes an AI fill
6
6
  a pull-request description from the branch's own diff.
7
7
 
8
- It knows nothing about any web framework. The only runtime dependency is
9
- ``typer``; the tools themselves are invoked from the active environment,
10
- so a project pins the ruff and mypy versions it wants.
8
+ It knows nothing about any web framework. ``ruff`` ships with it, so the
9
+ lint/format commands work the moment it is installed; ``mypy`` and
10
+ ``pytest`` are left to the project, which pins the versions it wants.
11
+ The tools are invoked from the project's environment first, so a pinned
12
+ version always beats the bundled one.
11
13
 
12
14
  ```bash
13
15
  tempest-cli check # lint + fmt-check + type + test
@@ -49,7 +51,7 @@ from tempest_cli.pr_prompt import GitError as GitError
49
51
  from tempest_cli.pr_prompt import PromptLanguage as PromptLanguage
50
52
  from tempest_cli.pr_prompt import generate_pr_prompt as generate_pr_prompt
51
53
 
52
- __version__: str = "0.2.0"
54
+ __version__: str = "0.3.0"
53
55
  """Installed package version."""
54
56
 
55
57
  __all__: list[str] = [
@@ -42,19 +42,25 @@ def _environment_dirs() -> list[Path]:
42
42
  environment has no ruff at all. The environments below are the ones
43
43
  that actually belong to the run, so they are consulted first:
44
44
 
45
- 1. the directory of the interpreter running this CLI — where the
46
- ``[tools]`` extra installs ruff/mypy/pytest next to the
47
- ``tempest-cli`` executable itself;
48
- 2. ``$VIRTUAL_ENV`` — the activated environment, which matters when
49
- the CLI itself lives elsewhere (``uv tool install`` / pipx);
50
- 3. the nearest ``.venv`` walking up from the working directory — a
51
- project environment that was never activated.
45
+ 1. ``$VIRTUAL_ENV`` — the activated environment;
46
+ 2. the nearest ``.venv`` walking up from the working directory — a
47
+ project environment that was never activated;
48
+ 3. the directory of the interpreter running this CLI.
49
+
50
+ The project comes before the interpreter on purpose. ``ruff`` ships
51
+ as a dependency of this package, so the CLI's own environment always
52
+ has one; a project that pins its own must still get the version it
53
+ pinned, with the bundled one serving only as the fallback for a
54
+ project that pins nothing. When the CLI is installed *into* the
55
+ project (the common case) all three point at the same directory and
56
+ the order is moot — it only decides for ``uv tool install`` / pipx,
57
+ where the CLI lives in an environment of its own.
52
58
 
53
59
  Returns:
54
60
  list[Path]: Existing directories, in preference order, without
55
61
  duplicates.
56
62
  """
57
- roots: list[Path] = [Path(sys.executable).parent]
63
+ roots: list[Path] = []
58
64
  virtual_env = os.environ.get("VIRTUAL_ENV")
59
65
  if virtual_env:
60
66
  roots.extend((Path(virtual_env) / "bin", Path(virtual_env) / "Scripts"))
@@ -68,6 +74,7 @@ def _environment_dirs() -> list[Path]:
68
74
  if candidate.is_dir():
69
75
  roots.extend((candidate / "bin", candidate / "Scripts"))
70
76
  break
77
+ roots.append(Path(sys.executable).parent)
71
78
  seen: set[Path] = set()
72
79
  ordered: list[Path] = []
73
80
  for root in roots:
@@ -320,10 +320,16 @@ def test_a_shim_probe_that_cannot_spawn_is_not_runnable(
320
320
  assert lint._shim_runs(Path("/home/u/.pyenv/shims/ruff")) is False
321
321
 
322
322
 
323
- def test_environment_dirs_prefers_the_running_interpreter(
323
+ def test_environment_dirs_prefers_the_project_over_the_cli_itself(
324
324
  monkeypatch: pytest.MonkeyPatch, tmp_path: Path
325
325
  ) -> None:
326
- """The CLI's own environment is searched before $VIRTUAL_ENV."""
326
+ """A pinned ruff must win over the one shipped with this package.
327
+
328
+ `ruff` is a dependency of tempest-cli, so the CLI's own environment
329
+ always has one. Searching it first would silently override the
330
+ version a project pinned whenever the CLI lives elsewhere
331
+ (`uv tool install` / pipx).
332
+ """
327
333
  interpreter_dir = tmp_path / "cli-env" / "bin"
328
334
  interpreter_dir.mkdir(parents=True)
329
335
  active = tmp_path / "active"
@@ -332,8 +338,8 @@ def test_environment_dirs_prefers_the_running_interpreter(
332
338
  monkeypatch.setenv("VIRTUAL_ENV", str(active))
333
339
  monkeypatch.chdir(tmp_path)
334
340
  dirs = lint._environment_dirs()
335
- assert dirs[0] == interpreter_dir
336
- assert active / "bin" in dirs
341
+ assert dirs[0] == active / "bin"
342
+ assert dirs.index(interpreter_dir) > dirs.index(active / "bin")
337
343
 
338
344
 
339
345
  def test_environment_dirs_finds_an_unactivated_venv(
@@ -346,3 +352,18 @@ def test_environment_dirs_finds_an_unactivated_venv(
346
352
  monkeypatch.delenv("VIRTUAL_ENV", raising=False)
347
353
  monkeypatch.chdir(project / "src")
348
354
  assert project / ".venv" / "bin" in lint._environment_dirs()
355
+
356
+
357
+ def test_ruff_ships_with_the_package() -> None:
358
+ """Installing tempest-cli must be enough to run the ruff commands.
359
+
360
+ Six of the eight commands are ruff. Reading the requirement from the
361
+ installed distribution, not from ``pyproject.toml``, is what proves
362
+ a user actually receives it.
363
+ """
364
+ from importlib.metadata import requires
365
+
366
+ declared = requires("tempest-cli") or []
367
+ runtime = [item for item in declared if "extra ==" not in item]
368
+ assert any(item.startswith("ruff") for item in runtime), runtime
369
+ assert not any(item.startswith(("mypy", "pytest")) for item in runtime), runtime
@@ -1126,9 +1126,10 @@ wheels = [
1126
1126
 
1127
1127
  [[package]]
1128
1128
  name = "tempest-cli"
1129
- version = "0.2.0"
1129
+ version = "0.3.0"
1130
1130
  source = { editable = "." }
1131
1131
  dependencies = [
1132
+ { name = "ruff" },
1132
1133
  { name = "typer" },
1133
1134
  ]
1134
1135
 
@@ -1136,7 +1137,6 @@ dependencies = [
1136
1137
  tools = [
1137
1138
  { name = "mypy" },
1138
1139
  { name = "pytest" },
1139
- { name = "ruff" },
1140
1140
  ]
1141
1141
 
1142
1142
  [package.dev-dependencies]
@@ -1156,7 +1156,7 @@ docs = [
1156
1156
  requires-dist = [
1157
1157
  { name = "mypy", marker = "extra == 'tools'", specifier = ">=1.13.0" },
1158
1158
  { name = "pytest", marker = "extra == 'tools'", specifier = ">=8.3.3" },
1159
- { name = "ruff", marker = "extra == 'tools'", specifier = ">=0.8.0" },
1159
+ { name = "ruff", specifier = ">=0.8.0" },
1160
1160
  { name = "typer", specifier = ">=0.12.0" },
1161
1161
  ]
1162
1162
  provides-extras = ["tools"]
@@ -1,89 +0,0 @@
1
- # Instalação
2
-
3
- ```bash
4
- uv add --dev tempest-cli
5
- ```
6
-
7
- Ou com pip:
8
-
9
- ```bash
10
- pip install tempest-cli
11
- ```
12
-
13
- Requer **Python 3.11+**. A única dependência de runtime é o `typer`.
14
-
15
- Ficam instalados **dois executáveis**: `tempest-cli` e o apelido curto
16
- `tc`. São o mesmo programa — tudo nesta documentação vale para os dois.
17
-
18
- ```bash
19
- tc check # idêntico a tempest-cli check
20
- ```
21
-
22
- !!! warning "`tc` também é o `tc(8)` do iproute2"
23
- Enquanto o ambiente que instalou o pacote estiver no `PATH`, `tc`
24
- resolve para esta CLI. Para o controlador de tráfego do Linux, chame
25
- pelo caminho absoluto (`/usr/sbin/tc`) ou use `tempest-cli` e deixe
26
- o `tc` livre.
27
-
28
- ## De onde vêm o ruff, o mypy e o pytest
29
-
30
- O `tempest-cli` **não** fixa versão de nenhum dos três: ele executa o que
31
- encontrar, nesta ordem:
32
-
33
- 1. **o ambiente da execução** — o diretório do interpretador que está
34
- rodando a CLI (onde o extra `[tools]` instala as três), depois
35
- `$VIRTUAL_ENV`, depois o `.venv` mais próximo subindo a árvore;
36
- 2. **o `PATH`** — pulando um *shim* de gerenciador de versão que não
37
- despacha para lugar nenhum (veja abaixo);
38
- 3. **`uv run --with <ferramenta> <ferramenta>`**, quando o `uv` está
39
- disponível — o ambiente do projeto mais a ferramenta, sem exigir
40
- ativação nem `uv sync` prévio.
41
-
42
- Se nada resolver, o comando sai com **127** e diz qual ferramenta faltou
43
- e como instalá-la, em vez de estourar um traceback.
44
-
45
- !!! info "Por que o `PATH` não vem primeiro"
46
- Em máquina com pyenv/asdf, o diretório `shims` está no `PATH`
47
- globalmente e tem um stub para toda ferramenta que qualquer versão
48
- instalada já forneceu. Procurar `ruff` ali acha
49
- `~/.pyenv/shims/ruff` mesmo quando o projeto não tem ruff nenhum — e
50
- rodá-lo dá `pyenv: ruff: command not found`. Por isso o ambiente da
51
- execução ganha do `PATH`, e um shim só é aceito depois de provar que
52
- despacha (`<ferramenta> --version` saindo `0`).
53
-
54
- !!! tip "Por que não fixar as versões"
55
- Uma versão de ruff fixada aqui viraria o teto de todo projeto que
56
- instalasse este pacote — e atualizar o linter é decisão de quem
57
- escreve o código, não de quem empacota o gate.
58
-
59
- Se você prefere instalar as três junto:
60
-
61
- ```bash
62
- uv add --dev "tempest-cli[tools]"
63
- ```
64
-
65
- ## Verificando
66
-
67
- ```bash
68
- tempest-cli --version
69
- tc --version # o mesmo programa
70
- tempest-cli check --help
71
- ```
72
-
73
- ## Em CI
74
-
75
- Cada comando devolve o código de saída da ferramenta por baixo, então o
76
- job lê exatamente como leria o `ruff` direto:
77
-
78
- ```yaml
79
- - name: Quality gate
80
- run: uv run tempest-cli check
81
- ```
82
-
83
- ## Recap
84
-
85
- - `uv add --dev tempest-cli`, Python 3.11+, só o `typer` de dependência.
86
- - Dois executáveis: `tempest-cli` e o apelido `tc`.
87
- - As ferramentas vêm do ambiente da execução, do `PATH` (sem shim morto)
88
- ou do `uv run --with`.
89
- - Ferramenta ausente = saída 127 com mensagem, não traceback.
File without changes
File without changes
File without changes
File without changes
File without changes