Slop Dealer Tools / 002

Dealer Style Pylint

The same Pylint verdicts, 48.3% sooner. A drop-in build of Pylint and Astroid: two pip lines, your config and plugins unchanged, every number receipted.

The project

Same verdicts. Less waiting.

Pylint is the slowest step in a lot of Python CI pipelines. This build of Pylint and its inference engine Astroid produces exactly the same diagnostics, statistics and exit codes as upstream, and gets there sooner. It keeps the package names, the commands, your configuration, pragmas and plugins.

It came out of a measured search: teams of AI agents proposed changes, a fixed judge timed every candidate against upstream on a frozen corpus, and nothing counted unless the output matched upstream byte for byte. Then a maintainer-style review removed every change that could not be proven safe, and the release gates re-measured what was left. Pylint and Astroid are the work of their maintainers; Slop Dealer's contribution is the published optimisation work.

Measured performance

Read the comparison.

Against upstream Pylint and Astroid at the same commits, on a frozen 249-file corpus of real packages (Flask, Werkzeug, Jinja2, Click, Requests, urllib3, Rich): seven phases per round, paired rounds with the order alternated, one process per phase on an isolated core, output checked against upstream before any time is counted.

48.3% less whole-command wall time for python -m pylint on CPython 3.14 (42 of 42 paired rounds), with a 20% smaller peak memory footprint. The installed pylint command measured 43.1% faster than upstream's installed command, identical output.

CPythonDefault settingsBoth speed switches off
3.1448.3% (judge, 42/42)27.6%
3.1345.1%30.7%
3.1241.3%29.1%
3.1138.5%27.0%
3.1020.5%20.5%

On a second corpus of Django, SciPy, pydantic and Ansible slices the command saved 57.2% at the defaults and 50.8% with the switches off. No Windows or macOS timing is claimed; the wheels are pure Python and passed a Windows smoke test.

Where the time went

Three kinds of saving.

Less lint work. Cheaper ancestry lookups, a per-module summary of rare node kinds, indexed dispatch of Astroid's transforms, byte-level prefilters in a few checkers, less allocation in the inference plumbing. One to three percent each.

Less work on modules you never asked about. Every run rebuilds the standard-library modules your code imports, and most of their function bodies are never looked at. This release builds a dependency module's function bodies only when something reads them, and re-issues identical generated modules (namedtuples, enums) from a recorded template instead of re-parsing them. Both are exact: fully built, the trees are identical to upstream's, node for node.

A faster exit. CPython can spend a quarter to half of a Pylint command tearing down the Astroid graph after the result is written. The build returns the exit code first, but only when it owns the process: launched by the interpreter, no wrapper, no embedder, no coverage, no live thread, no atexit handler of yours. The collector's young-generation threshold is also raised tenfold on 3.14.

Both process-level changes switch off in one line:

PYLINT_FAST_EXIT=0 pylint ...       # or: pylint --fast-exit=no
PYLINT_GC_MULTIPLE=1 pylint ...     # or: pylint --gc-multiple=1

The stated contract: when the fast exit is taken, __del__ finalizers on cyclic plugin objects do not run. Register an atexit handler and it declines.

What it took

Fast was easy. Safe took longer.

The fastest tree the search produced was 47% faster, and a review found ten of its changes unsound: stale caches after public mutations, a diagnostic lost after a plugin transform, a wrapper's exit status taken over. Every one was removed or rebuilt in a form that passes the review's own witnesses. The gates then caught five extra warnings on pandas, bisected to one "harmless" skipped inference, and reverted it. The safe tree was slower. A last round of work on the modules nobody lints (above) then took it past the unsafe one, and that is the number published here.

We aimed for 50% and did not reach it. The last attempt, deferring attribute registration in dependency modules, would have cleared it, and a census showed it changes what gets registered in 8.8% of cases. It was left out.

Install and source

Install it. Check it.

python -m pip install --find-links "https://slopdealer.github.io/Dealer-Style-Pylint/wheels/find-links/" "astroid==4.4.0.dev0+league.3"
python -m pip install --find-links "https://slopdealer.github.io/Dealer-Style-Pylint/wheels/find-links/" "pylint==4.1.0.dev0+league.3"

Install both, as a pair; the find-links page pins the wheel hashes. pylint --version shows the +league.3 label. To go back, reinstall your previous pins with pip install --force-reinstall.

The repository has the README, the change log with every contract, the wheels and their checksums, an upstream-ready patch series with each mechanism as its own patch, the reviews, and every receipt behind the numbers on this page.

Try your own workload.

Corpus size, plugins, Python version and CI hardware all move the result. Run your usual command with both builds on the same machine, compare the output, and keep whichever you trust.

An independent Slop Dealer build. Pylint is distributed under GPL-2.0 and Astroid under LGPL-2.1; this derivative keeps both licences.