Find dead Python code with Ruff's Rust parser
Project description
Ghostbuster
Ghostbuster finds dead Python code without starting Python. It is a Rust command-line tool built directly on Ruff's parser, syntax tree, source ranges, and line index.
The project takes Vulture's practical dead-code model as its behavioral reference while keeping a small Rust-native interface and a slightly more precise distinction between normal names and object members.
Install
With a prebuilt binary from a tagged GitHub release,
or from PyPI under the ghostbuster-code distribution name:
uv tool install ghostbuster-code
The PyPI name is longer because the unrelated ghostbuster name was already taken. Both methods
install the same ghostbuster executable and do not require Python at runtime. To build the full
source checkout instead:
cargo install --git https://github.com/mazdak/ghostbuster --locked
Try it
cargo run -- src tests
Example output:
src/example.py:8: V103 unused function 'retired_handler' (60% confidence)
src/example.py:13: V201 unreachable code after 'return' (100% confidence)
Useful options:
ghostbuster --min-confidence 80 src
ghostbuster --exclude 'generated/**,vendor/**' .
ghostbuster --ignore-names 'visit_*,legacy_hook' src
ghostbuster --ignore-decorators '@app.route,@registry.*' src
ghostbuster --format json src > findings.json
Run ghostbuster --help for the complete interface. Explicit files are accepted regardless of
their extension. Directories are walked recursively for .py files while respecting Git and
standard ignore files.
Exit codes are designed for CI:
| Code | Meaning |
|---|---|
| 0 | No dead code found |
| 1 | A path could not be read or Python could not be parsed |
| 2 | Invalid command-line arguments or patterns |
| 3 | Dead code found |
Findings
| Code | Finding | Confidence |
|---|---|---|
| V101 | Unused attribute | 60% |
| V102 | Unused class | 60% |
| V103 | Unused function | 60% |
| V104 | Unused import | 90% |
| V105 | Unused method | 60% |
| V106 | Unused property | 60% |
| V107 | Unused variable or argument | 60% / 100% |
| V201 | Unreachable code | 100% |
Ghostbuster understands definitions and loads across all input files in one run. It also handles
common dynamic-Python signals such as __all__, getattr, hasattr, decorators, properties,
dunder conventions, pytest entry points, type comments, dynamic format strings, Vulture's packaged
protocol whitelists, and # noqa comments. Source files support Python's UTF-8 BOM plus common
PEP 263 encodings, including Latin-1, Macintosh encodings, and numeric cpNNN code pages. F401
suppresses V104 and F841 suppresses V107, so existing Ruff suppressions remain useful.
Reachability covers dead tails after return, raise, break, and continue; constant branches;
non-terminating while loops; terminal if, try, and exhaustive match branches; and nested
suites. Ruff's AST truthiness handles literals, with Vulture-compatible short-circuit evaluation
for constant and, or, and not expressions.
Why Ruff rather than a new parser?
Python syntax evolves quickly and source positions are easy to get subtly wrong. Ghostbuster uses
the same Rust crates as Ruff and ty for parsing, AST traversal, UTF-8 byte ranges, Unicode columns,
CRLF lines, and BOM handling. The five required crates are checked into vendor/ruff and pinned to
one upstream Git revision, so builds do not silently switch parser implementations.
Ghostbuster itself only implements the dead-code policy that those projects do not expose as a standalone public API. Pulling in ty's full database, module resolver, and type checker would make a simple scanner much larger without replacing that policy layer.
Vulture compatibility evaluation
The data-driven corpus in tests/vulture is derived from Vulture's upstream tests and pins the
exact source revision. It contains 46 cases: eight compare the complete result and collectively
cover V101–V107 plus V201; the other 38 project one diagnostic category so a focused reachability
test does not fail because an unrelated function in its snippet is also unused.
Ghostbuster deliberately preserves Vulture's project-wide bare-name behavior, which keeps the compatibility oracle stable across modules. Its precision improvement is narrower: normal names and object members live in separate namespaces, so a bare function call does not automatically mark every same-named method alive. Intentional differences are documented separately from missing compatibility behavior.
Development
Ghostbuster pins the same Rust 1.97 toolchain currently used by Ruff. The required checks are:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
cargo check --workspace --all-targets --all-features --locked --offline
The minimum supported Rust version is 1.95. The pinned 1.97 toolchain supplies the formatter and Clippy version used by CI. See CONTRIBUTING.md for the complete development workflow.
- Ruff source revision:
f34ad603f07c766f9c4941a2f23ae88c84812c93 - Vulture source revision:
2c21cb0ae2afa657e36f6a397cb573608a65d79e
Ghostbuster is intentionally not a crates.io package: its Ruff internals are pinned path dependencies. Build or install it from a complete source checkout, use the platform wheels on PyPI, or download a native release archive.
License
Ghostbuster is MIT licensed. Vendored Ruff code and Vulture-derived test data retain their upstream
MIT notices. See THIRD_PARTY.md for provenance and THIRD_PARTY.html for the
complete generated dependency notices shipped with releases.
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 Distributions
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 ghostbuster_code-0.1.0-py3-none-win_amd64.whl.
File metadata
- Download URL: ghostbuster_code-0.1.0-py3-none-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
692385bcf297ff449cc2f0d54e93b1f9c2f0f77a5344ca3062250e84e9bb46b5
|
|
| MD5 |
42f1590ec7a7970ce32c3bdfd2ea0cc9
|
|
| BLAKE2b-256 |
cc73e907c87854982dfe05c3b9bb8a694ca4862071922648a846bdab5d8fc38d
|
Provenance
The following attestation bundles were made for ghostbuster_code-0.1.0-py3-none-win_amd64.whl:
Publisher:
release.yml on mazdak/ghostbuster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ghostbuster_code-0.1.0-py3-none-win_amd64.whl -
Subject digest:
692385bcf297ff449cc2f0d54e93b1f9c2f0f77a5344ca3062250e84e9bb46b5 - Sigstore transparency entry: 2212185958
- Sigstore integration time:
-
Permalink:
mazdak/ghostbuster@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mazdak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ghostbuster_code-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: ghostbuster_code-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
007fc2cd30dba9eafd9b31629cae9223c89d64f55ea9f5c13100c5b7c596ed87
|
|
| MD5 |
d98f67262d23dad49efe11abf9ec64d4
|
|
| BLAKE2b-256 |
01bf83e3da80107df179662f19a4a57dc73dd608eaf5756794bab4d3daef5833
|
Provenance
The following attestation bundles were made for ghostbuster_code-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on mazdak/ghostbuster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ghostbuster_code-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
007fc2cd30dba9eafd9b31629cae9223c89d64f55ea9f5c13100c5b7c596ed87 - Sigstore transparency entry: 2212185903
- Sigstore integration time:
-
Permalink:
mazdak/ghostbuster@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mazdak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ghostbuster_code-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: ghostbuster_code-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8a3aac096dbdf43a2095224d3c990e0248dc7b086c7308ec59788f81937e575
|
|
| MD5 |
5b9608d739fff6679b0ede3634192462
|
|
| BLAKE2b-256 |
779e5dcc8705f53ea0c6994940fddbefdb007eae582db846b44178db8acc44e5
|
Provenance
The following attestation bundles were made for ghostbuster_code-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on mazdak/ghostbuster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ghostbuster_code-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
d8a3aac096dbdf43a2095224d3c990e0248dc7b086c7308ec59788f81937e575 - Sigstore transparency entry: 2212185877
- Sigstore integration time:
-
Permalink:
mazdak/ghostbuster@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mazdak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ghostbuster_code-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: ghostbuster_code-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.8 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59fd2b57366e779eb27b7bdd3edc49b6dcb510cd924117106a2386ce298ecda2
|
|
| MD5 |
3ca15273677b532f01faeca94624b908
|
|
| BLAKE2b-256 |
01f4ecf67f1827389a4a8d1c3c6893abb6a1862572d018043964bd6d4374151c
|
Provenance
The following attestation bundles were made for ghostbuster_code-0.1.0-py3-none-macosx_11_0_arm64.whl:
Publisher:
release.yml on mazdak/ghostbuster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ghostbuster_code-0.1.0-py3-none-macosx_11_0_arm64.whl -
Subject digest:
59fd2b57366e779eb27b7bdd3edc49b6dcb510cd924117106a2386ce298ecda2 - Sigstore transparency entry: 2212185982
- Sigstore integration time:
-
Permalink:
mazdak/ghostbuster@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mazdak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ghostbuster_code-0.1.0-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: ghostbuster_code-0.1.0-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.9 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81878ffcd015f9c36a413b75ce6a0b6136fa0430cdf2ba878170e9be9e236276
|
|
| MD5 |
87c322776be03b3b19c24d19f4876f45
|
|
| BLAKE2b-256 |
e075e470bbaa45ccf6de84e99b9026625ce0baf0330f77624b1a7e34e3040e2c
|
Provenance
The following attestation bundles were made for ghostbuster_code-0.1.0-py3-none-macosx_10_12_x86_64.whl:
Publisher:
release.yml on mazdak/ghostbuster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ghostbuster_code-0.1.0-py3-none-macosx_10_12_x86_64.whl -
Subject digest:
81878ffcd015f9c36a413b75ce6a0b6136fa0430cdf2ba878170e9be9e236276 - Sigstore transparency entry: 2212185929
- Sigstore integration time:
-
Permalink:
mazdak/ghostbuster@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mazdak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a703b6f6735409ad9d0c2392d3d7130787a9dcd5 -
Trigger Event:
push
-
Statement type: