A Rust reimplementation of pylint's error checking that produces byte-for-byte identical output to pylint — 15-84x faster
Project description
prylint
A Rust reimplementation of pylint that produces byte-for-byte identical output — 15–2300× faster (median ~85×).
prylint is not "inspired by" pylint. It is a bug-for-bug port: the same
messages, at the same lines and columns, with the same text, in the same
order, with the same exit codes and the same Your code has been rated
footer — verified byte-identically against real pylint on 52 production
codebases (~65,000 Python files), including django, numpy, pandas, sympy,
home-assistant, sqlalchemy, twisted, scikit-learn, and pylint's own functional
test suite. Where pylint has bugs, prylint reproduces them. Where pylint
crashes, prylint reports the same crash message.
Install
pip install prylint
Requirements: a python3 (≥3.9) on PATH (used only to mirror pylint's
module-resolution paths and to reproduce CPython's exact syntax-error messages
for unparseable files). pylint and astroid themselves are not required.
Usage
Use it exactly like pylint — full check mode is the default:
prylint . # all checks (like `pylint .`)
prylint -E . # errors only (like `pylint -E .`)
prylint --disable=C0114,... . # same --disable / --enable / inline pragmas
Output, message order, exit codes, the score footer, --rcfile /
pyproject.toml discovery, init-hook, and # pylint: pragmas all match
pylint 4.0.5.
Benchmarks
prylint . vs pylint . (both full check mode), pylint 4.0.5, Apple M-series,
single-threaded:
| codebase | pylint | prylint | speedup |
|---|---|---|---|
| black | 26.7 hr | 41s | 2328× |
| sentry | 3.7 hr | 24s | 546× |
| home-assistant (17.5k files) | 10.3 hr | 82s | 452× |
| airflow | 1.9 hr | 17s | 399× |
| salt | 1890s | 8.8s | 215× |
| zulip | 909s | 5.3s | 172× |
| django | 1524s | 10.1s | 150× |
| ansible | 419s | 2.9s | 143× |
| nova (OpenStack) | 1209s | 10.3s | 117× |
| fastapi | 116s | 1.0s | 120× |
| mypy | 367s | 3.9s | 95× |
| sqlalchemy | 614s | 7.1s | 87× |
| pandas | 1009s | 14.2s | 71× |
| scikit-learn | 613s | 9.6s | 64× |
| sympy | 1238s | 26s | 48× |
| …and 12 more, all ≥30× | |||
| aggregate (these 27) | 45.8 hr | 4.9 min | ~560× |
(These 27 are the large repos that are slow enough to time meaningfully; the full accuracy suite is 52 repos — see below.)
Median per-repo speedup ~85×; the aggregate is higher because pylint's
duplicate-code check (R0801) is O(n²) and dominates on test-heavy repos like
black. These are single-core numbers — the inference engine is
single-threaded to replicate astroid's order-sensitive global cache exactly
(see LIMITATIONS.md), and that byte-identical path is already
15–2300× pylint.
Every row above is also an accuracy test: each repo's full output is byte-identical to pylint's (see exceptions in LIMITATIONS.md).
Accuracy
prylint was built by differential testing against pinned pylint 4.0.5 / astroid 4.0.4 / CPython 3.12:
- AST fidelity — prylint's parse tree (built on the ruff parser) is compared node-by-node against astroid's (positions, scopes, locals, brain transforms) across all corpus files: zero differences.
- Inference fidelity — astroid's inference engine is ported exactly:
lazy-generator semantics, the 100-node inference budget, the bounded-LRU
caches (
lookup128,_metaclass_lookup_attribute1024) with their exact eviction, the 64-entry inference-tip FIFO,Uninferablepropagation. Every name/attribute/call node's inference is dumped and compared against astroid. - Output fidelity — full runs compared byte-for-byte, including message
order, module headers, the score footer,
# pylint:pragma handling (disable/enable blocks,disable-next,skip-file), config-file discovery, and exit-code bitmasks. - Blind testing — two batteries of 10 repos each were added after development and judged cold; every divergence was root-caused and fixed.
Known, documented exceptions (one obscure SQLAlchemy class; the deliberately
excluded no-member family; the places pylint is nondeterministic against
itself) are catalogued in LIMITATIONS.md.
How it works
- File discovery, message control, config parsing, and reporting are direct
ports of pylint's own logic (down to
os.walkordering, the************* Moduleheader rule, and the score-report footer). - Parsing uses ruff's Rust parser, then rebuilds astroid's exact tree shape (docstring extraction, decorator positions, implicit class locals, metaclass handling, brain transforms for dataclasses/enums/namedtuples/attrs/…).
- A full port of astroid's inference engine resolves names, calls, attributes, MROs, and operator protocols with astroid's exact conservatism — including its caches and their quirks, because the quirks are observable in the output.
- Files the Rust parser rejects are re-judged by CPython itself (an embedded,
stdlib-only helper) so syntax-error messages match
ast.parseexactly.
Reproducing the test suite
scripts/setup_corpora.sh clones all 52 corpora at pinned commits and builds
the pinned pylint/astroid ground-truth venv. The accuracy contract: every
change must keep the corpora byte-identical (harness/ holds the differential
comparators).
License
GPL-2.0-or-later, the same license as pylint — prylint reproduces pylint's message texts and behavior verbatim.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prylint-0.4.2.tar.gz.
File metadata
- Download URL: prylint-0.4.2.tar.gz
- Upload date:
- Size: 1.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0dea90b8bc79eb5e7412c180a9cf034a107cf6e1fea46f8cbe078775908db60f
|
|
| MD5 |
e9f5cb1c4cd317474aa07f156fb72280
|
|
| BLAKE2b-256 |
c7cf38edbebace645bb87f83909858382391fad6ca4596bd4aa9d3be5910e0d0
|
File details
Details for the file prylint-0.4.2-py3-none-win_amd64.whl.
File metadata
- Download URL: prylint-0.4.2-py3-none-win_amd64.whl
- Upload date:
- Size: 4.2 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55394ec3ead2d10652cbe29f820d14f0c03ec8b65d4430c89d57eb549e94d2f1
|
|
| MD5 |
cc90eebcdc13d73091cf150c82942e5d
|
|
| BLAKE2b-256 |
05031745da692b62eedc94dabb9fbc6572ff571e399ddb66b9bf6dc4530e36b6
|
File details
Details for the file prylint-0.4.2-py3-none-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: prylint-0.4.2-py3-none-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 4.3 MB
- Tags: Python 3, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16efe779edc96b8ae3228aef8d6f54c69a9d8114a862f5897e29cf6dc62c9917
|
|
| MD5 |
ca5863550a15653390e4567225157536
|
|
| BLAKE2b-256 |
041efe64feb4410656c601d83ef22615da8a9a634fbb4d9dd004062c119ea423
|
File details
Details for the file prylint-0.4.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: prylint-0.4.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.4 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c948478aa3bc14f0d38a25ebf34189d80d7918863ab1e2620d6727772b73dfe7
|
|
| MD5 |
c89a2642c299eb1f9b7f744c39d53f37
|
|
| BLAKE2b-256 |
aee59e1b9f44a0b70ab5285c89576ac001aa8b38ee1abf2c02c5b68790216ec8
|
File details
Details for the file prylint-0.4.2-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: prylint-0.4.2-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.2 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
019f94c6f05c0565b338661f45ddb0ba27253b513717834e1c5ddd8f5f72ac9e
|
|
| MD5 |
359343463a91dd9288ea6fb0a6984734
|
|
| BLAKE2b-256 |
4e9fa78aecdccf9631812a71e24bc2ac60ddbc9354b41681e984921fc2a5dfab
|
File details
Details for the file prylint-0.4.2-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: prylint-0.4.2-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.3 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a66f81442a185a90f41c74e6f971bb763ea05af9859487ff6273c6e866b79bf0
|
|
| MD5 |
503d9114ae433063494ae58028902754
|
|
| BLAKE2b-256 |
59f769c1084179fa97ee9140af196dc991a523c3aab9c507f0cfa7117a9b856a
|