Static checks distilled from real upstream bugs that off-the-shelf linters miss.
Project description
wildlint
Static checks distilled from real upstream bugs — the kind off-the-shelf linters miss because they look like ordinary, working code.
Every rule here was born from a concrete bug that was found and fixed in a public project, then generalized to the smallest static check that still catches the class without flooding you with false positives. If a bug could not be turned into a low-noise rule, it is documented as not-shipped rather than added as noise (see Not shipped).
Install
pip install wildlint
Use
wildlint path/to/code # scan a file or directory (default: .)
wildlint --select WL001,WL002 src/
wildlint --pedantic src/ # also run opt-in, higher-false-positive rules
Exits non-zero when anything is found, so it drops straight into CI or a pre-commit hook.
pre-commit
# .pre-commit-config.yaml
repos:
- repo: https://github.com/patchwright/wildlint
rev: v0.1.0
hooks:
- id: wildlint
CI (GitHub Actions)
- run: pip install wildlint
- run: wildlint src/
Rules
| Code | Tier | Catches | Distilled from |
|---|---|---|---|
| WL001 | default | x.replace(P, "") guarded by x.startswith(P)/endswith(P) — removes every occurrence, silently corrupting values that contain the marker twice. Meant str.removeprefix/removesuffix. |
nephila/giturlparse#149 |
| WL002 | pedantic | s.split(' ') where s.split() was meant — keeps empty tokens and skips whitespace collapsing/trimming, leaking blanks downstream. Advisory and opt-in: only an exact single-space literal fires, and it's frequently intentional. |
derek73/python-nameparser#164 |
| WL003 | pedantic | x[-k] with k >= 2 — IndexError when the sequence is shorter than k. Opt-in because deep negative indexing is often provably safe from context the checker can't see. |
savoirfairelinux/num2words#661 |
The default tier is WL001 only — it has effectively zero false positives. WL002
and WL003 are opt-in via --pedantic: real bug classes, but they also fire on
legitimate code, so the default stays strictly precision.
Each rule is verified against the actual pre-fix source of the project it came
from — see the tests, and the rule docstrings in src/wildlint/checkers.py.
Bugs considered but not shipped
Some real bugs do not generalize into a low-false-positive static rule. They are
recorded in NON_GENERALIZED in checkers.py so the reasoning is preserved:
- break-vs-continue (mnamer#371) — whether
breakshould becontinueis entirely loop-intent dependent. - sign-doubling (humanize#326) — a numeric-formatting concern, not a syntactic pattern.
- validation-branch-order (validators#463) — specific to one parser's control flow.
- radix-from-ignored-param (shortuuid#115) — requires matching a docstring contract to the implementation.
Adding a rule
A checker is any object with code, name, tier, and
check(tree, path) -> list[Finding]. Append an instance to CHECKERS in
checkers.py and add positive/negative tests mirroring the wild bug. That's the
whole extension surface — the suite grows one real bug at a time.
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
Built Distribution
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 wildlint-0.1.1.tar.gz.
File metadata
- Download URL: wildlint-0.1.1.tar.gz
- Upload date:
- Size: 10.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c269fbefb41e218a784bc746b280a782b856616cb8c07cf03bee3d0108486b2
|
|
| MD5 |
89de02cf3ed5c405d6d4cd9da8d52e48
|
|
| BLAKE2b-256 |
427e0f841300c528323637235e3dbf3042373a48aef17c8387818d955fc5457c
|
Provenance
The following attestation bundles were made for wildlint-0.1.1.tar.gz:
Publisher:
release.yml on patchwright/wildlint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wildlint-0.1.1.tar.gz -
Subject digest:
9c269fbefb41e218a784bc746b280a782b856616cb8c07cf03bee3d0108486b2 - Sigstore transparency entry: 1820426802
- Sigstore integration time:
-
Permalink:
patchwright/wildlint@32c1938d8a25fedbbfa2a4371a04f53d548d17bb -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/patchwright
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@32c1938d8a25fedbbfa2a4371a04f53d548d17bb -
Trigger Event:
push
-
Statement type:
File details
Details for the file wildlint-0.1.1-py3-none-any.whl.
File metadata
- Download URL: wildlint-0.1.1-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
795942598b0b2abd8c10a64c532aeea9557b7edb5ade4c138f9185011d520ed9
|
|
| MD5 |
8033160af708169e5041fd56752531f6
|
|
| BLAKE2b-256 |
73a8d1656e5ba232f9264e017c0f27c07d2c3a5a06177d74a9acb83840252f5f
|
Provenance
The following attestation bundles were made for wildlint-0.1.1-py3-none-any.whl:
Publisher:
release.yml on patchwright/wildlint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wildlint-0.1.1-py3-none-any.whl -
Subject digest:
795942598b0b2abd8c10a64c532aeea9557b7edb5ade4c138f9185011d520ed9 - Sigstore transparency entry: 1820426805
- Sigstore integration time:
-
Permalink:
patchwright/wildlint@32c1938d8a25fedbbfa2a4371a04f53d548d17bb -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/patchwright
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@32c1938d8a25fedbbfa2a4371a04f53d548d17bb -
Trigger Event:
push
-
Statement type: