# Ruff [![image](https://img.shields.io/pypi/v/ruff.svg)](https://pypi.python.org/pypi/ruff) [![image](https://img.shields.io/pypi/l/ruff.svg)](https://pypi.python.org/pypi/ruff) [![image](https://img.shields.io/pypi/pyversions/ruff.svg)](https://pypi.python.org/pypi/ruff) [![Actions status](https://github.com/charliermarsh/ruff/workflows/CI/badge.svg)](https://github.com/charliermarsh/ruff/actions) 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.11 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](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set - πŸ”Œ Native re-implementations of popular Flake8 plugins, like [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) - 🌎 Monorepo-friendly configuration via hierarchical and cascading settings 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`](https://pypi.org/project/isort/), [`pydocstyle`](https://pypi.org/project/pydocstyle/), [`yesqa`](https://github.com/asottile/yesqa), [`eradicate`](https://pypi.org/project/eradicate/), and even a subset of [`pyupgrade`](https://pypi.org/project/pyupgrade/) and [`autoflake`](https://pypi.org/project/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: - [FastAPI](https://github.com/tiangolo/fastapi) - [Bokeh](https://github.com/bokeh/bokeh) - [Zulip](https://github.com/zulip/zulip) - [Pydantic](https://github.com/pydantic/pydantic) - [Hatch](https://github.com/pypa/hatch) - [Jupyter](https://github.com/jupyter-server/jupyter_server) - [Synapse](https://github.com/matrix-org/synapse) - [Ibis](https://github.com/ibis-project/ibis) - [Saleor](https://github.com/saleor/saleor) Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster). ## Testimonials [**SebastiΓ‘n RamΓ­rez**](https://twitter.com/tiangolo/status/1591912354882764802), creator of [FastAPI](https://github.com/tiangolo/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**](https://github.com/bokeh/bokeh/pull/12605), co-creator of [Bokeh](https://github.com/bokeh/bokeh/), original author of [Conda](https://docs.conda.io/en/latest/): > 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**](https://github.com/charliermarsh/ruff/issues/465#issuecomment-1317400028), lead developer of [Zulip](https://github.com/zulip/zulip): > This is just ridiculously fast... `ruff` is amazing. ## Table of Contents 1. [Installation and Usage](#installation-and-usage) 1. [Configuration](#configuration) 1. [Supported Rules](#supported-rules) 1. [Pyflakes (F)](#pyflakes-f) 1. [pycodestyle (E, W)](#pycodestyle-e-w) 1. [mccabe (C90)](#mccabe-c90) 1. [isort (I)](#isort-i) 1. [pydocstyle (D)](#pydocstyle-d) 1. [pyupgrade (UP)](#pyupgrade-up) 1. [pep8-naming (N)](#pep8-naming-n) 1. [flake8-2020 (YTT)](#flake8-2020-ytt) 1. [flake8-annotations (ANN)](#flake8-annotations-ann) 1. [flake8-bandit (S)](#flake8-bandit-s) 1. [flake8-blind-except (BLE)](#flake8-blind-except-ble) 1. [flake8-boolean-trap (FBT)](#flake8-boolean-trap-fbt) 1. [flake8-bugbear (B)](#flake8-bugbear-b) 1. [flake8-builtins (A)](#flake8-builtins-a) 1. [flake8-comprehensions (C4)](#flake8-comprehensions-c4) 1. [flake8-debugger (T10)](#flake8-debugger-t10) 1. [flake8-errmsg (EM)](#flake8-errmsg-em) 1. [flake8-import-conventions (ICN)](#flake8-import-conventions-icn) 1. [flake8-print (T20)](#flake8-print-t20) 1. [flake8-quotes (Q)](#flake8-quotes-q) 1. [flake8-return (RET)](#flake8-return-ret) 1. [flake8-simplify (SIM)](#flake8-simplify-sim) 1. [flake8-tidy-imports (TID)](#flake8-tidy-imports-tid) 1. [flake8-unused-arguments (ARG)](#flake8-unused-arguments-arg) 1. [flake8-datetimez (DTZ)](#flake8-datetimez-dtz) 1. [eradicate (ERA)](#eradicate-era) 1. [pandas-vet (PD)](#pandas-vet-pd) 1. [pygrep-hooks (PGH)](#pygrep-hooks-pgh) 1. [Pylint (PLC, PLE, PLR, PLW)](#pylint-plc-ple-plr-plw) 1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf) 1. [Editor Integrations](#editor-integrations) 1. [FAQ](#faq) 1. [Development](#development) 1. [Releases](#releases) 1. [Benchmarks](#benchmarks) 1. [Reference](#reference) 1. [License](#license) 1. [Contributing](#contributing) ## Installation and Usage ### Installation Ruff is available as [`ruff`](https://pypi.org/project/ruff/) on PyPI: ```shell pip install ruff ``` [![Packaging status](https://repology.org/badge/vertical-allrepos/ruff-python-linter.svg?exclude_unsupported=1)](https://repology.org/project/ruff-python-linter/versions) For **macOS Homebrew** and **Linuxbrew** users, Ruff is also available as [`ruff`](https://formulae.brew.sh/formula/ruff) on Homebrew: ```shell brew install ruff ``` For **Conda** users, Ruff is also available as [`ruff`](https://anaconda.org/conda-forge/ruff) on `conda-forge`: ```shell conda install -c conda-forge ruff ``` For **Arch Linux** users, Ruff is also available as [`ruff`](https://archlinux.org/packages/community/x86_64/ruff/) on the official repositories: ```shell pacman -S ruff ``` ### Usage To run Ruff, try any of the following: ```shell 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: ```shell ruff path/to/code/ --watch ``` Ruff also works with [pre-commit](https://pre-commit.com): ```yaml - repo: https://github.com/charliermarsh/ruff-pre-commit # Ruff version. rev: 'v0.0.195' hooks: - id: ruff # Respect `exclude` and `extend-exclude` settings. args: ["--force-exclude"] ``` ## Configuration Ruff is configurable both via `pyproject.toml` and the command line. For a full list of configurable options, see the [API reference](#reference). If left unspecified, the default configuration is equivalent to: ```toml [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: ```toml [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.: ```toml [tool.ruff] # Add "Q" to the list of enabled codes. select = ["E", "F", "Q"] [tool.ruff.flake8-quotes] docstring-quotes = "double" ``` As an alternative to `pyproject.toml`, Ruff will also respect a `ruff.toml` file, which implements an equivalent schema (though the `[tool.ruff]` hierarchy can be omitted). For example, the above `pyproject.toml` described above would be represented via the following `ruff.toml`: ```toml # 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`. [per-file-ignores] "__init__.py" = ["E402"] "path/to/file.py" = ["E402"] ``` For a full list of configurable options, see the [API reference](#reference). Some common configuration settings can be provided via the command-line: ```shell ruff path/to/code/ --select F401 --select F403 ``` See `ruff --help` for more: ```shell Ruff: An extremely fast Python linter. Usage: ruff [OPTIONS] [FILES]... Arguments: [FILES]... Options: --config Path to the `pyproject.toml` or `ruff.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 --fix-only Fix any fixable lint errors, but don't report on leftover violations. Implies `--fix` -n, --no-cache Disable cache reads --select