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.

Major features:

  • 10-100x faster than your current linter.
  • Installable via pip.
  • Python 3.10 compatibility.
  • ESLint-inspired cache semantics.
  • TypeScript-inspired --watch semantics.
  • pyproject.toml support.

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.

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
A Python linter written in Rust

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:

maturin publish --skip-existing --target x86_64-apple-darwin && \
  maturin publish --skip-existing --target aarch64-apple-darwin

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 5 \
  "./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 the ecosystem's existing tools:

hyperfine --ignore-failure --warmup 5 \
  "pycodestyle resources/test/cpython" \
  "pyflakes resources/test/cpython" \
  "flake8 resources/test/cpython" \
  "autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
  "pylint --recursive=y resources/test/cpython/" \
  "pycodestyle --select E501 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:

  • pycodestyle
  • pyflakes
  • flake8
  • autoflake
  • pylint
  • pycodestyle, limited to the checks supported by Ruff
  • flake8, limited to the checks supported by Ruff
  • flake8, with a hack to enable multiprocessing on macOS
  • flake8, limited to the checks supported by Ruff, with a hack to enable multiprocessing on macOS

(You can poetry install from ./scripts to create a working environment for the above.)

 hyperfine --ignore-failure --warmup 5 \   "pycodestyle resources/test/cpython" \   "pyflakes resources/test/cpython" \   "flake8 resources/test/cpython" \   "autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \   "pylint --recursive=y resources/test/cpython/" \   "pycodestyle --select E501 resources/test/cpython" \   "flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython" \   "python -m run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501" \   "python -m run_flake8 resources/test/cpython"
Benchmark 1: pycodestyle resources/test/cpython
  Time (mean ± σ):     41.921 s ±  1.409 s    [User: 41.451 s, System: 0.194 s]
  Range (min  max):   41.182 s  45.894 s    10 runs

  Warning: Ignoring non-zero exit code.
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet PC without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: pyflakes resources/test/cpython
  Time (mean ± σ):     27.960 s ±  1.251 s    [User: 27.491 s, System: 0.236 s]
  Range (min  max):   26.449 s  29.899 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: flake8 resources/test/cpython
  Time (mean ± σ):     75.320 s ±  0.909 s    [User: 74.625 s, System: 0.610 s]
  Range (min  max):   74.181 s  77.336 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 ± σ):     32.690 s ±  0.585 s    [User: 32.300 s, System: 0.296 s]
  Range (min  max):   31.948 s  33.326 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 5: pylint --recursive=y resources/test/cpython/
  Time (mean ± σ):     27.592 s ±  0.227 s    [User: 26.627 s, System: 0.911 s]
  Range (min  max):   27.325 s  27.955 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 6: pycodestyle --select E501 resources/test/cpython
  Time (mean ± σ):     14.540 s ±  0.156 s    [User: 14.397 s, System: 0.121 s]
  Range (min  max):   14.384 s  14.920 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 7: flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython
  Time (mean ± σ):     75.391 s ±  0.600 s    [User: 74.642 s, System: 0.591 s]
  Range (min  max):   74.458 s  76.550 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 8: python -m run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501
  Time (mean ± σ):     12.542 s ±  0.467 s    [User: 87.891 s, System: 0.816 s]
  Range (min  max):   11.771 s  13.034 s    10 runs

Benchmark 9: python -m run_flake8 resources/test/cpython
  Time (mean ± σ):     12.276 s ±  0.398 s    [User: 86.720 s, System: 0.792 s]
  Range (min  max):   11.809 s  12.865 s    10 runs

Summary
  'python -m run_flake8 resources/test/cpython' ran
    1.02 ± 0.05 times faster than 'python -m run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501'
    1.18 ± 0.04 times faster than 'pycodestyle --select E501 resources/test/cpython'
    2.25 ± 0.08 times faster than 'pylint --recursive=y resources/test/cpython/'
    2.28 ± 0.13 times faster than 'pyflakes resources/test/cpython'
    2.66 ± 0.10 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
    3.41 ± 0.16 times faster than 'pycodestyle resources/test/cpython'
    6.14 ± 0.21 times faster than 'flake8 resources/test/cpython'
    6.14 ± 0.21 times faster than 'flake8 --select=F831,F541,F634,F403,F706,F901,E501 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.16.tar.gz (53.4 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.16-cp310-cp310-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

ruff-0.0.16-cp310-cp310-macosx_10_7_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.10macOS 10.7+ x86-64

ruff-0.0.16-cp39-cp39-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

ruff-0.0.16-cp39-cp39-macosx_10_7_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.9macOS 10.7+ x86-64

ruff-0.0.16-cp38-cp38-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

ruff-0.0.16-cp38-cp38-macosx_10_7_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.8macOS 10.7+ x86-64

ruff-0.0.16-cp37-cp37m-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.7mmacOS 11.0+ ARM64

ruff-0.0.16-cp37-cp37m-macosx_10_7_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.7mmacOS 10.7+ x86-64

File details

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

File metadata

  • Download URL: ruff-0.0.16.tar.gz
  • Upload date:
  • Size: 53.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/0.13.0

File hashes

Hashes for ruff-0.0.16.tar.gz
Algorithm Hash digest
SHA256 1df2dae97b64a2e718aada19551b0a9c2a129e8a198252a14caf3c09cd311b0f
MD5 69f740cba9c792e67599b9a745440e12
BLAKE2b-256 bdb537025e8ca76b3a590e17fd2ce4b8f38f1c1400194e93881dd20731a3b613

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 657070d63691b92cda091f679c5e798e2c557586fffb998aad59cd20d1c63287
MD5 68e740676b0afc2b160e702ef421d288
BLAKE2b-256 eb644b0c17535653dc13f61d80ba941ae0dd4fe26f994ea986a1570d12f29ee0

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp310-cp310-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp310-cp310-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 667e215f1f12d0bfc7bd8b8e093fea11f726a401ec848274b223ad1a0aa524ce
MD5 38765863dd01ac7a16b844c18dcc4ac3
BLAKE2b-256 468f7ceae1a844515829d56f753dd486690364bcd90dcbbaa43d75957088a56d

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7ae8a1922ab55671341ee24227ad44cccc5fb4b00876ba605eda84c29e4c0e7f
MD5 5b299da3ea381825561f303ef4f96373
BLAKE2b-256 d6760619047971e7907d180e7915f6378b69d1307f47817b7f8a0dfd2a9eeb37

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp39-cp39-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp39-cp39-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 8e1319a51bae170e3043dc13526c1c05e5811c789ba51719bf4b9740adddfd14
MD5 3b1928ca28f57d0542426f6e430e7c7c
BLAKE2b-256 b5db98c479526d94218c86bfbf380b4aafd6a6a87df5565d7780865b5286b628

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 06449a8296e1ffc57c34272dab24c2626d216281803151653619dde80d0e84c6
MD5 de456aeaefce5885bf4c49f2d6526451
BLAKE2b-256 883d3d76ff7b201203cdd0c243e312e29c9bb5c07803d6aab9efa02540736a23

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp38-cp38-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp38-cp38-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 617617fc1c18dfa640c6f34dfd053c471e45efc0cd0ae8c78d8c8f989e08c7d2
MD5 bdb8469332ed067315085e72b4a94ad8
BLAKE2b-256 a2f5358d76c6871f319c38c6afa31c554866c7ef825f7929adbca04753d01955

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp37-cp37m-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp37-cp37m-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ccdd281b26a40efe716d72a90bb555648ca88409d133468561e8a1f9578656e7
MD5 dace66035a5072e405f18e69629bb35f
BLAKE2b-256 fbd0355f90da44751f70d39efc35701f9ce2c8a7e87d8eef392fc8a034c94fd6

See more details on using hashes here.

File details

Details for the file ruff-0.0.16-cp37-cp37m-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.16-cp37-cp37m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 22994f188883a7e24bce42876ddd2aa2a3da8be5d24144a66a6fb2b02249a0c7
MD5 6339e1fa9fc4842133a12b288044a028
BLAKE2b-256 164785d7ed09a15e42791c57017f312b506fc9f87edf5c5876268c4128c402a4

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