An extremely fast Python linter, written in Rust.
Linting the CPython codebase from scratch.
- ⚡️ 10-100x faster than existing linters
- 🐍 Installable via
pip
- 🤝 Python 3.10 compatibility
- 🛠️
pyproject.toml
support - 📦 Built-in caching, to avoid re-analyzing unchanged files
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
- ⚖️ Near-parity with the built-in Flake8 rule set
- 🔌 Native re-implementations of popular Flake8 plugins, like
flake8-bugbear
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
functionality behind a single, common interface. Ruff can be used to replace Flake8 (plus a variety
of plugins), isort
, pydocstyle
,
yesqa
, eradicate
,
and even a subset of pyupgrade
and autoflake
all while executing tens or hundreds of times faster than any individual tool.
Ruff is extremely actively developed and used in major open-source projects like:
Read the launch blog post.
Sebastián Ramírez, creator of FastAPI:
Ruff is so fast that sometimes I add an intentional bug in the code just to confirm it's actually running and checking the code.
Bryan Van de Ven, co-creator of Bokeh, original author of Conda:
Ruff is ~150-200x faster than flake8 on my machine, scanning the whole repo takes ~0.2s instead of ~20s. This is an enormous quality of life improvement for local dev. It's fast enough that I added it as an actual commit hook, which is terrific.
Tim Abbott, lead developer of Zulip:
This is just ridiculously fast...
ruff
is amazing.
- Installation and Usage
- Configuration
- Supported Rules
- Pyflakes (F)
- pycodestyle (E)
- isort (I)
- pydocstyle (D)
- pyupgrade (U)
- pep8-naming (N)
- eradicate (ERA)
- flake8-bandit (S)
- flake8-comprehensions (C)
- flake8-boolean-trap (FBT)
- flake8-bugbear (B)
- flake8-builtins (A)
- flake8-debugger (T)
- flake8-tidy-imports (I25)
- flake8-print (T)
- flake8-quotes (Q)
- flake8-annotations (ANN)
- flake8-2020 (YTT)
- flake8-blind-except (BLE)
- mccabe (C90)
- Ruff-specific rules (RUF)
- Meta rules (M)
- Editor Integrations
- FAQ
- Development
- Releases
- Benchmarks
- Reference
- License
- Contributing
Ruff is available as ruff
on PyPI:
pip install ruff
If you're a macOS Homebrew or a Linuxbrew user, you can also install ruff
via Homebrew:
brew install ruff
To run Ruff, try any of the following:
ruff path/to/code/to/check.py
ruff path/to/code/
ruff path/to/code/*.py
You can run Ruff in --watch
mode to automatically re-run on-change:
ruff path/to/code/ --watch
Ruff also works with pre-commit:
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.146
hooks:
- id: ruff
Ruff is configurable both via pyproject.toml
and the command line. For a full list of configurable
options, see the API reference.
If left unspecified, the default configuration is equivalent to:
[tool.ruff]
line-length = 88
# Enable Pyflakes `E` and `F` codes by default.
select = ["E", "F"]
ignore = []
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
per-file-ignores = {}
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# Assume Python 3.10.
target-version = "py310"
[tool.ruff.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10
As an example, the following would configure Ruff to: (1) avoid checking for line-length
violations (E501
); (2), always autofix, but never remove unused imports (F401
); and (3) ignore
import-at-top-of-file errors (E402
) in __init__.py
files:
[tool.ruff]
# Enable Pyflakes and pycodestyle rules.
select = ["E", "F"]
# Never enforce `E501` (line length violations).
ignore = ["E501"]
# Always autofix, but never try to fix `F401` (unused imports).
fix = true
unfixable = ["F401"]
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402"]
"path/to/file.py" = ["E402"]
Plugin configurations should be expressed as subsections, e.g.:
[tool.ruff]
# Add "Q" to the list of enabled codes.
select = ["E", "F", "Q"]
[tool.ruff.flake8-quotes]
docstring-quotes = "double"
For a full list of configurable options, see the API reference.
Some common configuration settings can be provided via the command-line:
ruff path/to/code/ --select F401 --select F403
See ruff --help
for more:
Ruff: An extremely fast Python linter.
Usage: ruff [OPTIONS] <FILES>...
Arguments:
<FILES>...
Options:
--config <CONFIG>
Path to the `pyproject.toml` file to use for configuration
-v, --verbose
Enable verbose logging
-q, --quiet
Only log errors
-s, --silent
Disable all logging (but still exit with status code "1" upon detecting errors)
-e, --exit-zero
Exit with status code "0", even upon detecting errors
-w, --watch
Run in watch mode by re-running whenever files change
--fix
Attempt to automatically fix lint errors
-n, --no-cache
Disable cache reads
--select <SELECT>
List of error codes to enable
--extend-select <EXTEND_SELECT>
Like --select, but adds additional error codes on top of the selected ones
--ignore <IGNORE>
List of error codes to ignore
--extend-ignore <EXTEND_IGNORE>
Like --ignore, but adds additional error codes on top of the ignored ones
--exclude <EXCLUDE>
List of paths, used to exclude files and/or directories from checks
--extend-exclude <EXTEND_EXCLUDE>
Like --exclude, but adds additional files and directories on top of the excluded ones
--fixable <FIXABLE>
List of error codes to treat as eligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--unfixable <UNFIXABLE>
List of error codes to treat as ineligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--per-file-ignores <PER_FILE_IGNORES>
List of mappings from file pattern to code to exclude
--format <FORMAT>
Output serialization format for error messages [default: text] [possible values: text, json]
--show-source
Show violations with source code
--show-files
See the files Ruff will be run against with the current settings
--show-settings
See Ruff's settings
--add-noqa
Enable automatic additions of noqa directives to failing lines
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
Regular expression matching the name of dummy variables
--target-version <TARGET_VERSION>
The minimum Python version that should be supported
--line-length <LINE_LENGTH>
Set the line-length for length-associated checks and automatic formatting
--max-complexity <MAX_COMPLEXITY>
Max McCabe complexity allowed for a function
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
-h, --help
Print help information
-V, --version
Print version information
To omit a lint check entirely, add it to the "ignore" list via --ignore
or --extend-ignore
,
either on the command-line or in your project.toml
file.
To ignore an error in-line, Ruff uses a noqa
system similar to Flake8.
To ignore an individual error, 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_ errors.
x = 1 # noqa
Note that, for multi-line strings, the noqa
directive should come at the end of the string, and
will apply to the entire body, like so:
"""Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
""" # noqa: E501
Ruff supports several workflows to aid in noqa
management.
First, Ruff provides a special error code, M001
, to enforce that your noqa
directives are
"valid", in that the errors they say they ignore are actually being triggered on that line (and
thus suppressed). You can run ruff /path/to/file.py --extend-select M001
to flag unused noqa
directives.
Second, Ruff can automatically remove unused noqa
directives via its autofix functionality.
You can run ruff /path/to/file.py --extend-select M001 --fix
to automatically remove unused
noqa
directives.
Third, Ruff can automatically add noqa
directives to all failing lines. This is useful when
migrating a new codebase to Ruff. You can run ruff /path/to/file.py --add-noqa
to automatically
add noqa
directives to all failing lines, with the appropriate error codes.
Regardless of the rule's origin, Ruff re-implements every rule in Rust as a first-party feature.
By default, Ruff enables all E
and F
error codes, which correspond to those built-in to Flake8.
The 🛠 emoji indicates that a rule is automatically fixable by the --fix
command-line option.
For more, see Pyflakes on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
F401 | UnusedImport | ... imported but unused |
🛠 |
F402 | ImportShadowedByLoopVar | Import ... from line 1 shadowed by loop variable |
|
F403 | ImportStarUsed | from ... import * used; unable to detect undefined names |
|
F404 | LateFutureImport | from __future__ imports must occur at the beginning of the file |
|
F405 | ImportStarUsage | ... may be undefined, or defined from star imports: ... |
|
F406 | ImportStarNotPermitted | from ... import * only allowed at module level |
|
F407 | FutureFeatureNotDefined | Future feature ... is not defined |
|
F501 | PercentFormatInvalidFormat | '...' % ... has invalid format string: ... | |
F502 | PercentFormatExpectedMapping | '...' % ... expected mapping but got sequence | |
F503 | PercentFormatExpectedSequence | '...' % ... expected sequence but got mapping | |
F504 | PercentFormatExtraNamedArguments | '...' % ... has unused named argument(s): ... | |
F505 | PercentFormatMissingArgument | '...' % ... is missing argument(s) for placeholder(s): ... | |
F506 | PercentFormatMixedPositionalAndNamed | '...' % ... has mixed positional and named placeholders | |
F507 | PercentFormatPositionalCountMismatch | '...' % ... has 4 placeholder(s) but 2 substitution(s) | |
F508 | PercentFormatStarRequiresSequence | '...' % ... * specifier requires sequence |
|
F509 | PercentFormatUnsupportedFormatCharacter | '...' % ... has unsupported format character 'c' | |
F521 | StringDotFormatInvalidFormat | '...'.format(...) has invalid format string: ... | |
F522 | StringDotFormatExtraNamedArguments | '...'.format(...) has unused named argument(s): ... | |
F523 | StringDotFormatExtraPositionalArguments | '...'.format(...) has unused arguments at position(s): ... | |
F524 | StringDotFormatMissingArguments | '...'.format(...) is missing argument(s) for placeholder(s): ... | |
F525 | StringDotFormatMixingAutomatic | '...'.format(...) mixes automatic and manual numbering | |
F541 | FStringMissingPlaceholders | f-string without any placeholders | |
F601 | MultiValueRepeatedKeyLiteral | Dictionary key literal repeated | |
F602 | MultiValueRepeatedKeyVariable | Dictionary key ... repeated |
|
F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | |
F622 | TwoStarredExpressions | Two starred expressions in assignment | |
F631 | AssertTuple | Assert test is a non-empty tuple, which is always True |
|
F632 | IsLiteral | Use == and != to compare constant literals |
🛠 |
F633 | InvalidPrintSyntax | Use of >> is invalid with print function |
|
F634 | IfTuple | If test is a tuple, which is always True |
|
F701 | BreakOutsideLoop | break outside loop |
|
F702 | ContinueOutsideLoop | continue not properly in loop |
|
F704 | YieldOutsideFunction | yield or yield from statement outside of a function |
|
F706 | ReturnOutsideFunction | return statement outside of a function/method |
|
F707 | DefaultExceptNotLast | An except block as not the last exception handler |
|
F722 | ForwardAnnotationSyntaxError | Syntax error in forward annotation: ... |
|
F821 | UndefinedName | Undefined name ... |
|
F822 | UndefinedExport | Undefined name ... in __all__ |
|
F823 | UndefinedLocal | Local variable ... referenced before assignment |
|
F831 | DuplicateArgumentName | Duplicate argument name in function definition | |
F841 | UnusedVariable | Local variable ... is assigned to but never used |
|
F901 | RaiseNotImplemented | raise NotImplemented should be raise NotImplementedError |
🛠 |
For more, see pycodestyle on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
E402 | ModuleImportNotAtTopOfFile | Module level import not at top of file | |
E501 | LineTooLong | Line too long (89 > 88 characters) | |
E711 | NoneComparison | Comparison to None should be cond is None |
🛠 |
E712 | TrueFalseComparison | Comparison to True should be cond is True |
🛠 |
E713 | NotInTest | Test for membership should be not in |
🛠 |
E714 | NotIsTest | Test for object identity should be is not |
🛠 |
E721 | TypeComparison | Do not compare types, use isinstance() |
|
E722 | DoNotUseBareExcept | Do not use bare except |
|
E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 |
E741 | AmbiguousVariableName | Ambiguous variable name: ... |
|
E742 | AmbiguousClassName | Ambiguous class name: ... |
|
E743 | AmbiguousFunctionName | Ambiguous function name: ... |
|
E902 | IOError | IOError: ... |
|
E999 | SyntaxError | SyntaxError: ... |
|
W292 | NoNewLineAtEndOfFile | No newline at end of file | |
W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' |
For more, see isort on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
I001 | UnsortedImports | Import block is un-sorted or un-formatted | 🛠 |
For more, see pydocstyle on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
D100 | PublicModule | Missing docstring in public module | |
D101 | PublicClass | Missing docstring in public class | |
D102 | PublicMethod | Missing docstring in public method | |
D103 | PublicFunction | Missing docstring in public function | |
D104 | PublicPackage | Missing docstring in public package | |
D105 | MagicMethod | Missing docstring in magic method | |
D106 | PublicNestedClass | Missing docstring in public nested class | |
D107 | PublicInit | Missing docstring in __init__ |
|
D200 | FitsOnOneLine | One-line docstring should fit on one line | |
D201 | NoBlankLineBeforeFunction | No blank lines allowed before function docstring (found 1) | 🛠 |
D202 | NoBlankLineAfterFunction | No blank lines allowed after function docstring (found 1) | 🛠 |
D203 | OneBlankLineBeforeClass | 1 blank line required before class docstring | 🛠 |
D204 | OneBlankLineAfterClass | 1 blank line required after class docstring | 🛠 |
D205 | BlankLineAfterSummary | 1 blank line required between summary line and description | 🛠 |
D206 | IndentWithSpaces | Docstring should be indented with spaces, not tabs | |
D207 | NoUnderIndentation | Docstring is under-indented | 🛠 |
D208 | NoOverIndentation | Docstring is over-indented | 🛠 |
D209 | NewLineAfterLastParagraph | Multi-line docstring closing quotes should be on a separate line | 🛠 |
D210 | NoSurroundingWhitespace | No whitespaces allowed surrounding docstring text | 🛠 |
D211 | NoBlankLineBeforeClass | No blank lines allowed before class docstring | 🛠 |
D212 | MultiLineSummaryFirstLine | Multi-line docstring summary should start at the first line | |
D213 | MultiLineSummarySecondLine | Multi-line docstring summary should start at the second line | |
D214 | SectionNotOverIndented | Section is over-indented ("Returns") | 🛠 |
D215 | SectionUnderlineNotOverIndented | Section underline is over-indented ("Returns") | 🛠 |
D300 | UsesTripleQuotes | Use """triple double quotes""" | |
D400 | EndsInPeriod | First line should end with a period | |
D402 | NoSignature | First line should not be the function's signature | |
D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | |
D404 | NoThisPrefix | First word of the docstring should not be "This" | |
D405 | CapitalizeSectionName | Section name should be properly capitalized ("returns") | 🛠 |
D406 | NewLineAfterSectionName | Section name should end with a newline ("Returns") | 🛠 |
D407 | DashedUnderlineAfterSection | Missing dashed underline after section ("Returns") | 🛠 |
D408 | SectionUnderlineAfterName | Section underline should be in the line following the section's name ("Returns") | 🛠 |
D409 | SectionUnderlineMatchesSectionLength | Section underline should match the length of its name ("Returns") | 🛠 |
D410 | BlankLineAfterSection | Missing blank line after section ("Returns") | 🛠 |
D411 | BlankLineBeforeSection | Missing blank line before section ("Returns") | 🛠 |
D412 | NoBlankLinesBetweenHeaderAndContent | No blank lines allowed between a section header and its content ("Returns") | 🛠 |
D413 | BlankLineAfterLastSection | Missing blank line after last section ("Returns") | 🛠 |
D414 | NonEmptySection | Section has no content ("Returns") | |
D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | |
D416 | SectionNameEndsInColon | Section name should end with a colon ("Returns") | 🛠 |
D417 | DocumentAllArguments | Missing argument descriptions in the docstring: x , y |
|
D418 | SkipDocstring | Function decorated with @overload shouldn't contain a docstring |
|
D419 | NonEmpty | Docstring is empty |
For more, see pyupgrade on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
U001 | UselessMetaclassType | __metaclass__ = type is implied |
🛠 |
U003 | TypeOfPrimitive | Use str instead of type(...) |
🛠 |
U004 | UselessObjectInheritance | Class ... inherits from object |
🛠 |
U005 | DeprecatedUnittestAlias | assertEquals is deprecated, use assertEqual instead |
🛠 |
U006 | UsePEP585Annotation | Use list instead of List for type annotations |
🛠 |
U007 | UsePEP604Annotation | Use X | Y for type annotations |
🛠 |
U008 | SuperCallWithParameters | Use super() instead of super(__class__, self) |
🛠 |
U009 | PEP3120UnnecessaryCodingComment | UTF-8 encoding declaration is unnecessary | 🛠 |
U010 | UnnecessaryFutureImport | Unnecessary __future__ import ... for target Python version |
🛠 |
U011 | UnnecessaryLRUCacheParams | Unnecessary parameters to functools.lru_cache |
🛠 |
U012 | UnnecessaryEncodeUTF8 | Unnecessary call to encode as UTF-8 |
🛠 |
U013 | ConvertTypedDictFunctionalToClass | Convert ... from TypedDict functional to class syntax |
🛠 |
U014 | ConvertNamedTupleFunctionalToClass | Convert ... from NamedTuple functional to class syntax |
🛠 |
U015 | RedundantOpenModes | Unnecessary open mode parameters | 🛠 |
For more, see pep8-naming on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
N801 | InvalidClassName | Class name ... should use CapWords convention |
|
N802 | InvalidFunctionName | Function name ... should be lowercase |
|
N803 | InvalidArgumentName | Argument name ... should be lowercase |
|
N804 | InvalidFirstArgumentNameForClassMethod | First argument of a class method should be named cls |
|
N805 | InvalidFirstArgumentNameForMethod | First argument of a method should be named self |
|
N806 | NonLowercaseVariableInFunction | Variable ... in function should be lowercase |
|
N807 | DunderFunctionName | Function name should not start and end with __ |
|
N811 | ConstantImportedAsNonConstant | Constant ... imported as non-constant ... |
|
N812 | LowercaseImportedAsNonLowercase | Lowercase ... imported as non-lowercase ... |
|
N813 | CamelcaseImportedAsLowercase | Camelcase ... imported as lowercase ... |
|
N814 | CamelcaseImportedAsConstant | Camelcase ... imported as constant ... |
|
N815 | MixedCaseVariableInClassScope | Variable mixedCase in class scope should not be mixedCase |
|
N816 | MixedCaseVariableInGlobalScope | Variable mixedCase in global scope should not be mixedCase |
|
N817 | CamelcaseImportedAsAcronym | Camelcase ... imported as acronym ... |
|
N818 | ErrorSuffixOnExceptionName | Exception name ... should be named with an Error suffix |
For more, see eradicate on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
ERA001 | CommentedOutCode | Found commented-out code | 🛠 |
For more, see flake8-bandit on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
S101 | AssertUsed | Use of assert detected |
|
S102 | ExecUsed | Use of exec detected |
|
S104 | HardcodedBindAllInterfaces | Possible binding to all interfaces | |
S105 | HardcodedPasswordString | Possible hardcoded password: "..." |
|
S106 | HardcodedPasswordFuncArg | Possible hardcoded password: "..." |
|
S107 | HardcodedPasswordDefault | Possible hardcoded password: "..." |
For more, see flake8-comprehensions on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
C400 | UnnecessaryGeneratorList | Unnecessary generator (rewrite as a list comprehension) |
🛠 |
C401 | UnnecessaryGeneratorSet | Unnecessary generator (rewrite as a set comprehension) |
🛠 |
C402 | UnnecessaryGeneratorDict | Unnecessary generator (rewrite as a dict comprehension) |
🛠 |
C403 | UnnecessaryListComprehensionSet | Unnecessary list comprehension (rewrite as a set comprehension) |
🛠 |
C404 | UnnecessaryListComprehensionDict | Unnecessary list comprehension (rewrite as a dict comprehension) |
🛠 |
C405 | UnnecessaryLiteralSet | Unnecessary (list|tuple) literal (rewrite as a set literal) |
🛠 |
C406 | UnnecessaryLiteralDict | Unnecessary (list|tuple) literal (rewrite as a dict literal) |
🛠 |
C408 | UnnecessaryCollectionCall | Unnecessary (dict|list|tuple) call (rewrite as a literal) |
🛠 |
C409 | UnnecessaryLiteralWithinTupleCall | Unnecessary (list|tuple) literal passed to tuple() (remove the outer call to tuple() ) |
🛠 |
C410 | UnnecessaryLiteralWithinListCall | Unnecessary (list|tuple) literal passed to list() (rewrite as a list literal) |
🛠 |
C411 | UnnecessaryListCall | Unnecessary list call (remove the outer call to list() ) |
🛠 |
C413 | UnnecessaryCallAroundSorted | Unnecessary (list|reversed) call around sorted() |
|
C414 | UnnecessaryDoubleCastOrProcess | Unnecessary (list|reversed|set|sorted|tuple) call within (list|set|sorted|tuple)() |
|
C415 | UnnecessarySubscriptReversal | Unnecessary subscript reversal of iterable within (reversed|set|sorted)() |
|
C416 | UnnecessaryComprehension | Unnecessary (list|set) comprehension (rewrite using (list|set)() ) |
🛠 |
C417 | UnnecessaryMap | Unnecessary map usage (rewrite using a (list|set|dict) comprehension) |
For more, see flake8-debugger on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
T100 | Debugger | Import for ... found |
For more, see flake8-boolean-trap on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
FBT001 | BooleanPositionalArgInFunctionDefinition | Boolean positional arg in function definition | |
FBT002 | BooleanDefaultValueInFunctionDefinition | Boolean default value in function definition | |
FBT003 | BooleanPositionalValueInFunctionCall | Boolean positional value in function call |
For more, see flake8-bugbear on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
B002 | UnaryPrefixIncrement | Python does not support the unary prefix increment | |
B003 | AssignmentToOsEnviron | Assigning to os.environ doesn't clear the environment |
|
B004 | UnreliableCallableCheck | Using hasattr(x, '__call__') to test if x is callable is unreliable. Use callable(x) for consistent results. |
|
B005 | StripWithMultiCharacters | Using .strip() with multi-character strings is misleading the reader |
|
B006 | MutableArgumentDefault | Do not use mutable data structures for argument defaults | |
B007 | UnusedLoopControlVariable | Loop control variable i not used within the loop body |
🛠 |
B008 | FunctionCallArgumentDefault | Do not perform function call in argument defaults | |
B009 | GetAttrWithConstant | Do not call getattr with a constant attribute value. It is not any safer than normal property access. |
🛠 |
B010 | SetAttrWithConstant | Do not call setattr with a constant attribute value. It is not any safer than normal property access. |
🛠 |
B011 | DoNotAssertFalse | Do not assert False (python -O removes these calls), raise AssertionError() |
🛠 |
B012 | JumpStatementInFinally | return/continue/break inside finally blocks cause exceptions to be silenced |
|
B013 | RedundantTupleInExceptionHandler | A length-one tuple literal is redundant. Write except ValueError instead of except (ValueError,) . |
🛠 |
B014 | DuplicateHandlerException | Exception handler with duplicate exception: ValueError |
🛠 |
B015 | UselessComparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend assert or remove it. |
|
B016 | CannotRaiseLiteral | Cannot raise a literal. Did you intend to return it or raise an Exception? | |
B017 | NoAssertRaisesException | assertRaises(Exception) should be considered evil |
|
B018 | UselessExpression | Found useless expression. Either assign it to a variable or remove it. | |
B019 | CachedInstanceMethod | Use of functools.lru_cache or functools.cache on methods can lead to memory leaks |
|
B020 | LoopVariableOverridesIterator | Loop control variable ... overrides iterable it iterates |
|
B021 | FStringDocstring | f-string used as docstring. This will be interpreted by python as a joined string rather than a docstring. | |
B022 | UselessContextlibSuppress | No arguments passed to contextlib.suppress . No exceptions will be suppressed and therefore this context manager is redundant |
|
B023 | FunctionUsesLoopVariable | Function definition does not bind loop variable ... |
|
B024 | AbstractBaseClassWithoutAbstractMethod | ... is an abstract base class, but it has no abstract methods |
|
B025 | DuplicateTryBlockException | try-except block with duplicate exception Exception |
|
B026 | StarArgUnpackingAfterKeywordArg | Star-arg unpacking after a keyword argument is strongly discouraged | |
B027 | EmptyMethodWithoutAbstractDecorator | ... is an empty method in an abstract base class, but has no abstract decorator |
|
B904 | RaiseWithoutFromInsideExcept | Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling |
For more, see flake8-builtins on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
A001 | BuiltinVariableShadowing | Variable ... is shadowing a python builtin |
|
A002 | BuiltinArgumentShadowing | Argument ... is shadowing a python builtin |
|
A003 | BuiltinAttributeShadowing | Class attribute ... is shadowing a python builtin |
For more, see flake8-tidy-imports on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
I252 | BannedRelativeImport | Relative imports are banned |
For more, see flake8-print on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
T201 | PrintFound | print found |
🛠 |
T203 | PPrintFound | pprint found |
🛠 |
For more, see flake8-quotes on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
Q000 | BadQuotesInlineString | Single quotes found but double quotes preferred | |
Q001 | BadQuotesMultilineString | Single quote multiline found but double quotes preferred | |
Q002 | BadQuotesDocstring | Single quote docstring found but double quotes preferred | |
Q003 | AvoidQuoteEscape | Change outer quotes to avoid escaping inner quotes |
For more, see flake8-annotations on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
ANN001 | MissingTypeFunctionArgument | Missing type annotation for function argument ... |
|
ANN002 | MissingTypeArgs | Missing type annotation for *... |
|
ANN003 | MissingTypeKwargs | Missing type annotation for **... |
|
ANN101 | MissingTypeSelf | Missing type annotation for ... in method |
|
ANN102 | MissingTypeCls | Missing type annotation for ... in classmethod |
|
ANN201 | MissingReturnTypePublicFunction | Missing return type annotation for public function ... |
|
ANN202 | MissingReturnTypePrivateFunction | Missing return type annotation for private function ... |
|
ANN204 | MissingReturnTypeMagicMethod | Missing return type annotation for magic method ... |
|
ANN205 | MissingReturnTypeStaticMethod | Missing return type annotation for staticmethod ... |
|
ANN206 | MissingReturnTypeClassMethod | Missing return type annotation for classmethod ... |
|
ANN401 | DynamicallyTypedExpression | Dynamically typed expressions (typing.Any) are disallowed in ... |
For more, see flake8-2020 on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
YTT101 | SysVersionSlice3Referenced | sys.version[:3] referenced (python3.10), use sys.version_info |
|
YTT102 | SysVersion2Referenced | sys.version[2] referenced (python3.10), use sys.version_info |
|
YTT103 | SysVersionCmpStr3 | sys.version compared to string (python3.10), use sys.version_info |
|
YTT201 | SysVersionInfo0Eq3Referenced | sys.version_info[0] == 3 referenced (python4), use >= |
|
YTT202 | SixPY3Referenced | six.PY3 referenced (python4), use not six.PY2 |
|
YTT203 | SysVersionInfo1CmpInt | sys.version_info[1] compared to integer (python4), compare sys.version_info to tuple |
|
YTT204 | SysVersionInfoMinorCmpInt | sys.version_info.minor compared to integer (python4), compare sys.version_info to tuple |
|
YTT301 | SysVersion0Referenced | sys.version[0] referenced (python10), use sys.version_info |
|
YTT302 | SysVersionCmpStr10 | sys.version compared to string (python10), use sys.version_info |
|
YTT303 | SysVersionSlice1Referenced | sys.version[:1] referenced (python10), use sys.version_info |
For more, see flake8-blind-except on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
BLE001 | BlindExcept | Blind except Exception: statement |
For more, see mccabe on PyPI.
Code | Name | Message | Fix |
---|---|---|---|
C901 | FunctionIsTooComplex | ... is too complex (10) |
Code | Name | Message | Fix |
---|---|---|---|
RUF001 | AmbiguousUnicodeCharacterString | String contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
RUF002 | AmbiguousUnicodeCharacterDocstring | Docstring contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | |
RUF101 | ConvertExitToSysExit | exit() is only available in the interpreter, use sys.exit() instead |
🛠 |
Code | Name | Message | Fix |
---|---|---|---|
M001 | UnusedNOQA | Unused noqa directive |
🛠 |
Download the Ruff VS Code extension.
Ruff can be installed as an External Tool in PyCharm. Open the Preferences pane, then navigate to "Tools", then "External Tools". From there, add a new tool with the following configuration:
Ruff should then appear as a runnable action:
Ruff is available as part of the coc-pyright extension for coc.nvim.
Ruff can also be integrated via efm
in just a few lines.
tools:
python-ruff: &python-ruff
lint-command: 'ruff --config ~/myconfigs/linters/ruff.toml --quiet ${INPUT}'
lint-stdin: true
lint-formats:
- '%f:%l:%c: %m'
format-command: 'ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -'
format-stdin: true
For neovim users using null-ls
, Ruff is already integrated.
local null_ls = require("null-ls")
local methods = require("null-ls.methods")
local helpers = require("null-ls.helpers")
local function ruff_fix()
return helpers.make_builtin({
name = "ruff",
meta = {
url = "https://github.com/charliermarsh/ruff/",
description = "An extremely fast Python linter, written in Rust.",
},
method = methods.internal.FORMATTING,
filetypes = { "python" },
generator_opts = {
command = "ruff",
args = { "--fix", "-e", "-n", "--stdin-filename", "$FILENAME", "-" },
to_stdin = true
},
factory = helpers.formatter_factory
})
end
null_ls.setup({
sources = {
ruff_fix(),
null_ls.builtins.diagnostics.ruff,
}
})
ruffd
is a Rust-based language server for Ruff that implements
the Language Server Protocol (LSP).
GitHub Actions has everything you need to run Ruff out-of-the-box:
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff
- name: Run Ruff
run: ruff .
Yes. Ruff is compatible with Black out-of-the-box, as long as
the line-length
setting is consistent between the two.
As a project, Ruff is designed to be used alongside Black and, as such, will defer implementing stylistic lint rules that are obviated by autoformatting.
(Coming from Flake8? Try flake8-to-ruff
to
automatically convert your existing configuration.)
Ruff can be used as a drop-in replacement for Flake8 when used (1) without or with a small number of plugins, (2) alongside Black, and (3) on Python 3 code.
Under those conditions, Ruff implements every rule in Flake8, with the exception of F811
.
Ruff also re-implements some of the most popular Flake8 plugins and related code quality tools natively, including:
isort
pydocstyle
pep8-naming
flake8-2020
flake8-annotations
flake8-bandit
(6/40)flake8-blind-except
flake8-boolean-trap
flake8-bugbear
flake8-builtins
flake8-comprehensions
flake8-debugger
flake8-docstrings
flake8-eradicate
flake8-print
flake8-quotes
flake8-super
flake8-tidy-imports
(1/3)mccabe
yesqa
eradicate
pyupgrade
(16/33)autoflake
(1/7)
Beyond the rule set, Ruff suffers from the following limitations vis-à-vis Flake8:
- Ruff does not yet support a few Python 3.9 and 3.10 language features, including structural pattern matching and parenthesized context managers.
- Flake8 has a plugin architecture and supports writing custom lint rules. (Instead, popular Flake8 plugins are re-implemented in Rust as part of Ruff itself.)
Today, Ruff can be used to replace Flake8 when used with any of the following plugins:
pydocstyle
pep8-naming
flake8-2020
flake8-annotations
flake8-bandit
(6/40)flake8-blind-except
flake8-boolean-trap
flake8-bugbear
flake8-builtins
flake8-comprehensions
flake8-debugger
flake8-docstrings
flake8-eradicate
flake8-print
flake8-quotes
flake8-super
flake8-tidy-imports
(1/3)mccabe
Ruff can also replace isort
, yesqa
,
and a subset of the rules implemented in pyupgrade
(16/33).
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
Nope! Ruff is available as ruff
on PyPI:
pip install ruff
Ruff ships with wheels for all major platforms, which enables pip
to install Ruff without relying
on Rust at all.
Ruff does not yet support third-party plugins, though a plugin system is within-scope for the project. See #283 for more.
How does Ruff's import sorting compare to isort
?
Ruff's import sorting is intended to be nearly equivalent to isort
when used profile = "black"
.
(There are some minor differences in how Ruff and isort break ties between similar imports.)
Like isort
, Ruff's import sorting is compatible with Black.
Ruff is less configurable than isort
, but supports the known-first-party
, known-third-party
,
extra-standard-library
, and src
settings, like so:
[tool.ruff]
select = [
# Pyflakes
"F",
# Pycodestyle
"E",
"W",
# isort
"I001"
]
src = ["src", "tests"]
[tool.ruff.isort]
known-first-party = ["my_module1", "my_module2"]
Yes! To enable a specific docstring convention, start by enabling all pydocstyle
error codes, and
then selectively disabling based on your preferred convention.
For example, if you're coming from flake8-docstrings
, the following configuration is equivalent to
--docstring-convention=numpy
:
[tool.ruff]
extend-select = ["D"]
extend-ignore = [
"D107",
"D203",
"D212",
"D213",
"D402",
"D413",
"D415",
"D416",
"D417",
]
Similarly, the following is equivalent to --docstring-convention=google
:
[tool.ruff]
extend-select = ["D"]
extend-ignore = [
"D203",
"D204",
"D213",
"D215",
"D400",
"D404",
"D406",
"D407",
"D408",
"D409",
"D413",
]
Similarly, the following is equivalent to --docstring-convention=pep8
:
[tool.ruff]
extend-select = ["D"]
extend-ignore = [
"D203",
"D212",
"D213",
"D214",
"D215",
"D404",
"D405",
"D406",
"D407",
"D408",
"D409",
"D410",
"D411",
"D413",
"D415",
"D416",
"D417",
]
Ruff is written in Rust (1.65.0). You'll need to install the Rust toolchain for development.
Assuming you have cargo
installed, you can run:
cargo run resources/test/fixtures
For development, we use nightly Rust:
cargo +nightly fmt
cargo +nightly clippy
cargo +nightly test
Ruff is distributed on PyPI, and published via maturin
.
See: .github/workflows/release.yaml
.
First, clone CPython. It's a large and diverse Python codebase, which makes it a good target for benchmarking.
git clone --branch 3.10 https://github.com/python/cpython.git resources/test/cpython
Add this pyproject.toml
to the CPython directory:
[tool.ruff]
line-length = 88
extend-exclude = [
"Lib/lib2to3/tests/data/bom.py",
"Lib/lib2to3/tests/data/crlf.py",
"Lib/lib2to3/tests/data/different_encoding.py",
"Lib/lib2to3/tests/data/false_encoding.py",
"Lib/lib2to3/tests/data/py2_test_grammar.py",
"Lib/test/bad_coding2.py",
"Lib/test/badsyntax_3131.py",
"Lib/test/badsyntax_pep3120.py",
"Lib/test/encoded_modules/module_iso_8859_1.py",
"Lib/test/encoded_modules/module_koi8_r.py",
"Lib/test/test_fstring.py",
"Lib/test/test_grammar.py",
"Lib/test/test_importlib/test_util.py",
"Lib/test/test_named_expressions.py",
"Lib/test/test_patma.py",
"Lib/test/test_source_encoding.py",
"Tools/c-analyzer/c_parser/parser/_delim.py",
"Tools/i18n/pygettext.py",
"Tools/test2to3/maintest.py",
"Tools/test2to3/setup.py",
"Tools/test2to3/test/test_foo.py",
"Tools/test2to3/test2to3/hello.py",
]
Next, to benchmark the release build:
cargo build --release
hyperfine --ignore-failure --warmup 10 --runs 100 \
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
"./target/release/ruff ./resources/test/cpython/"
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
Time (mean ± σ): 297.4 ms ± 4.9 ms [User: 2460.0 ms, System: 67.2 ms]
Range (min … max): 287.7 ms … 312.1 ms 100 runs
Warning: Ignoring non-zero exit code.
Benchmark 2: ./target/release/ruff ./resources/test/cpython/
Time (mean ± σ): 79.6 ms ± 7.3 ms [User: 59.7 ms, System: 356.1 ms]
Range (min … max): 62.4 ms … 111.2 ms 100 runs
Warning: Ignoring non-zero exit code.
To benchmark against the ecosystem's existing tools:
hyperfine --ignore-failure --warmup 5 \
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
"pylint --recursive=y resources/test/cpython/" \
"pyflakes resources/test/cpython" \
"autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
"pycodestyle resources/test/cpython" \
"flake8 resources/test/cpython" \
"python -m scripts.run_flake8 resources/test/cpython"
In order, these evaluate:
- Ruff
- Pylint
- Pyflakes
- autoflake
- pycodestyle
- Flake8
- Flake8, with a hack to enable multiprocessing on macOS
(You can poetry install
from ./scripts
to create a working environment for the above.)
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
Time (mean ± σ): 297.9 ms ± 7.0 ms [User: 2436.6 ms, System: 65.9 ms]
Range (min … max): 289.9 ms … 314.6 ms 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 2: pylint --recursive=y resources/test/cpython/
Time (mean ± σ): 37.634 s ± 0.225 s [User: 36.728 s, System: 0.853 s]
Range (min … max): 37.201 s … 38.106 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 3: pyflakes resources/test/cpython
Time (mean ± σ): 40.950 s ± 0.449 s [User: 40.688 s, System: 0.229 s]
Range (min … max): 40.348 s … 41.671 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 4: autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython
Time (mean ± σ): 11.562 s ± 0.160 s [User: 107.022 s, System: 1.143 s]
Range (min … max): 11.417 s … 11.917 s 10 runs
Benchmark 5: pycodestyle resources/test/cpython
Time (mean ± σ): 67.428 s ± 0.985 s [User: 67.199 s, System: 0.203 s]
Range (min … max): 65.313 s … 68.496 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 6: flake8 resources/test/cpython
Time (mean ± σ): 116.099 s ± 1.178 s [User: 115.217 s, System: 0.845 s]
Range (min … max): 114.180 s … 117.724 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 7: python -m scripts.run_flake8 resources/test/cpython
Time (mean ± σ): 20.477 s ± 0.349 s [User: 142.372 s, System: 1.504 s]
Range (min … max): 20.107 s … 21.183 s 10 runs
Summary
'./target/release/ruff ./resources/test/cpython/ --no-cache' ran
38.81 ± 1.05 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
68.74 ± 1.99 times faster than 'python -m scripts.run_flake8 resources/test/cpython'
126.33 ± 3.05 times faster than 'pylint --recursive=y resources/test/cpython/'
137.46 ± 3.55 times faster than 'pyflakes resources/test/cpython'
226.35 ± 6.23 times faster than 'pycodestyle resources/test/cpython'
389.73 ± 9.92 times faster than 'flake8 resources/test/cpython'
A regular expression used to identify "dummy" variables, or those which should be ignored when evaluating (e.g.) unused-variable checks.
Default value: "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
(matches _
, __
, and _var
, but not _var_
)
Type: Regex
Example usage:
[tool.ruff]
# Only ignore variables named "_".
dummy_variable_rgx = "^_$"
A list of file patterns to exclude from linting.
Exclusions are based on globs, and can be either:
- Single-path patterns, like
.mypy_cache
(to exclude any directory named.mypy_cache
in the tree),foo.py
(to exclude any file namedfoo.py
), orfoo_*.py
(to exclude any file matchingfoo_*.py
). - Relative patterns, like
directory/foo.py
(to exclude that specific file) ordirectory/*.py
(to exclude any Python files indirectory
). Note that these paths are relative to the project root (e.g., the directory containing yourpyproject.toml
).
Note that you'll typically want to use extend_exclude
to modify the excluded
paths.
Default value: [".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]
Type: Vec<FilePattern>
Example usage:
[tool.ruff]
exclude = [".venv"]
A list of file patterns to omit from linting, in addition to those specified by exclude
.
Default value: []
Type: Vec<FilePattern>
Example usage:
[tool.ruff]
# In addition to the standard set of exclusions, omit all tests, plus a specific file.
extend-exclude = ["tests", "src/bad.py"]
A list of check code prefixes to ignore. Prefixes can specify exact checks (like F841
), entire
categories (like F
), or anything in between.
When breaking ties between enabled and disabled checks (via select
and ignore
, respectively),
more specific prefixes override less specific prefixes.
Default value: []
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# Skip unused variable checks (`F841`).
ignore = ["F841"]
A list of check code prefixes to ignore, in addition to those specified by ignore
.
Default value: []
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# Skip unused variable checks (`F841`).
extend-ignore = ["F841"]
A list of check code prefixes to enable. Prefixes can specify exact checks (like F841
), entire
categories (like F
), or anything in between.
When breaking ties between enabled and disabled checks (via select
and ignore
, respectively),
more specific prefixes override less specific prefixes.
Default value: ["E", "F"]
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# On top of the defaults (`E`, `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
select = ["E", "F", "B", "Q"]
A list of check code prefixes to enable, in addition to those specified by select
.
Default value: []
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# On top of the default `select` (`E`, `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
extend-select = ["B", "Q"]
A list of check codes that are unsupported by Ruff, but should be preserved when (e.g.)
validating # noqa
directives. Useful for retaining # noqa
directives that cover plugins not
yet implemented in Ruff.
Default value: []
Type: Vec<String>
Example usage:
[tool.ruff]
# Avoiding flagging (and removing) `V101` from any `# noqa` directives, despite Ruff's lack of
# support for `vulture`.
external = ["V101"]
Enable autofix behavior by-default when running ruff
(overridden by the --fix
and --no-fix
command-line flags).
Default value: false
Type: bool
Example usage:
[tool.ruff]
fix = true
A list of check code prefixes to consider autofix-able.
Default value: ["A", "ANN", "B", "BLE", "C", "D", "E", "F", "FBT", "I", "M", "N", "Q", "RUF", "S", "T", "U", "W", "YTT"]
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# Only allow autofix behavior for `E` and `F` checks.
fixable = ["E", "F"]
A list of check code prefixes to consider un-autofix-able.
Default value: []
Type: Vec<CheckCodePrefix>
Example usage:
[tool.ruff]
# Disable autofix for unused imports (`F401`).
unfixable = ["F401"]
The line length to use when enforcing long-lines violations (like E501).
Default value: 88
Type: usize
Example usage:
[tool.ruff]
# Allow lines to be as long as 120 characters.
line-length = 120
A list of mappings from file pattern to check code prefixes to exclude, when considering any matching files.
Default value: {}
Type: HashMap<String, Vec<CheckCodePrefix>>
Example usage:
[tool.ruff]
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402"]
"path/to/file.py" = ["E402"]
Whether to show source code snippets when reporting lint error violations (overridden by the
--show-source
command-line flag).
Default value: false
Type: bool
Example usage:
[tool.ruff]
# By default, always show source code snippets.
show_source = true
The source code paths to consider, e.g., when resolving first- vs. third-party imports.
Default value: ["."]
Type: Vec<PathBuf>
Example usage:
[tool.ruff]
# Allow imports relative to the "src" and "test" directories.
src = ["src", "test"]
The Python version to target, e.g., when considering automatic code upgrades, like rewriting type annotations. Note that the target version will not be inferred from the current Python version, and instead must be specified explicitly (as seen below).
Default value: "py310"
Type: PythonVersion
Example usage:
[tool.ruff]
# Always generate Python 3.7-compatible code.
target-version = "py37"
Whether to allow the omission of a return type hint for __init__
if at least one argument is
annotated.
Default value: false
Type: bool
Example usage:
[tool.ruff.flake8-annotations]
mypy_init_return = true
Whether to suppress ANN000
-level errors for arguments matching the "dummy" variable regex (like
_
).
Default value: false
Type: bool
Example usage:
[tool.ruff.flake8-annotations]
suppress_dummy_args = true
Whether to suppress ANN200
-level errors for functions that meet either of the following criteria:
- Contain no
return
statement. - Explicit
return
statement(s) all returnNone
(explicitly or implicitly).
Default value: false
Type: bool
Example usage:
[tool.ruff.flake8-annotations]
suppress_none_returning = true
Whether to suppress ANN401
for dynamically typed *args
and **kwargs
arguments.
Default value: false
Type: bool
Example usage:
[tool.ruff.flake8-annotations]
allow_star_arg_any = true
Additional callable functions to consider "immutable" when evaluating, e.g., no-mutable-default-argument
checks (B006
).
Default value: []
Type: Vec<String>
Example usage:
[tool.ruff.flake8-bugbear]
# Allow default arguments like, e.g., `data: List[str] = fastapi.Query(None)`.
extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]
Quote style to prefer for inline strings (either "single" ('
) or "double" ("
)).
Default value: "double"
Type: Quote
Example usage:
[tool.ruff.flake8-quotes]
inline-quotes = "single"
Quote style to prefer for multiline strings (either "single" ('
) or "double" ("
)).
Default value: "double"
Type: Quote
Example usage:
[tool.ruff.flake8-quotes]
multiline-quotes = "single"
Quote style to prefer for docstrings (either "single" ('
) or "double" ("
)).
Default value: "double"
Type: Quote
Example usage:
[tool.ruff.flake8-quotes]
docstring-quotes = "single"
Whether to avoid using single quotes if a string contains single quotes, or vice-versa with double quotes, as per PEP8. This minimizes the need to escape quotation marks within strings.
Default value: true
Type: bool
Example usage:
[tool.ruff.flake8-quotes]
# Don't bother trying to avoid escapes.
avoid-escape = false
Whether to ban all relative imports ("all"
), or only those imports that extend into the parent
module and beyond ("parents"
).
Default value: "parents"
Type: Strictness
Example usage:
[tool.ruff.flake8-tidy-imports]
# Disallow all relative imports.
ban-relative-imports = "all"
A list of modules to consider first-party, regardless of whether they can be identified as such via introspection of the local filesystem.
Default value: []
Type: Vec<String>
Example usage:
[tool.ruff.isort]
known-first-party = ["src"]
A list of modules to consider third-party, regardless of whether they can be identified as such via introspection of the local filesystem.
Default value: []
Type: Vec<String>
Example usage:
[tool.ruff.isort]
known-third-party = ["fastapi"]
A list of modules to consider standard-library, in addition to those known to Ruff in advance.
Default value: []
Type: Vec<String>
Example usage:
[tool.ruff.isort]
extra-standard-library = ["path"]
The maximum McCabe complexity to allow before triggering C901
errors.
Default value: 10
Type: usize
Example usage:
[tool.ruff.flake8-tidy-imports]
# Flag errors (`C901`) whenever the complexity level exceeds 5.
max-complexity = 5
A list of names to ignore when considering pep8-naming
violations.
Default value: ["setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule", "asyncSetUp", "asyncTearDown", "setUpTestData", "failureException", "longMessage", "maxDiff"]
Type: Vec<String>
Example usage:
[tool.ruff.pep8-naming]
ignore-names = ["callMethod"]
A list of decorators that, when applied to a method, indicate that the method should be treated as
a class method. For example, Ruff will expect that any method decorated by a decorator in this list
takes a cls
argument as its first argument.
Default value: ["classmethod"]
Type: Vec<String>
Example usage:
[tool.ruff.pep8-naming]
# Allow Pydantic's `@validator` decorator to trigger class method treatment.
classmethod-decorators = ["classmethod", "pydantic.validator"]
A list of decorators that, when applied to a method, indicate that the method should be treated as
a static method. For example, Ruff will expect that any method decorated by a decorator in this list
has no self
or cls
argument.
Default value: ["staticmethod"]
Type: Vec<String>
Example usage:
[tool.ruff.pep8-naming]
# Allow a shorthand alias, `@stcmthd`, to trigger static method treatment.
staticmethod-decorators = ["staticmethod", "stcmthd"]
MIT
Contributions are welcome and hugely appreciated. To get started, check out the contributing guidelines.