culler 0.1.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
Binary file
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: culler
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Intended Audience :: Developers
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Programming Language :: Rust
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Classifier: Topic :: Utilities
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Summary: A precise Python dead-code analyzer.
|
|
21
|
+
Keywords: dead-code,static-analysis,python,cli,rust
|
|
22
|
+
Author: Beau Hayes-Pollard
|
|
23
|
+
License-Expression: MIT
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
26
|
+
Project-URL: Benchmark, https://github.com/beaubhp/culler/tree/main/benchmark
|
|
27
|
+
Project-URL: Homepage, https://github.com/beaubhp/culler
|
|
28
|
+
Project-URL: Issues, https://github.com/beaubhp/culler/issues
|
|
29
|
+
Project-URL: Repository, https://github.com/beaubhp/culler
|
|
30
|
+
|
|
31
|
+
# Culler
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/culler/)
|
|
34
|
+
[](https://pypi.org/project/culler/)
|
|
35
|
+
[](https://github.com/beaubhp/culler/actions/workflows/ci.yml)
|
|
36
|
+
[](https://github.com/beaubhp/culler/actions/workflows/package-check.yml)
|
|
37
|
+
[](https://github.com/beaubhp/culler/blob/main/LICENSE)
|
|
38
|
+
|
|
39
|
+
Culler is a fast, high-confidence dead-code analyzer for Python projects.
|
|
40
|
+
|
|
41
|
+
It is built in Rust, distributed as a single command-line tool, and designed to
|
|
42
|
+
find dead Python code without turning ordinary public APIs, exports, tests, or
|
|
43
|
+
dynamic Python edges into noisy findings.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
culler check .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<picture>
|
|
51
|
+
<source
|
|
52
|
+
media="(prefers-color-scheme: dark)"
|
|
53
|
+
srcset="benchmark/assets/runtime-dark.png"
|
|
54
|
+
>
|
|
55
|
+
<source
|
|
56
|
+
media="(prefers-color-scheme: light)"
|
|
57
|
+
srcset="benchmark/assets/runtime-light.png"
|
|
58
|
+
>
|
|
59
|
+
<img
|
|
60
|
+
width="49%"
|
|
61
|
+
alt="Runtime benchmark comparing Culler, Vulture, and deadcode"
|
|
62
|
+
src="https://raw.githubusercontent.com/beaubhp/culler/main/benchmark/assets/runtime-dark.png"
|
|
63
|
+
>
|
|
64
|
+
</picture>
|
|
65
|
+
<picture>
|
|
66
|
+
<source
|
|
67
|
+
media="(prefers-color-scheme: dark)"
|
|
68
|
+
srcset="benchmark/assets/f1-dark.png"
|
|
69
|
+
>
|
|
70
|
+
<source
|
|
71
|
+
media="(prefers-color-scheme: light)"
|
|
72
|
+
srcset="benchmark/assets/f1-light.png"
|
|
73
|
+
>
|
|
74
|
+
<img
|
|
75
|
+
width="49%"
|
|
76
|
+
alt="F1 benchmark comparing Culler high-plus-review, Culler, Vulture, and deadcode"
|
|
77
|
+
src="https://raw.githubusercontent.com/beaubhp/culler/main/benchmark/assets/f1-dark.png"
|
|
78
|
+
>
|
|
79
|
+
</picture>
|
|
80
|
+
</p>
|
|
81
|
+
|
|
82
|
+
<p align="center">
|
|
83
|
+
<sub>
|
|
84
|
+
Left: median wall-clock runtime, where lower is better. Right: F1 score,
|
|
85
|
+
the balance between precision and recall, where higher is better.
|
|
86
|
+
</sub>
|
|
87
|
+
</p>
|
|
88
|
+
|
|
89
|
+
Benchmark: 15 realistic Python projects, 57,068 lines, 715 expected findings,
|
|
90
|
+
and comparisons against Vulture and deadcode. Results are corpus-specific; the
|
|
91
|
+
methodology and reproduction commands are below.
|
|
92
|
+
|
|
93
|
+
## Highlights
|
|
94
|
+
|
|
95
|
+
- **High-confidence findings by default.** Culler reports the findings it can
|
|
96
|
+
support strongly, and keeps review-confidence findings available separately.
|
|
97
|
+
- **Whole-project reachability for applications.** Production roots let Culler
|
|
98
|
+
identify code that is unreachable from known entry points.
|
|
99
|
+
- **Conservative library analysis.** Exports, public surfaces, tests, and
|
|
100
|
+
dynamic behavior are handled carefully to avoid noisy reports.
|
|
101
|
+
- **Useful without heavy setup.** Basic unused-code checks work with little or
|
|
102
|
+
no configuration, and deeper reachability is enabled with `pyproject.toml`.
|
|
103
|
+
- **Automation-friendly output.** JSON output uses stable rule and diagnostic
|
|
104
|
+
identifiers for editors, dashboards, CI, and benchmark tooling.
|
|
105
|
+
|
|
106
|
+
## Installation
|
|
107
|
+
|
|
108
|
+
The recommended installation methods for the CLI are `uv tool` and `pipx`:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv tool install culler
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pipx install culler
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You can also install it into an existing Python environment:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -m pip install culler
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The PyPI package installs the compiled `culler` binary. It does not expose a
|
|
125
|
+
Python import API yet.
|
|
126
|
+
|
|
127
|
+
## Quick Start
|
|
128
|
+
|
|
129
|
+
Run Culler on the current project:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
culler check .
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Emit machine-readable JSON:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
culler check . --format json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Show review-confidence findings as well as high-confidence findings:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
culler check . --show-review
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Explain a specific candidate or finding:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
culler explain <candidate-or-finding-id> .
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Exit codes are intentionally small:
|
|
154
|
+
|
|
155
|
+
| Code | Meaning |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| `0` | Analysis completed without default-visible findings. |
|
|
158
|
+
| `1` | Analysis completed and default-visible findings were reported. |
|
|
159
|
+
| `2` | Input, configuration, parse, or completeness error. |
|
|
160
|
+
|
|
161
|
+
## Configuration
|
|
162
|
+
|
|
163
|
+
Culler reads configuration from `pyproject.toml`.
|
|
164
|
+
|
|
165
|
+
```toml
|
|
166
|
+
[tool.culler]
|
|
167
|
+
src = "src"
|
|
168
|
+
mode = "auto"
|
|
169
|
+
target-python = "3.12"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
For applications, declare production roots when you want reachability findings:
|
|
173
|
+
|
|
174
|
+
```toml
|
|
175
|
+
[tool.culler]
|
|
176
|
+
src = "src"
|
|
177
|
+
mode = "application"
|
|
178
|
+
root_coverage = "complete"
|
|
179
|
+
roots = ["my_app.cli:main"]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For libraries, Culler treats exported and externally visible surfaces more
|
|
183
|
+
conservatively:
|
|
184
|
+
|
|
185
|
+
```toml
|
|
186
|
+
[tool.culler]
|
|
187
|
+
src = "src"
|
|
188
|
+
mode = "library"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Useful fields:
|
|
192
|
+
|
|
193
|
+
| Field | Purpose |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| `src` | Source root or roots to analyze. |
|
|
196
|
+
| `mode` | `auto`, `application`, or `library`. |
|
|
197
|
+
| `root_coverage` | `partial` or `complete` when roots are known. |
|
|
198
|
+
| `roots` | Application entry points such as `pkg.cli:main`. |
|
|
199
|
+
| `tests` | Test paths when they are not discoverable conventionally. |
|
|
200
|
+
| `target-python` | Python syntax/semantic target, currently `3.10` through `3.15`. |
|
|
201
|
+
| `exclude` | Glob patterns to exclude from analysis. |
|
|
202
|
+
| `allow_partial` | Permit partial analysis without escalating to exit code `2`. |
|
|
203
|
+
|
|
204
|
+
## Output and Rules
|
|
205
|
+
|
|
206
|
+
Text output is optimized for local development and CI logs. JSON output is
|
|
207
|
+
intended for editors, dashboards, benchmarks, and automation.
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
culler check . --format json
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Rule IDs are stable machine-readable identifiers:
|
|
214
|
+
|
|
215
|
+
| Rule | Finding |
|
|
216
|
+
| --- | --- |
|
|
217
|
+
| `CULL001` | Unreferenced function. |
|
|
218
|
+
| `CULL002` | Unreferenced class. |
|
|
219
|
+
| `CULL003` | Root-unreachable function. |
|
|
220
|
+
| `CULL004` | Root-unreachable class. |
|
|
221
|
+
| `CULL005` | Unused import binding. |
|
|
222
|
+
| `CULL006` | Unused local binding. |
|
|
223
|
+
| `CULL007` | Unreachable statement range. |
|
|
224
|
+
| `CULL008` | Unused private method. |
|
|
225
|
+
|
|
226
|
+
Diagnostic IDs such as `CULL_P0101` describe analysis, parsing, or
|
|
227
|
+
configuration problems.
|
|
228
|
+
|
|
229
|
+
## Benchmark Methodology
|
|
230
|
+
|
|
231
|
+
The benchmark compares Culler with Vulture and deadcode on one fixed corpus of
|
|
232
|
+
artificial but realistic Python projects. The projects are artificial because
|
|
233
|
+
precision and recall need ground truth; many real repositories contain little
|
|
234
|
+
confirmed dead code, and exhaustive manual labeling is subjective. The corpus is
|
|
235
|
+
designed to resemble code developers commonly inherit: services, libraries,
|
|
236
|
+
CLIs, workers, pipelines, plugin systems, configuration packages, and
|
|
237
|
+
utility-heavy AI-era codebases.
|
|
238
|
+
|
|
239
|
+
| Scope | Value |
|
|
240
|
+
| --- | ---: |
|
|
241
|
+
| Projects | 15 |
|
|
242
|
+
| Python files | 374 |
|
|
243
|
+
| Python LOC | 57,068 |
|
|
244
|
+
| Expected findings | 715 |
|
|
245
|
+
| Clean projects | 2 |
|
|
246
|
+
| Large or noisy projects | 2 |
|
|
247
|
+
|
|
248
|
+
The expected findings live under `benchmark/expected/` and use comparable
|
|
249
|
+
categories: unused imports, unused locals, unreachable statements, unused
|
|
250
|
+
functions, unused classes, and unused private methods.
|
|
251
|
+
|
|
252
|
+
### Tool Scope
|
|
253
|
+
|
|
254
|
+
| Tool | Why included |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| Culler | Subject under evaluation. |
|
|
257
|
+
| Vulture | Classic Python dead-code detector. |
|
|
258
|
+
| deadcode | Newer whole-codebase Python unused-code detector. |
|
|
259
|
+
|
|
260
|
+
Ruff, Pylint, Pyflakes, Flake8, autoflake, pycln, and unimport are not included
|
|
261
|
+
in the headline comparison. They overlap on some unused-import or unused-local
|
|
262
|
+
checks, but they are linters or cleanup tools rather than direct whole-project
|
|
263
|
+
dead-code analyzers.
|
|
264
|
+
|
|
265
|
+
### Scoring
|
|
266
|
+
|
|
267
|
+
Every expected finding not matched by a tool is a false negative. Every parsed
|
|
268
|
+
tool finding in a scoreable category that does not match an expected finding is
|
|
269
|
+
a false positive, including findings in clean projects. Matching is
|
|
270
|
+
deterministic by category, path, symbol name where relevant, and source span;
|
|
271
|
+
duplicate reports count once as a true positive and then as false positives.
|
|
272
|
+
|
|
273
|
+
Culler's headline score uses high-confidence findings. The benchmark also
|
|
274
|
+
reports a Culler high-plus-review aggregate, which includes review-confidence
|
|
275
|
+
findings from the same Culler JSON run. It does not represent a separate timed
|
|
276
|
+
CLI invocation.
|
|
277
|
+
|
|
278
|
+
### Runtime
|
|
279
|
+
|
|
280
|
+
Runtime includes subprocess startup time. That reflects command-line user
|
|
281
|
+
experience and avoids special-casing tools written in different languages. By
|
|
282
|
+
default, each tool gets one warmup run and five measured runs per project; the
|
|
283
|
+
report uses median wall time. Result JSON records command lines, tool versions,
|
|
284
|
+
Python version, OS, CPU, memory, and the Culler commit.
|
|
285
|
+
|
|
286
|
+
Peak RSS is recorded where `/usr/bin/time -l` exposes it. If unavailable, the
|
|
287
|
+
result uses `null`.
|
|
288
|
+
|
|
289
|
+
### Running the Benchmark
|
|
290
|
+
|
|
291
|
+
Validate the corpus and expected files:
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
python3 benchmark/run.py --validate-only
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Run the benchmark runner self-tests:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
python3 benchmark/test_run.py
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Build Culler and run the full benchmark:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
cargo build --release
|
|
307
|
+
python3 benchmark/run.py \
|
|
308
|
+
--culler target/release/culler \
|
|
309
|
+
--tools culler,vulture,deadcode \
|
|
310
|
+
--runs 5 \
|
|
311
|
+
--results benchmark/results/latest.json
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Generated reports are written under `benchmark/results/` and ignored by
|
|
315
|
+
default. Raw tool outputs are retained under `benchmark/results/raw/`.
|
|
316
|
+
|
|
317
|
+
## Development
|
|
318
|
+
|
|
319
|
+
Prerequisites:
|
|
320
|
+
|
|
321
|
+
- Rust 1.82 or newer
|
|
322
|
+
- Python 3.10 or newer
|
|
323
|
+
- `uv` for packaging and benchmark helper commands
|
|
324
|
+
|
|
325
|
+
Core checks:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
cargo fmt --all --check
|
|
329
|
+
cargo check
|
|
330
|
+
cargo clippy --all-targets --all-features -- -D warnings
|
|
331
|
+
cargo test
|
|
332
|
+
python3 benchmark/test_run.py
|
|
333
|
+
python3 benchmark/run.py --validate-only
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Build the PyPI package locally:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
uvx maturin build --release --out dist --sdist
|
|
340
|
+
uvx twine check dist/*
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Status
|
|
344
|
+
|
|
345
|
+
Culler is pre-1.0 software. Rule IDs are intended to be stable, but CLI,
|
|
346
|
+
configuration, and JSON output details may still evolve before `1.0`.
|
|
347
|
+
|
|
348
|
+
Releases use reviewed PRs and changelog updates. See
|
|
349
|
+
[`CONTRIBUTING.md`](https://github.com/beaubhp/culler/blob/main/CONTRIBUTING.md)
|
|
350
|
+
for commit and release guidance.
|
|
351
|
+
|
|
352
|
+
## License
|
|
353
|
+
|
|
354
|
+
Culler is released under the MIT License. See
|
|
355
|
+
[`LICENSE`](https://github.com/beaubhp/culler/blob/main/LICENSE).
|
|
356
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
culler-0.1.0.data/scripts/culler.exe,sha256=mf6ZM6o1hB72EYvh7rmd1Ji6j0GkLkOETVnvnfeU60E,5691904
|
|
2
|
+
culler-0.1.0.dist-info/METADATA,sha256=b1LJjTIl8n10Huvk01m-7-mY5uRlHV4irZ-7VQzv3sM,11361
|
|
3
|
+
culler-0.1.0.dist-info/WHEEL,sha256=2zDlIYIdD4m4N3p5DVEG3iJhGLdhsBQgdH-FqVkAur8,94
|
|
4
|
+
culler-0.1.0.dist-info/licenses/LICENSE,sha256=OrV7tYI_7Ido1ujE-NbSnB22SEPOlf3YKjTonpFjw6E,1096
|
|
5
|
+
culler-0.1.0.dist-info/sboms/culler-cli.cyclonedx.json,sha256=VNq7z7EaLk7Rm-aDjohuEwPtfT7g55c2tDeOcPsJ1TU,125694
|
|
6
|
+
culler-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Beau Hayes-Pollard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|