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.20.tar.gz (72.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.20-py3-none-win_amd64.whl (1.6 MB view details)

Uploaded Python 3Windows x86-64

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

Uploaded Python 3Windows x86

ruff-0.0.20-py3-none-musllinux_1_2_x86_64.whl (1.8 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

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

Uploaded Python 3musllinux: musl 1.2+ i686

ruff-0.0.20-py3-none-musllinux_1_2_armv7l.whl (1.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

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

Uploaded Python 3musllinux: musl 1.2+ ARM64

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

Uploaded Python 3manylinux: glibc 2.17+ s390x

ruff-0.0.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

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

Uploaded Python 3manylinux: glibc 2.17+ ppc64

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

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

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

Uploaded Python 3manylinux: glibc 2.17+ ARM64

ruff-0.0.20-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.20-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.12+ i686

ruff-0.0.20-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (3.3 MB view details)

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

ruff-0.0.20-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.20.tar.gz.

File metadata

  • Download URL: ruff-0.0.20.tar.gz
  • Upload date:
  • Size: 72.0 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.20.tar.gz
Algorithm Hash digest
SHA256 b210ada28a58d00a5757fbd18310f00532006e53bfb4e2ff7cea88eb8bf2769d
MD5 2dd886a36dbc62d9cdebcfb2acfd3238
BLAKE2b-256 897d1f6c9daaf41c013b1787115be1ef40cc425d584835189d48a60bded1b3fd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.20-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.6 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.20-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 bdd9f9e76b58fe13719df4c7ef2e22e02eaeb223540c7dfd16e4724a677ad99b
MD5 6af80246c8edddb6ec91bec977cf50fb
BLAKE2b-256 42efc6590735bc309eb87263eff0f360fd3d8422883737c53f4b2883209862ab

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.20-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.20-py3-none-win32.whl
Algorithm Hash digest
SHA256 7073bc114566337fbef923daa46f9a3b1588bf606de80651cfc43200f48bef06
MD5 e14205bdd5b5c0a23b0c828ee1ca7d60
BLAKE2b-256 556450b3e3c587a891772fa66e4fefd0e2bff7db87eb24512b5a0a07354f5989

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9b762a641c75fdbdb18bb2fcf3cb8f1da2cded541f825db407e1ce3927be1298
MD5 878ff2130edec32eaeab0311f5e9de14
BLAKE2b-256 4a17b169a99add1275eda589140be6b2f2bd8262df0e9694f6495c731b755764

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.20-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.20-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 08328846a07be57bbf77143a8c732905d3ddbcf608258bd79e7b12098fc85f02
MD5 a6fd2d90b3847d079a9b3e62a8775128
BLAKE2b-256 290b76fa9aa084d6897eeb2c4274aaeee4db1d7efa9603e17781d7dd77335f46

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 47142f4a62da28ab090309c42f6b791cfeb28fd7fcfa2bd32cf9618d8aa75162
MD5 334e6685a3fc30c9f0d45c60f72cb373
BLAKE2b-256 9bc586fdb448f95a8776d5836278b7fc271599da8ae34cd9ba6eeb59b788a728

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 a14c5425142d9c91a6e2373b34fce76ab64b9b3381f5dd87eeb42205ae8b94dc
MD5 62a2d5b66e622da2e964382d7f7a5aa8
BLAKE2b-256 01eab018b460c8a95910baf2190ae7ed483f978c86e37d4988ad350faecdd408

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 180b27881ef0609cbff67b066c39614c90f3a927fbd81eac5fb9b73357102105
MD5 f131ac513fa3de84f780476b508bb299
BLAKE2b-256 7e24637a7f673253d1b02c6a7c4386ac1c2351618edb49b64a956bbb50faa0b5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 ca3e13b550a0a0598822df34da1345d186e0adb6242d7141fd89d973ea57efa9
MD5 f0b44b7e78264c0ce0a89561bdaa4565
BLAKE2b-256 ea7ec0ab790a62e026ea8c3d4ef9fdaf7c7ab27b7ac0b5f3661bd30df45881a9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 65afe4fad798dfb5353c33e0e686c7347e48857ff96b69b62fad3699ea7f9a69
MD5 02421e56fee92c1563ca45c2b7519bad
BLAKE2b-256 e9fd17c09315a896e3e7f21a4712c3b8ca9895ffa36dbc64e0d756140e6436ac

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 08534ec33bd35d633d914cfd5f66fdaa9dc6c0f15d14098ed6e6e81aecaba754
MD5 4c72459db5ad0d6bc8b0981c56cb1f5d
BLAKE2b-256 58e31d56ebeab3d33939adf7ac9cfffe9cf0efb2e76a38c668e622207ba3c098

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3b1f040239ccf96c4364175010c890350fc80785b6613a00008ff084c282fcb8
MD5 ff927bcee155bbd0c4cfcb0f5acabc7b
BLAKE2b-256 a517506f61505766c738491240daff71727b83d988c0ac80acd1936dff5b3106

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 eb2a75043d62c15b8b7370f6b82f9830405172f0e88ce56a3f8fec8fcec418ef
MD5 563f5ee352604afbae3b270433d3f51b
BLAKE2b-256 ceb056b5a1f20ba256f4da3fccef58e5d515c8c2f24846fcd8fa3960ff1826b9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 421398a113c254fb8d8880d6fe3402a53cd6ab4cae0a7a0184054c4124811bd0
MD5 29ff4db86838027904f4b1a67a373e1d
BLAKE2b-256 71a326ee50bf5d36cea96fb9e328faced6e9f32a42d6d3037b1a9b973dd4bda5

See more details on using hashes here.

File details

Details for the file ruff-0.0.20-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.20-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 aff98628bc6cb3299f100f1677cae822ec23c37bfa78fca211626ee501cc37fb
MD5 54fa9a43ed2ca44535964d5cee55b298
BLAKE2b-256 2bc05acad3e3d97c409d7f8aee514b569755c63676dfd25a9cf547dba11aea54

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.20-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 8b9633c05e65768ce2a82b88e540075095af78f93c7b638f0fb27f9d4ac2eb29
MD5 2fc5977709a32a8ff81171e306b93ba4
BLAKE2b-256 bee851ec88068af68fb52231ac32f7da65b358b84dc6d1eac61a9c65b1bed7e5

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