Skip to main content

An extremely fast Python linter, written in Rust.

Project description

Ruff

image image image Actions status

An extremely fast Python linter, written in Rust.

Bar chart with benchmark results

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 goes beyond the responsibilities of a traditional linter, instead functioning as an advanced code transformation tool capable of upgrading type annotations, rewriting class definitions, sorting imports, and more.

Ruff is extremely actively developed and used in major open-source projects like:

Read the launch blog post.

Testimonials

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.

Table of Contents

  1. Installation and Usage
  2. Configuration
  3. Supported Rules
    1. Pyflakes (F)
    2. pycodestyle (E, W)
    3. mccabe (C90)
    4. isort (I)
    5. pydocstyle (D)
    6. pyupgrade (UP)
    7. pep8-naming (N)
    8. flake8-2020 (YTT)
    9. flake8-annotations (ANN)
    10. flake8-bandit (S)
    11. flake8-blind-except (BLE)
    12. flake8-boolean-trap (FBT)
    13. flake8-bugbear (B)
    14. flake8-builtins (A)
    15. flake8-comprehensions (C4)
    16. flake8-debugger (T10)
    17. flake8-print (T20)
    18. flake8-quotes (Q)
    19. flake8-return (RET)
    20. flake8-tidy-imports (I25)
    21. eradicate (ERA)
    22. pygrep-hooks (PGH)
    23. Pylint (PL)
    24. Ruff-specific rules (RUF)
  4. Editor Integrations
  5. FAQ
  6. Development
  7. Releases
  8. Benchmarks
  9. Reference
  10. License
  11. Contributing

Installation and Usage

Installation

Ruff is available as ruff on PyPI:

pip install ruff

For macOS Homebrew and Linuxbrew users, Ruff is also available as ruff on Homebrew:

brew install ruff

For Conda users, Ruff is also available as ruff on conda-forge:

conda install -c conda-forge ruff

Usage

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.158
    hooks:
      - id: ruff

Configuration

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, junit, grouped]
      --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
      --explain <EXPLAIN>
          Explain a rule
  -h, --help
          Print help information
  -V, --version
          Print version information

Ignoring errors

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 inline, 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 string, 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

To ignore all errors across an entire file, Ruff supports Flake8's # flake8: noqa directive (or, equivalently, # ruff: noqa). Adding either of those directives to any part of a file will disable error reporting for the entire file.

For targeted exclusions across entire files (e.g., "Ignore all F841 violations in /path/to/file.py"), see the per-file-ignores configuration setting.

Automating noqa Directives

Ruff supports several workflows to aid in noqa management.

First, Ruff provides a special error code, RUF100, 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 RUF100 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 RUF100 --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.

Supported Rules

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.

Pyflakes

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 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 🛠

pycodestyle

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'

mccabe

For more, see mccabe on PyPI.

Code Name Message Fix
C901 FunctionIsTooComplex ... is too complex (10)

isort

For more, see isort on PyPI.

Code Name Message Fix
I001 UnsortedImports Import block is un-sorted or un-formatted 🛠

pydocstyle

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

pyupgrade

For more, see pyupgrade on PyPI.

Code Name Message Fix
UP001 UselessMetaclassType __metaclass__ = type is implied 🛠
UP003 TypeOfPrimitive Use str instead of type(...) 🛠
UP004 UselessObjectInheritance Class ... inherits from object 🛠
UP005 DeprecatedUnittestAlias assertEquals is deprecated, use assertEqual instead 🛠
UP006 UsePEP585Annotation Use list instead of List for type annotations 🛠
UP007 UsePEP604Annotation Use X | Y for type annotations 🛠
UP008 SuperCallWithParameters Use super() instead of super(__class__, self) 🛠
UP009 PEP3120UnnecessaryCodingComment UTF-8 encoding declaration is unnecessary 🛠
UP010 UnnecessaryFutureImport Unnecessary __future__ import ... for target Python version 🛠
UP011 UnnecessaryLRUCacheParams Unnecessary parameters to functools.lru_cache 🛠
UP012 UnnecessaryEncodeUTF8 Unnecessary call to encode as UTF-8 🛠
UP013 ConvertTypedDictFunctionalToClass Convert ... from TypedDict functional to class syntax 🛠
UP014 ConvertNamedTupleFunctionalToClass Convert ... from NamedTuple functional to class syntax 🛠
UP015 RedundantOpenModes Unnecessary open mode parameters 🛠

pep8-naming

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

flake8-2020

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

flake8-annotations

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 ...

flake8-bandit

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: "..."

flake8-blind-except

For more, see flake8-blind-except on PyPI.

Code Name Message Fix
BLE001 BlindExcept Blind except Exception: statement

flake8-boolean-trap

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

flake8-bugbear

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

flake8-builtins

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

flake8-comprehensions

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)

flake8-debugger

For more, see flake8-debugger on PyPI.

Code Name Message Fix
T100 Debugger Import for ... found

flake8-print

For more, see flake8-print on PyPI.

Code Name Message Fix
T201 PrintFound print found 🛠
T203 PPrintFound pprint found 🛠

flake8-quotes

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

flake8-return

For more, see flake8-return on PyPI.

Code Name Message Fix
RET501 UnnecessaryReturnNone Do not explicitly return None in function if it is the only possible return value 🛠
RET502 ImplicitReturnValue Do not implicitly return None in function able to return non-None value 🛠
RET503 ImplicitReturn Missing explicit return at the end of function able to return non-None value 🛠
RET504 UnnecessaryAssign Unnecessary variable assignment before return statement
RET505 SuperfluousElseReturn Unnecessary else after return statement
RET506 SuperfluousElseRaise Unnecessary else after raise statement
RET507 SuperfluousElseContinue Unnecessary else after continue statement
RET508 SuperfluousElseBreak Unnecessary else after break statement

flake8-tidy-imports

For more, see flake8-tidy-imports on PyPI.

Code Name Message Fix
I252 BannedRelativeImport Relative imports are banned

eradicate

For more, see eradicate on PyPI.

Code Name Message Fix
ERA001 CommentedOutCode Found commented-out code 🛠

pygrep-hooks

For more, see pygrep-hooks on GitHub.

Code Name Message Fix
PGH001 NoEval No builtin eval() allowed

Pylint

For more, see Pylint on PyPI.

Code Name Message Fix
PLC0414 UselessImportAlias Import alias does not rename original package 🛠
PLC2201 MisplacedComparisonConstant Comparison should be ... 🛠
PLC3002 UnnecessaryDirectLambdaCall Lambda expression called directly. Execute the expression inline instead.
PLE1142 AwaitOutsideAsync await should be used within an async function
PLR0206 PropertyWithParameters Cannot have defined parameters for properties
PLR0402 ConsiderUsingFromImport Consider using from ... import ...
PLR1701 ConsiderMergingIsinstance Consider merging these isinstance calls: isinstance(..., (...))
PLR1722 ConsiderUsingSysExit Consider using sys.exit() 🛠
PLW0120 UselessElseOnLoop Else clause on loop without a break statement, remove the else and de-indent all the code inside it

Ruff-specific rules

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'?)
RUF100 UnusedNOQA Unused noqa directive 🛠

Editor Integrations

VS Code (Official)

Download the Ruff VS Code extension.

PyCharm

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:

Install Ruff as an External Tool

Ruff should then appear as a runnable action:

Ruff as a runnable action

Vim & Neovim (Unofficial)

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,
    }
})

Language Server Protocol (Unofficial)

ruffd is a Rust-based language server for Ruff that implements the Language Server Protocol (LSP).

GitHub Actions

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 .

FAQ

Is Ruff compatible with Black?

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.

How does Ruff compare to Flake8?

(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:

Beyond the rule set, Ruff suffers from the following limitations vis-à-vis Flake8:

  1. Ruff does not yet support a few Python 3.9 and 3.10 language features, including structural pattern matching and parenthesized context managers.
  2. 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.)

How does Ruff compare to Pylint?

At time of writing, Pylint implements 409 total rules, while Ruff implements 224, of which at least 60 overlap with the Pylint rule set. Subjectively, Pylint tends to implement more rules based on type inference (e.g., validating the number of arguments in a function call).

Like Flake8, Pylint supports plugins (called "checkers"), while Ruff implements all checks natively.

Unlike Pylint, Ruff is capable of automatically fixing its own lint errors.

Pylint parity is being tracked in #689.

Which tools does Ruff replace?

Today, Ruff can be used to replace Flake8 when used with any of the following plugins:

Ruff can also replace isort, yesqa, eradicate, pygrep-hooks (1/10), 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.

Do I need to install Rust to use Ruff?

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.

Can I write my own plugins for Ruff?

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"]

Does Ruff support NumPy- or Google-style docstrings?

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",
]

Development

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

Releases

Ruff is distributed on PyPI, and published via maturin.

See: .github/workflows/release.yaml.

Benchmarks

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'

Reference

Options

exclude

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 named foo.py), or foo_*.py (to exclude any file matching foo_*.py ).
  • Relative patterns, like directory/foo.py (to exclude that specific file) or directory/*.py (to exclude any Python files in directory). Note that these paths are relative to the project root (e.g., the directory containing your pyproject.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"]

extend-exclude

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"]

ignore

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"]

extend-ignore

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"]

select

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"]

extend-select

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"]

external

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"]

fix

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

fixable

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"]

unfixable

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"]

line-length

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

dummy-variable-rgx

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 = "^_$"

ignore-init-module-imports

Avoid automatically removing unused imports in __init__.py files. Such imports will still be flagged, but with a dedicated message suggesting that the import is either added to the module's __all__ symbol, or re-exported with a redundant alias (e.g., import os as os).

Default value: false

Type: bool

Example usage:

[tool.ruff]
ignore-init-module-imports = true

format

The style in which violation messages should be formatted: "text" (default), "grouped" (group messages by file), "json" (machine-readable), "junit" (machine-readable XML), or "github" (GitHub Actions annotations).

Default value: "text"

Type: SerializationFormat

Example usage:

[tool.ruff]
# Group violations by containing file.
format = "grouped"

per-file-ignores

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"]

show-source

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

src

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"]

target-version

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"

flake8-annotations

mypy-init-return

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

suppress-dummy-args

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

suppress-none-returning

Whether to suppress ANN200-level errors for functions that meet either of the following criteria:

  • Contain no return statement.
  • Explicit return statement(s) all return None (explicitly or implicitly).

Default value: false

Type: bool

Example usage:

[tool.ruff.flake8-annotations]
suppress-none-returning = true

allow-star-arg-any

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

flake8-bugbear

extend-immutable-calls

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"]

flake8-quotes

inline-quotes

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"

multiline-quotes

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"

docstring-quotes

Quote style to prefer for docstrings (either "single" (') or "double" (")).

Default value: "double"

Type: Quote

Example usage:

[tool.ruff.flake8-quotes]
docstring-quotes = "single"

avoid-escape

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

flake8-tidy-imports

ban-relative-imports

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"

isort

known-first-party

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"]

known-third-party

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"]

extra-standard-library

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"]

combine-as-imports

Combines as imports on the same line. See isort's combine-as-imports option.

Default value: false

Type: bool

Example usage:

[tool.ruff.isort]
combine-as-imports = true

force-wrap-aliases

Force import from statements with multiple members and at least one alias (e.g., import A as B) to wrap such that every line contains exactly one member. For example, this formatting would be retained, rather than condensing to a single line:

from .utils import (
    test_directory as test_directory,
    test_id as test_id
)

Default value: false

Type: bool

Example usage:

[tool.ruff.isort]
force-wrap-aliases = true

mccabe

max-complexity

The maximum McCabe complexity to allow before triggering C901 errors.

Default value: 10

Type: usize

Example usage:

[tool.ruff.mccabe]
# Flag errors (`C901`) whenever the complexity level exceeds 5.
max-complexity = 5

pep8-naming

ignore-names

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"]

classmethod-decorators

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"]

staticmethod-decorators

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"]

pyupgrade

keep-runtime-typing

Whether to avoid PEP 585 (List[int] -> list[int]) and PEP 604 (Optional[str] -> str | None) rewrites even if a file imports from __future__ import annotations. Note that this setting is only applicable when the target Python version is below 3.9 and 3.10 respectively.

Default value: false

Type: bool

Example usage:

[tool.ruff.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true

License

MIT

Contributing

Contributions are welcome and hugely appreciated. To get started, check out the contributing guidelines.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ruff-0.0.158.tar.gz (358.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ruff-0.0.158-py3-none-win_amd64.whl (3.5 MB view details)

Uploaded Python 3Windows x86-64

ruff-0.0.158-py3-none-win32.whl (3.3 MB view details)

Uploaded Python 3Windows x86

ruff-0.0.158-py3-none-musllinux_1_2_x86_64.whl (3.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

ruff-0.0.158-py3-none-musllinux_1_2_i686.whl (3.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ i686

ruff-0.0.158-py3-none-musllinux_1_2_armv7l.whl (3.3 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

ruff-0.0.158-py3-none-musllinux_1_2_aarch64.whl (3.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

ruff-0.0.158-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

ruff-0.0.158-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (3.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ s390x

ruff-0.0.158-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (3.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

ruff-0.0.158-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl (3.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64

ruff-0.0.158-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl (3.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ i686

ruff-0.0.158-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

ruff-0.0.158-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

ruff-0.0.158-py3-none-macosx_10_9_x86_64.macosx_10_9_arm64.macosx_10_9_universal2.whl (7.0 MB view details)

Uploaded Python 3macOS 10.9+ ARM64macOS 10.9+ universal2 (ARM64, x86-64)macOS 10.9+ x86-64

ruff-0.0.158-py3-none-macosx_10_7_x86_64.whl (3.7 MB view details)

Uploaded Python 3macOS 10.7+ x86-64

File details

Details for the file ruff-0.0.158.tar.gz.

File metadata

  • Download URL: ruff-0.0.158.tar.gz
  • Upload date:
  • Size: 358.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for ruff-0.0.158.tar.gz
Algorithm Hash digest
SHA256 1948df71d1f941e0a8097a8cc4bfdd5dc833658b5399b8f0ad1c16289245c17b
MD5 67a2eb2c6c7181ba4c42595a85a8c5bb
BLAKE2b-256 28781274ee1ec9789661bf754d81575316c7553bfd9101cd8659056bbf1fa88b

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-win_amd64.whl.

File metadata

  • Download URL: ruff-0.0.158-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for ruff-0.0.158-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 88c09d99a6c6cd3edbdcd337e0554d86a4e692efb401282d0fcb99e531ea0060
MD5 fc550988ebe012af21d285e236791f41
BLAKE2b-256 218c4edc6b3dd7d40b9c60ae3339db7f47297e420e05c3d12546d770db5fa25c

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-win32.whl.

File metadata

  • Download URL: ruff-0.0.158-py3-none-win32.whl
  • Upload date:
  • Size: 3.3 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.6

File hashes

Hashes for ruff-0.0.158-py3-none-win32.whl
Algorithm Hash digest
SHA256 9c1a4bf0f21735470eede9a2034abc75d628cc8e94438fbc6ea1c98416e8f27a
MD5 37e084a92561a9f1b7715074a94949a1
BLAKE2b-256 9d613495867fc1b3fcfd3062f647e8747fecfb9107159ad1cb8151cc46a5db7d

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2659e157931c70cf2029695b32483a5e28ce2733e58a1f3b8bc8d13ccdc5f0b6
MD5 1d364fd8aa9e87881598c8fa0dc0e5f8
BLAKE2b-256 066b660422398f75d637226a049c078b9c65167f3d58ea9da512e011892cd7d4

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 dcd0282c5d393e6ed731c2901710169d32f862ceabb5d8f9d4988da42adadb55
MD5 e20b3f874f4ebd20d30a8b4498fd504d
BLAKE2b-256 5234aeee7a3f51d4a3654fb765027397d46118fb0778277af5c963032662cc30

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 6d9e283ccdb913e6925754a4f283aed887223c28e307392633c5c95b18360aef
MD5 bd3ef2fc9a0a9bbae5d7b41ca00c2b5d
BLAKE2b-256 b1db271ed7aaea1806587f5bcaab7a85e38fa31de04c69aaea15754ccb9cff07

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 e5f223df71eb3a8a46acd6ba66cb00cee028bb1c17a750fe228bb0d819d9c0bc
MD5 903c57307770e4f00e1e689a2f4c4511
BLAKE2b-256 f744bc6a84bf0c338589b544c65070d8b318dfbf33bdc14d53d1fe13196f9748

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d073b22ea8677db948819425124ae0febcd584a5c777517cb9f48b46b531ff49
MD5 806a165abe050cc614998cadc79f6954
BLAKE2b-256 3931d1f3740a88aac0e2db34e51382c5b7bf0bcebb817a0a18f020bdfd904dbe

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 b36bd185997d9b09d472294522d0b5858e6424fbd1240907f60484e500af44c6
MD5 8793b7885027f2049e0f6d883e25b4e5
BLAKE2b-256 f2f149f9d868a0982263b2f8a8aff20256f7b4537e62444856bba97acbd79cc3

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 95c3265cbcd24c5a625319395aa1e502d9624999e8f04aa366bad9a9f97dc963
MD5 ba648cd24a4697af81404b55115d308d
BLAKE2b-256 abb7cf628974b0e2a9cd31b3dd7ae054af14a138e590d1e746fc7bbcce613ad5

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 8f6ed4e2827179204108f20236d09621a7b1cf465bbd8bb3dbcb0116892d4734
MD5 8f504a6e584628c48c313fdc627bb874
BLAKE2b-256 44617b838fb75da10b686289fdce55d073a4bbf7eabbee5ffb263c34aae31c9e

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 1fbd6cb15e35de95ea1ed4eb8f0e3fca8bd0d993289bdf564a67f8a038189c46
MD5 9eb53504c2d171d44f96d4d7144ac293
BLAKE2b-256 8568fdd50dcb546602a6fe8ffbed652bd3a79859c329afbcb005f81de1eacffe

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 efaa7bbb4d8b101f89b2ff4df755461d1f3e87a7c0785a5c16ac02f80608dd00
MD5 9a26e4f12f366510bdef5a11c49412fa
BLAKE2b-256 40f4835eede5887e2bd8b084e7280d71fa8821136e18a9e0b6dd52b1d0146c5e

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f09c35023aa6cf74e7d04ebb5a05cbbcd027f92f3bf2e1b8fe7ac554ba73a064
MD5 b5e0dc939ad23c339c81cc1a9a3dba17
BLAKE2b-256 19aacc336206e83518ba9d1121f138282a189187c265986920a2cc954f75a9d4

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-macosx_10_9_x86_64.macosx_10_9_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-macosx_10_9_x86_64.macosx_10_9_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 8f9231f0fd927431f77203916e5a7cdbab7a31b95ed1cd384011e965aef4644c
MD5 fe45acc01835eb0560262a0a8ea32cca
BLAKE2b-256 b056584f447f49b30af4cf7ddc26d249ec075b2a8f14ef530b6b6ad0d41d8e50

See more details on using hashes here.

File details

Details for the file ruff-0.0.158-py3-none-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.158-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 84840fe4754f0831b1c5815da71f3293b7707a3aa2003257fcb8d33af5140161
MD5 58d7b7712e3ffec6931ccc35ceaf9940
BLAKE2b-256 463e80f656a0cdafb043b21a2241be6ec855babea5b040741e804890f97f2282

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page