pyfaro lint¶
pyfaro lint runs Ruff's linter (ruff check)
on your project. Use it to catch unused imports, import-order problems and
other rule violations before review or CI.
Pyfaro does not reimplement Ruff or interpret its configuration: it finds the right Ruff, runs it from the project root and returns its exit code.
Quick example¶
Scenarios¶
The examples use the project from pyfaro create lib demo plus two messy
files, src/demo/messy.py and scripts/tool.py.
Lint the whole project¶
$ pyfaro lint
I001 [*] Import block is un-sorted or un-formatted
--> scripts/tool.py:1:1
|
1 | import json
| ^^^^^^^^^^^
2 | x=1
|
help: Organize imports
|
1 | import json
2 +
3 | x=1
|
F401 [*] `json` imported but unused
--> scripts/tool.py:1:8
|
1 | import json
| ^^^^
2 | x=1
|
help: Remove unused import: `json`
|
- import json
1 | x=1
|
F401 [*] `os` imported but unused
--> src/demo/messy.py:1:8
|
1 | import os
| ^^
2 | import sys
|
help: Remove unused import: `os`
|
- import os
1 | import sys
|
F401 [*] `sys` imported but unused
--> src/demo/messy.py:2:8
|
1 | import os
2 | import sys
| ^^^
help: Remove unused import: `sys`
|
1 | import os
- import sys
2 |
|
Found 4 errors.
[*] 4 fixable with the `--fix` option.
error: ruff failed (exit status: 1); see ruff's output above
Ruff's report is untouched. The last line is Pyfaro's: Ruff exited with 1,
and so does pyfaro lint.
Note
pyfaro lint does not take --fix. Ruff's output says some findings are
fixable; apply them with pyfaro check --fix, which also
formats and re-verifies.
Lint specific paths¶
Pass files or directories after the command. They are relative to the
directory where you ran pyfaro, not to the project root, so tab completion
works as in any shell:
$ pyfaro lint src
…
Found 2 errors.
[*] 2 fixable with the `--fix` option.
error: ruff failed (exit status: 1); see ruff's output above
From inside a subdirectory, the same file is reachable by the path you would
use for ls; the reports always show project-relative paths:
A path that does not exist is a Ruff error:
$ pyfaro lint nonexistent.py
E902 No such file or directory (os error 2)
--> nonexistent.py:1:1
Found 1 error.
error: ruff failed (exit status: 1); see ruff's output above
Lint another project: --project¶
--project <PATH> selects exactly that project directory instead of searching
upward from the current one. The PATHS stay relative to your current
directory:
Here demo/src is resolved from the directory you are in, not from demo.
--project may appear before or after the paths. The project configuration
must load before Ruff starts.
Path handling¶
- Positional paths are relative to your current directory. Pyfaro turns them into absolute paths before starting Ruff.
- Ruff itself runs with the project root as its working directory.
- With no paths, Ruff checks the whole project root.
- With explicit paths, Pyfaro adds
--force-exclude, so a file your configuration excludes stays excluded even when you name it.
Configuration¶
Ruff reads its own configuration: [tool.ruff] in pyproject.toml,
ruff.toml or .ruff.toml. Pyfaro never passes overrides. A new project from
pyfaro create contains:
To exclude a directory, use Ruff's own setting:
With that, scripts/tool.py no longer appears in the whole-project run, and
naming it explicitly does not bring it back:
$ pyfaro lint scripts/tool.py
warning: No Python files found under the given path(s)
All checks passed!
Warning
Keep one source of Ruff configuration. pyfaro doctor reports
[tool.ruff] next to a ruff.toml as an error.
Guarantees¶
- No implicit sync.
pyfaro lintnever creates or modifies.venvoruv.lock. Install tools withpyfaro add --dev ruffandpyfaro sync. - No source writes. It only reads your code. Ruff may refresh its own
cache (
.ruff_cache). - Ruff runs directly (no shell, no
uv run), output streams through, stdin is inherited, and cancelling stops Ruff's process tree.
Errors and fixes¶
A problem in Ruff's configuration is reported by Ruff, with exit code 2:
$ pyfaro lint
ruff failed
Cause: Unknown rule selector `NOPE999` in `select` from `~/demo/pyproject.toml`
error: ruff failed (exit status: 2); see ruff's output above
Ruff is looked up in the project environment, then VIRTUAL_ENV, then PATH.
In a project that was not synced:
$ pyfaro lint
error: ruff: not found in the project environment, VIRTUAL_ENV, or PATH; run `pyfaro add --dev ruff` then `pyfaro sync`
Run exactly those two commands (the first only if Ruff is not already in your
dev group). Outside any project:
Exit codes¶
| Code | Meaning |
|---|---|
0 |
No violations |
1 |
Violations found, or a Pyfaro failure (no project, Ruff missing) |
2 |
Ruff itself failed, for example on an unknown rule selector in [tool.ruff] (Ruff's exit status is returned unchanged) |
130 |
Cancelled |
See also¶
pyfaro fmt— formatting with Ruff.pyfaro check— format check, lint and type check together, with--fix.pyfaro tools— see which Ruff is used.