Skip to main content

ruff

A performance-focused, Pyflakes-inspired Python linter, written in Rust.

Features:

  • Python 3.10 compatibility
  • ESLint-inspired cache semantics
  • TypeScript-inspired --watch semantics
  • pyproject.toml support

Installation

Available as ruff on PyPI:

pip install ruff

Usage

To run the linter, try any of the following:

ruff path/to/code/to/check.py
# ...or...
ruff path/to/code/
# ...or...
ruff path/to/code/*.py

You can also run in --watch mode to automatically re-run the linter on-change with, e.g.:

ruff path/to/code/ --watch

Development

ruff is written in Rust:

cargo fmt
cargo clippy
cargo run resources/test/src

Deployment

ruff is released for Python using maturin:

maturin publish --username crmarsh --skip-existing --target x86_64-apple-darwin && \
  maturin publish --username crmarsh --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 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:

python -m venv .venv
source .venv/bin/activate
pip install pylint pycodestyle flake8 autoflake pyflakes

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" 
 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'

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.15.tar.gz (51.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.15-cp38-cp38-macosx_11_0_arm64.whl (1.5 MB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

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

Uploaded CPython 3.8macOS 10.7+ x86-64

File details

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

File metadata

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

File hashes

Hashes for ruff-0.0.15.tar.gz
Algorithm Hash digest
SHA256 b255e451e3cbab4b9ae953afb1e1c9070588d01510a9b546a1e9418137dd3968
MD5 f1a1a963fcfea28b9869224249ef0e7a
BLAKE2b-256 07bda03aaa38296b510b4764fcf71afa4ce97ae733211b4e64b2d224e2482a75

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.15-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c12496da33a3e24c3bce8a5b0ed9eaa33bb15ff37e552366bb479809023e8a24
MD5 a4a7965a17a90f81126a8da14f875eec
BLAKE2b-256 5c0465e2c32630578c9e1e86b77100313d2436f3d10ff9fb5515d98df8b5ab8e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ruff-0.0.15-cp38-cp38-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 b0260a7426aae275cbf5f6a6f38c50adbfa07f7043b22dc19aadcfc00b0a03c3
MD5 b14d4bd92769c0f25607c9ea9da48d26
BLAKE2b-256 b471ea2c9a86d2bfef1c1e2d221c0d00592d731ce695372feae7f824a5b57122

See more details on using hashes here.

Release history Release notifications | RSS feed

0.16.4

18 files

0.16.3

18 files

0.16.2

18 files

0.16.1

18 files

0.16.0

18 files

0.15.22

18 files

0.15.21

18 files

0.15.20

18 files

0.15.19

18 files

0.15.18

18 files

0.15.17

18 files

0.15.16

18 files

0.15.15

18 files

0.15.14

18 files

0.15.13

18 files

0.15.12

18 files

0.15.11

18 files

0.15.10

18 files

0.15.9

18 files

0.15.8

18 files

0.15.7

18 files

0.15.6

18 files

0.15.5

18 files

0.15.4

18 files

0.15.3

18 files

0.15.2

18 files

0.15.1

18 files

0.15.0

18 files

0.14.14

19 files

0.14.13

19 files

0.14.12

19 files

0.14.11

19 files

0.14.10

19 files

0.14.9

19 files

0.14.8

19 files

0.14.7

19 files

0.14.6

19 files

0.14.5

19 files

0.14.4

19 files

0.14.3

19 files

0.14.2

19 files

0.14.1

19 files

0.14.0

19 files

0.13.3

19 files

0.13.2

19 files

0.13.1

19 files

0.13.0

19 files

0.12.12

19 files

0.12.11

19 files

0.12.10

19 files

0.12.9

19 files

0.12.8

18 files

0.12.7

18 files

0.12.6

17 files

0.12.5

18 files

0.12.4

18 files

0.12.3

18 files

0.12.2

18 files

0.12.1

18 files

0.12.0

18 files

0.11.13

18 files

0.11.12

18 files

0.11.11

18 files

0.11.10

18 files

0.11.9

18 files

0.11.8

18 files

0.11.7

18 files

0.11.6

18 files

0.11.5

18 files

0.11.4

18 files

0.11.3

18 files

0.11.2

18 files

0.11.1

18 files

0.11.0

18 files

0.10.0

18 files

0.9.10

18 files

0.9.9

18 files

0.9.8

18 files

0.9.7

18 files

0.9.6

18 files

0.9.5

18 files

0.9.4

18 files

0.9.3

18 files

0.9.2

18 files

0.9.1

18 files

0.9.0

18 files

0.8.6

18 files

0.8.5

18 files

0.8.4

18 files

0.8.3

18 files

0.8.2

18 files

0.8.1

18 files

0.8.0

18 files

0.7.4

18 files

0.7.3

18 files

0.7.2

18 files

0.7.1

18 files

0.7.0

18 files

0.6.9

18 files

0.6.8

18 files

0.6.7

18 files

0.6.6

18 files

0.6.5

18 files

0.6.4

18 files

0.6.3

18 files

0.6.2

18 files

0.6.1

18 files

0.6.0

18 files

0.5.7

18 files

0.5.6

18 files

0.5.5

18 files

0.5.4

18 files

0.5.3

18 files

0.5.2

18 files

0.5.1

18 files

0.5.0

18 files

0.4.10

17 files

0.4.9

17 files

0.4.8

17 files

0.4.7

17 files

0.4.6

17 files

0.4.5

17 files

0.4.4

17 files

0.4.3

17 files

0.4.2

17 files

0.4.1

17 files

0.4.0

17 files

0.3.7

17 files

0.3.6

17 files

0.3.5

17 files

0.3.4

17 files

0.3.3

17 files

0.3.2

17 files

0.3.1

17 files

0.3.0

17 files

0.2.2

17 files

0.2.1

17 files

0.2.0

17 files

0.1.15

17 files

0.1.14

17 files

0.1.13

17 files

0.1.12

17 files

0.1.11

17 files

0.1.10

17 files

0.1.9

17 files

0.1.8

17 files

0.1.7

17 files

0.1.6

17 files

0.1.5

17 files

0.1.4

17 files

0.1.3

17 files

0.1.2

17 files

0.1.1

17 files

0.1.0

17 files

0.0.292

17 files

0.0.291

17 files

0.0.290

17 files

0.0.289

17 files

0.0.288

17 files

0.0.287

17 files

0.0.286

17 files

0.0.285

17 files

0.0.284

17 files

0.0.283

17 files

0.0.282

17 files

0.0.281

17 files

0.0.280

17 files

0.0.279

17 files

0.0.278

17 files

0.0.277

17 files

0.0.276

17 files

0.0.275

17 files

0.0.274

17 files

0.0.273

17 files

0.0.272

17 files

0.0.271

17 files

0.0.270

17 files

0.0.269

17 files

0.0.267

17 files

0.0.266

17 files

0.0.265

17 files

0.0.264

17 files

0.0.263

17 files

0.0.262

17 files

0.0.261

17 files

0.0.260

17 files

0.0.259

17 files

0.0.257

17 files

0.0.256

17 files

0.0.255

17 files

0.0.254

17 files

0.0.253

17 files

0.0.252

17 files

0.0.251

17 files

0.0.250

17 files

0.0.249

17 files

0.0.248

17 files

0.0.247

17 files

0.0.246

16 files

0.0.245

16 files

0.0.244

16 files

0.0.243

16 files

0.0.242

16 files

0.0.241

16 files

0.0.240

16 files

0.0.239

16 files

0.0.238

16 files

0.0.237

16 files

0.0.236

16 files

0.0.235

16 files

0.0.234

16 files

0.0.233

16 files

0.0.231

16 files

0.0.230

16 files

0.0.229

16 files

0.0.228

16 files

0.0.227

16 files

0.0.226

16 files

0.0.225

16 files

0.0.224

16 files

0.0.223

16 files

0.0.222

16 files

0.0.221

16 files

0.0.220

16 files

0.0.219

16 files

0.0.218

16 files

0.0.217

16 files

0.0.216

16 files

0.0.215

16 files

0.0.214

16 files

0.0.213

16 files

0.0.212

16 files

0.0.211

16 files

0.0.210

16 files

0.0.209

16 files

0.0.208

16 files

0.0.207

16 files

0.0.206

16 files

0.0.205

16 files

0.0.204

16 files

0.0.203

16 files

0.0.202

16 files

0.0.201

16 files

0.0.200

16 files

0.0.199

16 files

0.0.198

16 files

0.0.196

16 files

0.0.195

16 files

0.0.194

16 files

0.0.193

16 files

0.0.192

16 files

0.0.191

16 files

0.0.190

16 files

0.0.189

16 files

0.0.188

16 files

0.0.187

16 files

0.0.186

16 files

0.0.185

16 files

0.0.184

16 files

0.0.183

16 files

0.0.182

16 files

0.0.181

16 files

0.0.180

16 files

0.0.178

16 files

0.0.177

16 files

0.0.176

16 files

0.0.175

16 files

0.0.174

16 files

0.0.173

16 files

0.0.172

16 files

0.0.171

16 files

0.0.170

16 files

0.0.169

16 files

0.0.168

16 files

0.0.167

16 files

0.0.166

16 files

0.0.165

16 files

0.0.164

16 files

0.0.163

16 files

0.0.162

16 files

0.0.161

16 files

0.0.160

16 files

0.0.159

16 files

0.0.158

16 files

0.0.157

16 files

0.0.156

16 files

0.0.155

16 files

0.0.154

16 files

0.0.153

16 files

0.0.152

16 files

0.0.151

16 files

0.0.150

16 files

0.0.149

16 files

0.0.148

16 files

0.0.146

16 files

0.0.145

16 files

0.0.144

16 files

0.0.143

16 files

0.0.142

16 files

0.0.141

16 files

0.0.140

16 files

0.0.139

16 files

0.0.138

16 files

0.0.137

16 files

0.0.135

16 files

0.0.134

16 files

0.0.133

16 files

0.0.132

16 files

0.0.131

16 files

0.0.130

16 files

0.0.129

16 files

0.0.128

16 files

0.0.127

16 files

0.0.126

16 files

0.0.125

16 files

0.0.124

16 files

0.0.123

16 files

0.0.122

16 files

0.0.121

16 files

0.0.120

16 files

0.0.119

16 files

0.0.118

16 files

0.0.117

16 files

0.0.116

16 files

0.0.114

16 files

0.0.113

16 files

0.0.112

16 files

0.0.111

16 files

0.0.110

16 files

0.0.109

16 files

0.0.108

16 files

0.0.107

16 files

0.0.106

16 files

0.0.105

16 files

0.0.104

16 files

0.0.103

16 files

0.0.102

16 files

0.0.100

16 files

0.0.99

16 files

0.0.98

16 files

0.0.97

16 files

0.0.96

16 files

0.0.95

16 files

0.0.94

16 files

0.0.93

16 files

0.0.92

16 files

0.0.91

16 files

0.0.90

16 files

0.0.89

16 files

0.0.88

16 files

0.0.86

16 files

0.0.85

16 files

0.0.84

16 files

0.0.83

16 files

0.0.82

16 files

0.0.81

16 files

0.0.80

16 files

0.0.79

16 files

0.0.78

16 files

0.0.77

16 files

0.0.76

16 files

0.0.75

16 files

0.0.74

16 files

0.0.73

16 files

0.0.72

16 files

0.0.71

16 files

0.0.70

16 files

0.0.69

16 files

0.0.68

16 files

0.0.67

16 files

0.0.66

16 files

0.0.65

16 files

0.0.64

16 files

0.0.63

16 files

0.0.62

16 files

0.0.61

16 files

0.0.60

16 files

0.0.59

16 files

0.0.58

16 files

0.0.57

16 files

0.0.55

16 files

0.0.54

16 files

0.0.53

16 files

0.0.52

16 files

0.0.51

16 files

0.0.50

16 files

0.0.49

16 files

0.0.48

16 files

0.0.47

16 files

0.0.46

16 files

0.0.45

16 files

0.0.44

16 files

0.0.43

16 files

0.0.42

16 files

0.0.40

16 files

0.0.39

16 files

0.0.37

16 files

0.0.36

16 files

0.0.35

16 files

0.0.34

16 files

0.0.33

16 files

0.0.32

16 files

0.0.31

16 files

0.0.30

16 files

0.0.29

16 files

0.0.28

16 files

0.0.25

16 files

0.0.24

16 files

0.0.23

16 files

0.0.22

16 files

0.0.21

16 files

0.0.20

16 files

0.0.19

11 files

0.0.18

40 files

0.0.17

48 files

0.0.16

9 files

This release

0.0.15 This release

3 files

0.0.14

3 files

0.0.13

3 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page