For years, Python linting required pylint, flake8, pycodestyle, isort, and a stack of plugins, each in a separate config. ruff (Rust-written) replaces all of them with a single tool that's 10-100x faster. It does style checks, import sorting, dead code detection, security warnings, and even autofixes. Modern Python projects (Pippa included) use ruff and call it a day.
The two commands
ruff check — show issues. ruff check --fix — autofix what's safely fixable. ruff format — format code (replaces black, in many setups). Configure once in pyproject.toml under [tool.ruff]. The default rules are sensible; tweak only when you have specific reasons.
mypy — static type checking
Type hints exist in your code; mypy reads them and verifies usage. mypy module.py or mypy . for the whole project. Errors are reported with file/line. Run it in CI; fix all errors as you go. Strict mode (--strict or strict = true in config) requires fully-typed code — the right setting for new projects, an aspiration for legacy ones.
pyright — the alternative
pyright (Microsoft) is mypy's main competitor. Faster, slightly different inference. VS Code's Pylance extension uses it. Many teams use pyright in the IDE for speed, mypy in CI for the "official" check. Both work on the same type hints.
pre-commit — running checks before each commit
pre-commit is a framework for Git hooks. Configure once in .pre-commit-config.yaml with the tools you want (ruff, mypy, pytest). Runs them on changed files at git commit time. Catches issues before you push.
Code
ruff — install and run·bash
pip install ruff
# Check your code
ruff check .
# Autofix
ruff check . --fix
# Format (replaces black for many)
ruff format .
# Common output:
# my_module.py:42:5: E711 Comparison to None should be 'x is None'
# Found 1 error.
# [*] 1 fixable with the --fix option.
In a small project: (a) install ruff and mypy. (b) Configure both in pyproject.toml with strict-ish settings. (c) Write a tiny module with a deliberate type error (e.g., return "abc" from a function annotated -> int). (d) Run mypy and observe the error. Fix it. (e) Run ruff check — write code with a deliberate unused import and confirm ruff flags it.
Progress
Progress is local-only — sign in to sync across devices.