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

Uploaded Python 3Windows x86-64

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

Uploaded Python 3Windows x86

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

Uploaded Python 3musllinux: musl 1.2+ x86-64

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

Uploaded Python 3musllinux: musl 1.2+ i686

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

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

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

Uploaded Python 3musllinux: musl 1.2+ ARM64

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

Uploaded Python 3manylinux: glibc 2.17+ s390x

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

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

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

Uploaded Python 3manylinux: glibc 2.17+ ppc64

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

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

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

Uploaded Python 3manylinux: glibc 2.17+ ARM64

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

Uploaded Python 3manylinux: glibc 2.12+ i686

ruff-0.0.21-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.21-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.21.tar.gz.

File metadata

  • Download URL: ruff-0.0.21.tar.gz
  • Upload date:
  • Size: 72.6 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.21.tar.gz
Algorithm Hash digest
SHA256 de4798b44e01ad6fe0af61fa7d40194b3a34c9522af5af16e893c0b2c1e39a7e
MD5 d3b555f2446b6a395c2d144550fc6974
BLAKE2b-256 e68ddaf545f79558e7bf0ebeb732fb767600ae0a0aff2fc4786d90445ec4dc7a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.21-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.21-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 3ad46964a9eb62203e2f101f9a7068442cefad5f955d62895226dc17ac8a5452
MD5 030ed2ae853956be4759922813e8a9a8
BLAKE2b-256 b5f3d2d4948e3587717a3d31e142058ecb9a69ef6c8924863b92a3a701b5b02d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.21-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.21-py3-none-win32.whl
Algorithm Hash digest
SHA256 d33c4d97e1b60b34a426525dca0806675320e4d9e4b3c4d423e014b55f12552d
MD5 2bcbc86090d573084e570a3193491e67
BLAKE2b-256 042f7dd8f0fe94c9ddc39d14546af84998e2335cca5975dab8866ae84f585213

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8629dd2db7d0ab00ce75c63892dba71ed8f0b60d113b082e57c34a5ac745a456
MD5 96e7834fbb3adba1b1982e5eb274bd01
BLAKE2b-256 455be7b3bb27ccc2d1b33cd28bd6f6a9d42e8e2188340ab3514336522d7b30fd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ruff-0.0.21-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.21-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 a89354b2ef74cf78ca3de21115edccaa820f82eab74d62af9a5c64380948db8f
MD5 306d2a09a042a71bb843201b8ed4aaa1
BLAKE2b-256 711409aca245cd8690a87131922bc338ea798aec6486d72d1e1d7e9bc9181a4b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 6c15ff133c09d3160fce5813db8e6a5a47f4d3fdfdf5ad327d6ecec0507fefff
MD5 efa4cbaff0d2c9429ed447da80748802
BLAKE2b-256 b9c0ad4ca8f8bf6e9a9eb1a88122c4fb4acace41e8e12c7bcbf7c91e72c44641

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 b03253f9db5e35d9815841d2c55379cabcab13cd5dda14522cdb5ef330f21459
MD5 94260c711b7e6e33435b0e017c83ad8b
BLAKE2b-256 6f915112e9c7c174d75c48ae9eceb64730c2f73a342d33b0635333988cf7228d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 59a3fedd5b07a18baa52ba1605216ce7859e9be8d451318d0b789d171a62e9d2
MD5 eaa29fb883bb37f59899f30b5a8e95a5
BLAKE2b-256 bbfb1d5594b8233723c8d3087db26c78afdb32f6b0b94f23f0e823ce8a83347f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 27cd2e4c02bf4600f678d0ede5bdac46bba4a1a66827bf49d4795b420ea27b01
MD5 eda3f850f98bed0f416c610e8d205aaf
BLAKE2b-256 037747d58bbae7f92f7803ae1dfd9edd755e5789fadda50670a901cbd53db6ba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 97258e5341084ebf73c1f04a642aee5a647b04f0feea6276a3b857c7e7c33d08
MD5 3855ebf625bec4a617050fac326b3f84
BLAKE2b-256 90217719352402d2048c73c0ff48c4cbcbc307e06ce7e519c33cf8ddf5fabb60

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 d777d42e79f72bbddb1389001947e497ad1617cef402c62de6f845d059d03d40
MD5 ded12cf42d5564c23114925e01bc9b97
BLAKE2b-256 9d9d4eeaf06a6fd5d3b07f82bfa1da0906eea4c800feb6fb0456f936b85f3f78

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ce9ae357b44ca521a783c16f6277884bbf67c09b4a0c52b6a8f2e60346461727
MD5 87cd26367db4d376cfbf54282eadb4d1
BLAKE2b-256 d198e1f766050747c55a6898eae9b7de95ce8e42005f5b53575ad354f451c7ff

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 932bdc3e5404df98aa1d1640fc581ed92046b7e1eb6674f601cfd64ea7e4d889
MD5 19686ae04d310bb1b0501393f45176aa
BLAKE2b-256 73c7c0912dbbd190cd5cc777965ebf4eaa23dbc5b8b73647c4d4bbf59d74d6f0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 26a11ac3a9eca75e5162c4122d36dfbbdf8977c3e4b15e2f2750f431fb9357a3
MD5 7250cd0f61296d3aba2a4d03b4274de5
BLAKE2b-256 99be443197d845a5d541e8162e4ce4ab32f7db1a4f8febbc5b80d6f66c6f3e97

See more details on using hashes here.

File details

Details for the file ruff-0.0.21-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.21-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 50527325acc7e3ea7cab591290510eabf5b6743fb175d9b0fc2e743ae4ff3930
MD5 3e5c521f898152cd71c58c9cc6617837
BLAKE2b-256 8c4c166da9e49a1905fe04543754a63cdb9bc92155cd53d60c1e883175dcebf7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.21-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 c6e21fd662a147a0c5b9fe76833e862fb05a67c7ee80ab462110a98f78cf261d
MD5 98f6b1d817e0adaf74e3506ae26e6cde
BLAKE2b-256 c37559ee5dadf596e91880f2bdc3c645550397aeefa4d4ea30151648e8a67a58

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