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
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.
$ ruff check path/to/code/ # Lint all files in `path/to/code` (and any subdirectories).
For the full list of supported options, run ruff check --help
.
The set of enabled rules is controlled via the lint.select
,
lint.extend-select
, and lint.ignore
settings.
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 lint.select
and lint.ignore
accept either
a full rule code (e.g., F401
) or any valid prefix (e.g., F
). For example, given the following
configuration file:
=== "pyproject.toml"
```toml
[tool.ruff.lint]
select = ["E", "F"]
ignore = ["F401"]
```
=== "ruff.toml"
```toml
[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
lint.select
overlint.extend-select
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:
=== "pyproject.toml"
```toml
[tool.ruff.lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]
```
=== "ruff.toml"
```toml
[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 lint.select
and
lint.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 extend-select
and
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 configuration file:
=== "pyproject.toml"
```toml
[tool.ruff.lint]
select = ["E", "F"]
ignore = ["F401"]
```
=== "ruff.toml"
```toml
[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
.
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.
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 change when applying unsafe fixes.
Specifically, an unsafe fix could lead to a change in runtime behavior, the removal of comments, or both, while safe fixes are intended to preserve runtime behavior and will only remove comments when deleting entire statements or expressions (e.g., removing unused imports).
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 raised exception changes 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 the change in exception type could break error handling upstream, 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
By default, Ruff will display a hint when unsafe fixes are available but not enabled. The suggestion can be silenced
by setting the unsafe-fixes
setting to false
or using the --no-unsafe-fixes
flag.
The safety of fixes can be adjusted per rule using the lint.extend-safe-fixes
and lint.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:
=== "pyproject.toml"
```toml
[tool.ruff.lint]
extend-safe-fixes = ["F601"]
extend-unsafe-fixes = ["UP034"]
```
=== "ruff.toml"
```toml
[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.
To limit the set of rules that Ruff should fix, use the lint.fixable
or lint.extend-fixable
, and lint.unfixable
settings.
For example, the following configuration would enable fixes for all rules except
unused-imports
(F401
):
=== "pyproject.toml"
```toml
[tool.ruff.lint]
fixable = ["ALL"]
unfixable = ["F401"]
```
=== "ruff.toml"
```toml
[lint]
fixable = ["ALL"]
unfixable = ["F401"]
```
Conversely, the following configuration would only enable fixes for F401
:
=== "pyproject.toml"
```toml
[tool.ruff.lint]
fixable = ["F401"]
```
=== "ruff.toml"
```toml
[lint]
fixable = ["F401"]
```
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 lint.ignore
setting, 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
For import sorting, the noqa
should come at the end of the first line in the import block, and
will apply to all imports in the block, like so:
import os # noqa: I001
import abc
To ignore all violations across an entire file, add the line # ruff: noqa
anywhere in the file,
preferably towards the top, like so:
# ruff: noqa
To ignore a specific rule across an entire file, add the line # ruff: noqa: {code}
anywhere in the
file, preferably towards the top, like so:
# ruff: noqa: F841
Or see the lint.per-file-ignores
setting, which enables the same
functionality from within your pyproject.toml
or ruff.toml
file.
Global noqa
comments must be on their own line to disambiguate from comments which ignore
violations on a single line.
Note that Ruff will also respect Flake8's # flake8: noqa
directive, and will treat it as
equivalent to # ruff: noqa
.
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
.
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
.
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.
Unlike isort, Ruff does not respect action comments within docstrings.
See the isort documentation for more.
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.