
## Summary This PR updates our documentation for the upcoming formatter release. Broadly, the documentation is now structured as follows: - Overview - Tutorial - Installing Ruff - The Ruff Linter - Overview - `ruff check` - Rule selection - Error suppression - Exit codes - The Ruff Formatter - Overview - `ruff format` - Philosophy - Configuration - Format suppression - Exit codes - Black compatibility - Known deviations - Configuring Ruff - pyproject.toml - File discovery - Configuration discovery - CLI - Shell autocompletion - Preview - Rules - Settings - Integrations - `pre-commit` - VS Code - LSP - PyCharm - GitHub Actions - FAQ - Contributing The major changes include: - Removing the "Usage" section from the docs, and instead folding that information into "Integrations" and the new Linter and Formatter sections. - Breaking up "Configuration" into "Configuring Ruff" (for generic configuration), and new Linter- and Formatter-specific sections. - Updating all example configurations to use `[tool.ruff.lint]` and `[tool.ruff.format]`. My suggestion is to pull and build the docs locally, and review by reading them in the browser rather than trying to parse all the code changes. Closes https://github.com/astral-sh/ruff/issues/7235. Closes https://github.com/astral-sh/ruff/issues/7647.
11 KiB
The Ruff Linter
The Ruff Linter is an extremely fast Python linter designed as a drop-in replacement for Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, autoflake, and more.
ruff check
ruff check
is the primary entrypoint to the Ruff linter. It accepts a list of files or
directories, and lints all discovered Python files, optionally fixing any fixable errors:
ruff check . # Lint all files in the current directory.
ruff check . --fix # Lint all files in the current directory, and fix any fixable errors.
ruff check . --watch # Lint all files in the current directory, and re-lint on change.
For the full list of supported options, run ruff check --help
.
Rule selection
The set of enabled rules is controlled via the select
and ignore
settings, along with the extend-select
and extend-ignore
modifiers.
Ruff's linter mirrors Flake8's rule code system, in which each rule code consists of a one-to-three
letter prefix, followed by three digits (e.g., F401
). The prefix indicates that "source" of the rule
(e.g., F
for Pyflakes, E
for pycodestyle, ANN
for flake8-annotations).
Rule selectors like select
and ignore
accept either
a full rule code (e.g., F401
) or any valid prefix (e.g., F
). For example, given the following
pyproject.toml
file:
[tool.ruff.lint]
select = ["E", "F"]
ignore = ["F401"]
Ruff would enable all rules with the E
(pycodestyle) or F
(Pyflakes) prefix, with the exception
of F401
. For more on configuring Ruff via pyproject.toml
, see Configuring Ruff.
As a special-case, Ruff also supports the ALL
code, which enables all rules. Note that some
pydocstyle rules conflict (e.g., D203
and D211
) as they represent alternative docstring
formats. Ruff will automatically disable any conflicting rules when ALL
is enabled.
If you're wondering how to configure Ruff, here are some recommended guidelines:
- Prefer
select
andignore
overextend-select
andextend-ignore
, to make your rule set explicit. - Use
ALL
with discretion. EnablingALL
will implicitly enable new rules whenever you upgrade. - Start with a small set of rules (
select = ["E", "F"]
) and add a category at-a-time. For example, you might consider expanding toselect = ["E", "F", "B"]
to enable the popular flake8-bugbear extension.
For example, a configuration that enables some of the most popular rules (without being too pedantic) might look like the following:
[tool.ruff.lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]
To resolve the enabled rule set, Ruff may need to reconcile select
and ignore
from a variety
of sources, including the current pyproject.toml
, any inherited pyproject.toml
files, and the
CLI (e.g., --select
).
In those scenarios, Ruff uses the "highest-priority" select
as the basis for the rule set, and
then applies any extend-select
, ignore
, and extend-ignore
adjustments. CLI options are given
higher priority than pyproject.toml
options, and the current pyproject.toml
file is given higher
priority than any inherited pyproject.toml
files.
For example, given the following pyproject.toml
file:
[tool.ruff.lint]
select = ["E", "F"]
ignore = ["F401"]
Running ruff check --select F401
would result in Ruff enforcing F401
, and no other rules.
Running ruff check --extend-select B
would result in Ruff enforcing the E
, F
, and B
rules,
with the exception of F401
.
Fixes
Ruff supports automatic fixes for a variety of lint errors. For example, Ruff can remove unused imports, reformat docstrings, rewrite type annotations to use newer Python syntax, and more.
To enable fixes, pass the --fix
flag to ruff check
:
ruff check . --fix
By default, Ruff will fix all violations for which safe fixes are available; to determine whether a rule supports fixing, see Rules.
Fix safety
Ruff labels fixes as "safe" and "unsafe". The meaning and intent of your code will be retained when applying safe fixes, but the meaning could be changed when applying unsafe fixes.
For example, unnecessary-iterable-allocation-for-first-element
(RUF015
) is a rule which checks for potentially unperformant use of list(...)[0]
. The fix replaces this pattern with next(iter(...))
which can result in a drastic speedup:
$ python -m timeit "head = list(range(99999999))[0]"
1 loop, best of 5: 1.69 sec per loop
$ python -m timeit "head = next(iter(range(99999999)))"
5000000 loops, best of 5: 70.8 nsec per loop
However, when the collection is empty, this changes the raised exception from an IndexError
to StopIteration
:
$ python -c 'list(range(0))[0]'
Traceback (most recent call last):
File "<string>", line 1, in <module>
IndexError: list index out of range
$ python -c 'next(iter(range(0)))[0]'
Traceback (most recent call last):
File "<string>", line 1, in <module>
StopIteration
Since this could break error handling, this fix is categorized as unsafe.
Ruff only enables safe fixes by default. Unsafe fixes can be enabled by settings unsafe-fixes
in your configuration file or passing the --unsafe-fixes
flag to ruff check
:
# Show unsafe fixes
ruff check . --unsafe-fixes
# Apply unsafe fixes
ruff check . --fix --unsafe-fixes
The safety of fixes can be adjusted per rule using the extend-safe-fixes
and extend-unsafe-fixes
settings.
For example, the following configuration would promote unsafe fixes for F601
to safe fixes and demote safe fixes for UP034
to unsafe fixes:
[tool.ruff.lint]
extend-safe-fixes = ["F601"]
extend-unsafe-fixes = ["UP034"]
You may use prefixes to select rules as well, e.g., F
can be used to promote fixes for all rules in Pyflakes to safe.
!!! note
All fixes will always be displayed by Ruff when using the json
output format. The safety of each fix is available under the applicability
field.
Disabling fixes
To limit the set of rules that Ruff should fix, use the fixable
and unfixable
settings, along with their extend-fixable
and extend-unfixable
variants.
For example, the following configuration would enable fixes for all rules except
unused-imports
(F401
):
[tool.ruff.lint]
fixable = ["ALL"]
unfixable = ["F401"]
Conversely, the following configuration would only enable fixes for F401
:
[tool.ruff.lint]
fixable = ["F401"]
Error suppression
Ruff supports several mechanisms for suppressing lint errors, be they false positives or permissible violations.
To omit a lint rule entirely, add it to the "ignore" list via the ignore
or extend-ignore
settings, either on the command-line
or in your pyproject.toml
or ruff.toml
file.
To suppress a violation inline, Ruff uses a noqa
system similar to Flake8.
To ignore an individual violation, add # noqa: {code}
to the end of the line, like so:
# Ignore F841.
x = 1 # noqa: F841
# Ignore E741 and F841.
i = 1 # noqa: E741, F841
# Ignore _all_ violations.
x = 1 # noqa
For multi-line strings (like docstrings), the noqa
directive should come at the end of the string
(after the closing triple quote), and will apply to the entire string, like so:
"""Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.
""" # noqa: E501
To ignore all violations across an entire file, add # ruff: noqa
to any line in the file, like so:
# ruff: noqa
To ignore a specific rule across an entire file, add # ruff: noqa: {code}
to any line in the file,
like so:
# ruff: noqa: F841
Or see the per-file-ignores
setting, which enables the same
functionality from within your pyproject.toml
or ruff.toml
file.
Note that Ruff will also respect Flake8's # flake8: noqa
directive, and will treat it as
equivalent to # ruff: noqa
.
Detecting unused suppression comments
Ruff implements a special rule, unused-noqa
,
under the RUF100
code, to enforce that your noqa
directives are "valid", in that the violations
they say they ignore are actually being triggered on that line (and thus suppressed). To flag
unused noqa
directives, run: ruff check /path/to/file.py --extend-select RUF100
.
Ruff can also remove any unused noqa
directives via its fix functionality. To remove any
unused noqa
directives, run: ruff check /path/to/file.py --extend-select RUF100 --fix
.
Inserting necessary suppression comments
Ruff can automatically add noqa
directives to all lines that contain violations, which is
useful when migrating a new codebase to Ruff. To automatically add noqa
directives to all
relevant lines (with the appropriate rule codes), run: ruff check /path/to/file.py --add-noqa
.
Action comments
Ruff respects isort's action comments
(# isort: skip_file
, # isort: on
, # isort: off
, # isort: skip
, and # isort: split
), which
enable selectively enabling and disabling import sorting for blocks of code and other inline
configuration.
Ruff will also respect variants of these action comments with a # ruff:
prefix
(e.g., # ruff: isort: skip_file
, # ruff: isort: on
, and so on). These variants more clearly
convey that the action comment is intended for Ruff, but are functionally equivalent to the
isort variants.
See the isort documentation for more.
Exit codes
By default, ruff check
exits with the following status codes:
0
if no violations were found, or if all present violations were fixed automatically.1
if violations were found.2
if Ruff terminates abnormally due to invalid configuration, invalid CLI options, or an internal error.
This convention mirrors that of tools like ESLint, Prettier, and RuboCop.
ruff check
supports two command-line flags that alter its exit code behavior:
--exit-zero
will cause Ruff to exit with a status code of0
even if violations were found. Note that Ruff will still exit with a status code of2
if it terminates abnormally.--exit-non-zero-on-fix
will cause Ruff to exit with a status code of1
if violations were found, even if all such violations were fixed automatically. Note that the use of--exit-non-zero-on-fix
can result in a non-zero exit code even if no violations remain after fixing.