Skip to main content

An extremely fast Python linter, written in Rust.

Project description

ruff

Actions status PyPI version

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
  • 📦 ESLint-inspired cache semantics
  • 👀 TypeScript-inspired --watch semantics

ruff is a proof-of-concept and not yet intended for production use. It supports only a small subset of the Flake8 rules, and may crash on your codebase.

Read the launch blog post.

Installation and usage

Installation

Available as ruff on PyPI:

pip install 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

Configuration

ruff is configurable both via pyproject.toml and the command line.

For example, you could configure ruff to only enforce a subset of rules with:

[tool.ruff]
line-length = 88
select = [
    "F401",
    "F403",
]

Alternatively, on the command-line:

ruff path/to/code/ --select F401 F403

See ruff --help for more:

ruff
An extremely fast Python linter.

USAGE:
    ruff [OPTIONS] <FILES>...

ARGS:
    <FILES>...

OPTIONS:
    -e, --exit-zero             Exit with status code "0", even upon detecting errors
    -h, --help                  Print help information
        --ignore <IGNORE>...    Comma-separated list of error codes to ignore
    -n, --no-cache              Disable cache reads
    -q, --quiet                 Disable all logging (but still exit with status code "1" upon
                                detecting errors)
        --select <SELECT>...    Comma-separated list of error codes to enable
    -v, --verbose               Enable verbose logging
    -w, --watch                 Run in watch mode by re-running whenever files change

Development

ruff is written in Rust (1.63.0). You'll need to install the Rust toolchain for development.

Assuming you have cargo installed, you can run:

cargo run resources/test/src
cargo fmt
cargo clippy
cargo test

Deployment

ruff is distributed on PyPI, and published via maturin.

See: .github/workflows/release.yaml.

Benchmarking

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.linter]
line-length = 88
exclude = [
    "Lib/ctypes/test/test_numbers.py",
    "Lib/dataclasses.py",
    "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/sqlite3/test/factory.py",
    "Lib/sqlite3/test/hooks.py",
    "Lib/sqlite3/test/regression.py",
    "Lib/sqlite3/test/transactions.py",
    "Lib/sqlite3/test/types.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/sortperf.py",
    "Lib/test/test_email/torture_test.py",
    "Lib/test/test_fstring.py",
    "Lib/test/test_genericpath.py",
    "Lib/test/test_getopt.py",
    "Lib/test/test_grammar.py",
    "Lib/test/test_htmlparser.py",
    "Lib/test/test_importlib/stubs.py",
    "Lib/test/test_importlib/test_files.py",
    "Lib/test/test_importlib/test_metadata_api.py",
    "Lib/test/test_importlib/test_open.py",
    "Lib/test/test_importlib/test_util.py",
    "Lib/test/test_named_expressions.py",
    "Lib/test/test_patma.py",
    "Lib/test/test_peg_generator/__main__.py",
    "Lib/test/test_pipes.py",
    "Lib/test/test_source_encoding.py",
    "Lib/test/test_weakref.py",
    "Lib/test/test_webbrowser.py",
    "Lib/tkinter/__main__.py",
    "Lib/tkinter/test/test_tkinter/test_variables.py",
    "Modules/_decimal/libmpdec/literature/fnt.py",
    "Modules/_decimal/tests/deccheck.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 1 \
  "./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 ± σ):     353.6 ms ±   7.6 ms    [User: 2868.8 ms, System: 171.5 ms]
  Range (min  max):   344.4 ms  367.3 ms    10 runs

Benchmark 2: ./target/release/ruff ./resources/test/cpython/
  Time (mean ± σ):      59.6 ms ±   2.5 ms    [User: 36.4 ms, System: 345.6 ms]
  Range (min  max):    55.9 ms   67.0 ms    48 runs

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" \
  "pycodestyle --select E501 resources/test/cpython" \
  "flake8 resources/test/cpython" \
  "flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython" \
  "python -m scripts.run_flake8 resources/test/cpython" \
  "python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501"

In order, these evaluate:

  • ruff
  • Pylint
  • PyFlakes
  • autoflake
  • pycodestyle
  • pycodestyle, limited to the checks supported by ruff
  • Flake8
  • Flake8, limited to the checks supported by ruff
  • Flake8, with a hack to enable multiprocessing on macOS
  • Flake8, with a hack to enable multiprocessing on macOS, limited to the checks supported by ruff

(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 ± σ):     469.3 ms ±  16.3 ms    [User: 2663.0 ms, System: 972.5 ms]
  Range (min  max):   445.2 ms  494.8 ms    10 runs

Benchmark 2: pylint --recursive=y resources/test/cpython/
  Time (mean ± σ):     27.211 s ±  0.097 s    [User: 26.405 s, System: 0.799 s]
  Range (min  max):   27.056 s  27.349 s    10 runs

Benchmark 3: pyflakes resources/test/cpython
  Time (mean ± σ):     27.309 s ±  0.033 s    [User: 27.137 s, System: 0.169 s]
  Range (min  max):   27.267 s  27.372 s    10 runs

Benchmark 4: autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython
  Time (mean ± σ):      8.027 s ±  0.024 s    [User: 74.255 s, System: 0.953 s]
  Range (min  max):    7.969 s   8.052 s    10 runs

Benchmark 5: pycodestyle resources/test/cpython
  Time (mean ± σ):     41.666 s ±  0.266 s    [User: 41.531 s, System: 0.132 s]
  Range (min  max):   41.295 s  41.980 s    10 runs

Benchmark 6: pycodestyle --select E501 resources/test/cpython
  Time (mean ± σ):     14.547 s ±  0.077 s    [User: 14.466 s, System: 0.079 s]
  Range (min  max):   14.429 s  14.695 s    10 runs

Benchmark 7: flake8 resources/test/cpython
  Time (mean ± σ):     75.700 s ±  0.152 s    [User: 75.254 s, System: 0.440 s]
  Range (min  max):   75.513 s  76.014 s    10 runs

Benchmark 8: flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython
  Time (mean ± σ):     75.122 s ±  0.532 s    [User: 74.677 s, System: 0.440 s]
  Range (min  max):   74.130 s  75.606 s    10 runs

Benchmark 9: python -m scripts.run_flake8 resources/test/cpython
  Time (mean ± σ):     12.794 s ±  0.147 s    [User: 90.792 s, System: 0.738 s]
  Range (min  max):   12.606 s  13.030 s    10 runs

Benchmark 10: python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501
  Time (mean ± σ):     12.487 s ±  0.118 s    [User: 90.052 s, System: 0.714 s]
  Range (min  max):   12.265 s  12.665 s    10 runs

Summary
  './target/release/ruff ./resources/test/cpython/ --no-cache' ran
   17.10 ± 0.60 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
   26.60 ± 0.96 times faster than 'python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501'
   27.26 ± 1.00 times faster than 'python -m scripts.run_flake8 resources/test/cpython'
   30.99 ± 1.09 times faster than 'pycodestyle --select E501 resources/test/cpython'
   57.98 ± 2.03 times faster than 'pylint --recursive=y resources/test/cpython/'
   58.19 ± 2.02 times faster than 'pyflakes resources/test/cpython'
   88.77 ± 3.14 times faster than 'pycodestyle resources/test/cpython'
  160.06 ± 5.68 times faster than 'flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython'
  161.29 ± 5.61 times faster than 'flake8 resources/test/cpython'

License

MIT

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.22.tar.gz (73.7 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.22-py3-none-win_amd64.whl (1.7 MB view details)

Uploaded Python 3Windows x86-64

ruff-0.0.22-py3-none-win32.whl (1.6 MB view details)

Uploaded Python 3Windows x86

ruff-0.0.22-py3-none-musllinux_1_2_x86_64.whl (1.9 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

ruff-0.0.22-py3-none-musllinux_1_2_i686.whl (1.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ i686

ruff-0.0.22-py3-none-musllinux_1_2_armv7l.whl (1.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

ruff-0.0.22-py3-none-musllinux_1_2_aarch64.whl (1.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

ruff-0.0.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ s390x

ruff-0.0.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

ruff-0.0.22-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl (2.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64

ruff-0.0.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (1.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

ruff-0.0.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

ruff-0.0.22-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.8 MB view details)

Uploaded Python 3manylinux: glibc 2.12+ x86-64

ruff-0.0.22-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.12+ i686

ruff-0.0.22-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (3.4 MB view details)

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

ruff-0.0.22-py3-none-macosx_10_7_x86_64.whl (1.7 MB view details)

Uploaded Python 3macOS 10.7+ x86-64

File details

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

File metadata

  • Download URL: ruff-0.0.22.tar.gz
  • Upload date:
  • Size: 73.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.22.tar.gz
Algorithm Hash digest
SHA256 3696c5b4eaa86d90c124c0c7225de5fa933243b4332f701f06c2006fc78813c8
MD5 c91167d504095d38d88a30fdbded623c
BLAKE2b-256 3dbf3438d4cf23e07a574c8c8ff4ec482d20a57919134dfd1aa6457799e4d3e5

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for ruff-0.0.22-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ef039c549720c0828f59a53542714bd5da902efa95b02a6d452f67e8a92036a9
MD5 61aa00b2c12f48bc5cae13a8525640c8
BLAKE2b-256 b4067fb8e44c295cb6dc5f952c0265e219451654353983a72584f29ed555e9c6

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.22-py3-none-win32.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.22-py3-none-win32.whl
Algorithm Hash digest
SHA256 ed2270c59b6f4aed023d9faf385ae5a6eac57a46a2b6f0ccc4cc555ef01c1f44
MD5 f171c17b9986f0e871f2d6747d90e585
BLAKE2b-256 9bde1353ff7913005b2fc2cceb22aca468d15198605336710d62489ab3a25143

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c209332534aae83d7871223fb01e8753c51e0c188be5ac536be3c301b7703c9d
MD5 81078185dd3fcecbe3a681f171404774
BLAKE2b-256 0bc3acefc065044cf435c21f8f6606a122c31d070e044ef441e605d230cb4e79

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.22-py3-none-musllinux_1_2_i686.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: Python 3, musllinux: musl 1.2+ i686
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.22-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 ca5775469276a1153cdbcd774077698da7173f501ddee657f13dc6874b95efff
MD5 1d8c615d4eda9056bdfefec5e180813f
BLAKE2b-256 7975c5307449188c4fd654ae2e87670d64830f7a69160f0e2c76f40e63a20ed1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 b0e119c9880d34a743c230a6696094af88f6593de01f3bcabf0ad1e8610ac5c8
MD5 251528cb598dbf65f4f17ee6c93c3c9f
BLAKE2b-256 88f1b3e1353823c213b30a4b5d533f991178e579d98c1df845751999cb86f0ca

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 c0a70b686f64d712241026ed34a049ab6896bd2dbc9fcf1931ee8ca4f9eb2e9d
MD5 bc6df46fa5d1a9375f2f13f01c83d6c8
BLAKE2b-256 7044c7b71720860ecf0398fe7225f478bde133d7c5c4197bc43c1d60e2b9ffb9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 631b8c27bf38a2a677efebc084cb6e3bf1aa299d61f48993bdbf41fbd03ad2ed
MD5 42f959b50f47615bff015ad8a0612af5
BLAKE2b-256 482444287ee041cabb407bff6e85909e16450ad83ebf67060cd9c36e4071025d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 4e6d8b0a435595f76a5fb66547429f30e8616f80ae489c7103aff975dd9ba0f2
MD5 8472b5b6ecb715b768ac902d01f85ba2
BLAKE2b-256 8959ada07f8b33c6ac72d7698a580a54fe8fdaad01b9cc2383bab3e8431877cb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 fc6186d64c6784d4fb9e8cd89b42c7ecfd4e337c9e66cba5104970535e15c911
MD5 50c7f2076d695b7066648013e589fc67
BLAKE2b-256 def14a7076cf089c21d4013cdcedec416d3e0664c530c10426e142527d24a952

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 a5ee6a6c3da126785c602b5bfb0eb354a91d76d5eaabfe25819867872caf465e
MD5 c831b6eda4821a9247b981c3098f502f
BLAKE2b-256 1866cadf245f3fdfdb9e1becb567329a781c93e21260a8ed6e5b52cfc5917127

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b9f5de11817e2c6f5ca150c2636281efebc292199967cc0327e99f65addd98a3
MD5 a949fe4ecb31edcf5857d1fb1be362e6
BLAKE2b-256 9ae027cdc078bbd26a8fb9c27b9eb57fd7c0756b4c7371f43729dd9a741af16c

See more details on using hashes here.

File details

Details for the file ruff-0.0.22-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 6edd51c1a745529013e5a19a17aeb0641aba6a435d2b0c8339f5d8a7b89bf539
MD5 2d42d1046b5b953f6f315b921067bf1f
BLAKE2b-256 7827dea52e1ac4ef6ddb311b7f06d109ef13c81b7f5a9842d40beab57c7b3329

See more details on using hashes here.

File details

Details for the file ruff-0.0.22-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl.

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 4a15d42da663c5aa9a1ad407b35ffb7b3f3bdd3ca78da6432bf5c53c6becbd2b
MD5 87dfdffd0d9fad8ae5f485d2f9ed97fe
BLAKE2b-256 bd727bceacb7f11aa583ba5bed6228cf4c16b656b14fe9080c455538b360f38f

See more details on using hashes here.

File details

Details for the file ruff-0.0.22-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 c35882164c7aed0d4b64f2d538bb06b245a087854bed58b6e1fa8e3ecbea0186
MD5 cce3837cb7e88aa912ff356045efff87
BLAKE2b-256 1c20d3e5019b0f31293edf1b6d580703adeee9c1c51000a0a0fdde33b139db28

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.22-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 73561cade53221d37e0e86ed062c3a3633a6cd5141b32a8d56b069cfcc66f3a7
MD5 2f028d3b8e96bb6a873fe35d1f132100
BLAKE2b-256 6dd06b8f9701a2c734f6f15a86bcf3fe0cfe0ad96c69ad0f14afaf964c1c2e58

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