gwc-pybundle 1.4.5__py3-none-any.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.
Potentially problematic release.
This version of gwc-pybundle might be problematic. Click here for more details.
- gwc_pybundle-1.4.5.dist-info/METADATA +876 -0
- gwc_pybundle-1.4.5.dist-info/RECORD +55 -0
- gwc_pybundle-1.4.5.dist-info/WHEEL +5 -0
- gwc_pybundle-1.4.5.dist-info/entry_points.txt +2 -0
- gwc_pybundle-1.4.5.dist-info/licenses/LICENSE.md +25 -0
- gwc_pybundle-1.4.5.dist-info/top_level.txt +1 -0
- pybundle/__init__.py +0 -0
- pybundle/__main__.py +4 -0
- pybundle/cli.py +365 -0
- pybundle/context.py +362 -0
- pybundle/doctor.py +148 -0
- pybundle/filters.py +178 -0
- pybundle/manifest.py +77 -0
- pybundle/packaging.py +45 -0
- pybundle/policy.py +132 -0
- pybundle/profiles.py +340 -0
- pybundle/roadmap_model.py +42 -0
- pybundle/roadmap_scan.py +295 -0
- pybundle/root_detect.py +14 -0
- pybundle/runner.py +163 -0
- pybundle/steps/__init__.py +26 -0
- pybundle/steps/bandit.py +72 -0
- pybundle/steps/base.py +20 -0
- pybundle/steps/compileall.py +76 -0
- pybundle/steps/context_expand.py +272 -0
- pybundle/steps/copy_pack.py +293 -0
- pybundle/steps/coverage.py +101 -0
- pybundle/steps/cprofile_step.py +155 -0
- pybundle/steps/dependency_sizes.py +120 -0
- pybundle/steps/duplication.py +94 -0
- pybundle/steps/error_refs.py +204 -0
- pybundle/steps/handoff_md.py +167 -0
- pybundle/steps/import_time.py +165 -0
- pybundle/steps/interrogate.py +84 -0
- pybundle/steps/license_scan.py +96 -0
- pybundle/steps/line_profiler.py +108 -0
- pybundle/steps/memory_profile.py +173 -0
- pybundle/steps/mutation_testing.py +136 -0
- pybundle/steps/mypy.py +60 -0
- pybundle/steps/pip_audit.py +45 -0
- pybundle/steps/pipdeptree.py +61 -0
- pybundle/steps/pylance.py +562 -0
- pybundle/steps/pytest.py +66 -0
- pybundle/steps/radon.py +121 -0
- pybundle/steps/repro_md.py +161 -0
- pybundle/steps/rg_scans.py +78 -0
- pybundle/steps/roadmap.py +153 -0
- pybundle/steps/ruff.py +111 -0
- pybundle/steps/shell.py +74 -0
- pybundle/steps/slow_tests.py +170 -0
- pybundle/steps/test_flakiness.py +172 -0
- pybundle/steps/tree.py +116 -0
- pybundle/steps/unused_deps.py +112 -0
- pybundle/steps/vulture.py +83 -0
- pybundle/tools.py +63 -0
|
@@ -0,0 +1,876 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gwc-pybundle
|
|
3
|
+
Version: 1.4.5
|
|
4
|
+
Summary: Deterministic Python project context bundling for humans, automation, and AI
|
|
5
|
+
Author-email: Jessica Brown <jessica@codenamejessica.com>
|
|
6
|
+
License: The MIT License (MIT)
|
|
7
|
+
=====================
|
|
8
|
+
|
|
9
|
+
Copyright © 2025 Jessica Brown
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person
|
|
12
|
+
obtaining a copy of this software and associated documentation
|
|
13
|
+
files (the “Software”), to deal in the Software without
|
|
14
|
+
restriction, including without limitation the rights to use,
|
|
15
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the
|
|
17
|
+
Software is furnished to do so, subject to the following
|
|
18
|
+
conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be
|
|
21
|
+
included in all copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
24
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
25
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
26
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
27
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
28
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
29
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
30
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
31
|
+
Project-URL: Homepage, https://github.com/girls-whocode/pybundle
|
|
32
|
+
Project-URL: Repository, https://github.com/girls-whocode/pybundle
|
|
33
|
+
Project-URL: Issues, https://github.com/girls-whocode/pybundle/issues
|
|
34
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
43
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
44
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
License-File: LICENSE.md
|
|
48
|
+
Requires-Dist: colorama>=0.4.6
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
|
|
51
|
+
# 🧳 pybundle 
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
[](https://pypi.org/project/gwc-pybundle/)
|
|
56
|
+
[](LICENSE.md)
|
|
57
|
+
[](https://pepy.tech/projects/gwc-pybundle)
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
[](https://github.com/girls-whocode/pybundle/actions)
|
|
61
|
+
[](https://github.com/astral-sh/ruff)
|
|
62
|
+
[](https://mypy-lang.org/)
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
**pybundle** is a deterministic, automation-friendly CLI that captures Python project context into a single, reproducible bundle — ideal for debugging, CI artifacts, audits, and AI-assisted workflows.
|
|
67
|
+
|
|
68
|
+
It produces **machine-readable outputs first**, with optional human-readable summaries layered on top.
|
|
69
|
+
|
|
70
|
+
> Think “`git archive` + diagnostics + metadata”, without guessing or heuristics.
|
|
71
|
+
|
|
72
|
+
> **Note:** The PyPI package name is `gwc-pybundle`, but the tool is installed and used as `pybundle`.
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🧠 Why pybundle exists
|
|
76
|
+
|
|
77
|
+
Modern software development compresses what used to be entire teams into a single role.
|
|
78
|
+
|
|
79
|
+
Today, one developer is often responsible for:
|
|
80
|
+
- application code
|
|
81
|
+
- build systems
|
|
82
|
+
- test tooling
|
|
83
|
+
- deployment logic
|
|
84
|
+
- CI/CD behavior
|
|
85
|
+
- environment differences
|
|
86
|
+
- security implications
|
|
87
|
+
- and increasingly, AI-assisted workflows
|
|
88
|
+
|
|
89
|
+
The problem is no longer *how* to write code.
|
|
90
|
+
|
|
91
|
+
It’s answering:
|
|
92
|
+
|
|
93
|
+
> **“Why is this system behaving the way it is?”**
|
|
94
|
+
|
|
95
|
+
That question is hard to answer when:
|
|
96
|
+
- context is scattered
|
|
97
|
+
- tooling output is ephemeral
|
|
98
|
+
- environment details are lost
|
|
99
|
+
- source snapshots are incomplete or noisy
|
|
100
|
+
|
|
101
|
+
AI didn’t create this problem - it exposed it.
|
|
102
|
+
|
|
103
|
+
Large language models don’t fail because they lack intelligence.
|
|
104
|
+
They fail because we give them **uncurated context**.
|
|
105
|
+
|
|
106
|
+
Humans don’t fail because they can’t debug.
|
|
107
|
+
They fail because the **cost of reconstructing context** exceeds the time they have.
|
|
108
|
+
|
|
109
|
+
**pybundle exists to reduce context debt.**
|
|
110
|
+
|
|
111
|
+
It captures *what matters*, ignores what doesn’t, and produces a deterministic artifact that explains:
|
|
112
|
+
- what code exists
|
|
113
|
+
- what tools ran
|
|
114
|
+
- what environment was used
|
|
115
|
+
- and why the outputs exist
|
|
116
|
+
|
|
117
|
+
For humans, automation, and AI alike.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## ✨ Features
|
|
122
|
+
|
|
123
|
+
* 📦 **Single archive output** (`.zip` or `.tar.gz`)
|
|
124
|
+
* 🧠 **Machine-readable manifest** (`MANIFEST.json`) for automation
|
|
125
|
+
* 🧾 **Structured summaries** (`SUMMARY.json`)
|
|
126
|
+
* 🧭 **Respects `.gitignore`** exactly when available
|
|
127
|
+
* 🛑 **Safely ignores virtualenvs and caches** (even with non-standard names)
|
|
128
|
+
* 🔍 Optional tooling checks (ruff, mypy, pytest, pylance, bandit, pip-audit, coverage)
|
|
129
|
+
* 🛡️ Security scanning (bandit for code issues, pip-audit for dependency CVEs)
|
|
130
|
+
* 🧪 Deterministic output (stable paths, timestamps, schemas)
|
|
131
|
+
* 🔒 Secret-safe (optional redaction)
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 📂 What’s in a pybundle archive?
|
|
136
|
+
|
|
137
|
+
At minimum, a bundle contains:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
MANIFEST.json # stable, machine-readable metadata
|
|
141
|
+
SUMMARY.json # structured summary of collected data
|
|
142
|
+
src/ # filtered project source snapshot
|
|
143
|
+
logs/ # tool outputs (ruff, mypy, pytest, pylance, bandit, pip-audit, coverage, rg scans)
|
|
144
|
+
meta/ # environment + tool detection
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `MANIFEST.json` (automation fuel)
|
|
148
|
+
|
|
149
|
+
Includes:
|
|
150
|
+
|
|
151
|
+
* tool paths detected
|
|
152
|
+
* options used
|
|
153
|
+
* archive name + format
|
|
154
|
+
* git commit hash (if available)
|
|
155
|
+
* UTC timestamp
|
|
156
|
+
* schema version (stable)
|
|
157
|
+
|
|
158
|
+
Another script can fully understand a bundle **without reading markdown**.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 🚀 Installation
|
|
163
|
+
|
|
164
|
+
We recommend using a Python virtual environment for development tooling.
|
|
165
|
+
|
|
166
|
+
### Quick installation (pybundle tooling) - RECOMMENDED
|
|
167
|
+
|
|
168
|
+
Create a dedicated requirements file in the root of your project:
|
|
169
|
+
|
|
170
|
+
```txt
|
|
171
|
+
# requirements-pybundle.txt
|
|
172
|
+
ruff
|
|
173
|
+
mypy
|
|
174
|
+
pytest
|
|
175
|
+
pytest-cov
|
|
176
|
+
bandit
|
|
177
|
+
pip-audit
|
|
178
|
+
gwc-pybundle==1.3.1
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Then install:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
pip install -r requirements-pybundle.txt
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
> **System dependency:**
|
|
188
|
+
> pybundle uses `ripgrep (rg)` for source scanning and expects the system binary.
|
|
189
|
+
>
|
|
190
|
+
> * macOS: `brew install ripgrep`
|
|
191
|
+
> * Ubuntu/Debian: `sudo apt install ripgrep`
|
|
192
|
+
> * Fedora: `sudo dnf install ripgrep`
|
|
193
|
+
|
|
194
|
+
After installation, run:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
pybundle run analysis
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
A new `artifacts/` directory will be created containing:
|
|
201
|
+
|
|
202
|
+
* the compressed bundle
|
|
203
|
+
* an extracted working directory
|
|
204
|
+
* machine-readable metadata (`MANIFEST.json`, `SUMMARY.json`)
|
|
205
|
+
|
|
206
|
+
See **Usage** for more details.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### Advanced installation
|
|
211
|
+
|
|
212
|
+
#### From GitHub
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pip install "gwc-pybundle @ git+https://github.com/girls-whocode/pybundle.git@v1.3.1"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Pinning to a tag ensures reproducible behavior.
|
|
219
|
+
|
|
220
|
+
#### Editable install (for development)
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pip install -e .
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 🧪 Usage
|
|
229
|
+
|
|
230
|
+
From the root of a Python project, run a profile using the `run` command:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
pybundle run analysis
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
This builds a timestamped diagnostic bundle under the default `artifacts/` directory.
|
|
237
|
+
|
|
238
|
+
### Profiles
|
|
239
|
+
|
|
240
|
+
Profiles define *what* pybundle collects and *which tools* are run.
|
|
241
|
+
|
|
242
|
+
**Available profiles** (v1.4.3+):
|
|
243
|
+
|
|
244
|
+
* **`analysis`** - What the code IS (structure, metrics, dependencies, docs)
|
|
245
|
+
- Code structure, complexity metrics, documentation coverage
|
|
246
|
+
- Dependency analysis, licenses, performance profiling
|
|
247
|
+
- No error detection or linting
|
|
248
|
+
|
|
249
|
+
* **`debug`** - What's WRONG with the code (errors, issues, problems)
|
|
250
|
+
- Linting, type checking, testing, security scans
|
|
251
|
+
- Error context extraction, anti-pattern detection
|
|
252
|
+
- Includes everything needed for troubleshooting
|
|
253
|
+
|
|
254
|
+
* **`ai`** - Debug optimized for AI (reduced noise, problem-focused)
|
|
255
|
+
- Same as debug but with defaults tuned for AI consumption
|
|
256
|
+
|
|
257
|
+
* **`backup`** - Minimal snapshot (source + git + env, no analysis)
|
|
258
|
+
|
|
259
|
+
To list all available profiles:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
pybundle list-profiles
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Profiles are always invoked via:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
pybundle run <profile>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### 💾 Backup profile
|
|
274
|
+
|
|
275
|
+
The `backup` profile creates a minimal, lightweight snapshot ideal for version archival or disaster recovery.
|
|
276
|
+
|
|
277
|
+
Run it with:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
pybundle run backup
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### What `backup` includes
|
|
284
|
+
|
|
285
|
+
* ✅ Full source code snapshot (respects `.gitignore`)
|
|
286
|
+
* ✅ Git status and diff (`meta/00_git_status.txt`, `meta/01_git_diff.txt`)
|
|
287
|
+
* ✅ Python version (`meta/20_python_version.txt`)
|
|
288
|
+
* ✅ Installed packages (`meta/22_pip_freeze.txt`)
|
|
289
|
+
* ✅ Copy manifest (`meta/50_copy_manifest.txt`)
|
|
290
|
+
* ❌ No linting, type-checking, or tests
|
|
291
|
+
* ❌ No security scanning
|
|
292
|
+
* ❌ No ripgrep scans
|
|
293
|
+
|
|
294
|
+
The result is a **fast, small, restorable archive** with just source code and environment context.
|
|
295
|
+
|
|
296
|
+
#### Restoring a backup
|
|
297
|
+
|
|
298
|
+
Backups are created as either `.zip` or `.tar.gz` archives (see Archive Format below).
|
|
299
|
+
|
|
300
|
+
To extract and inspect:
|
|
301
|
+
|
|
302
|
+
**For .zip archives:**
|
|
303
|
+
```bash
|
|
304
|
+
# Look for filename with *_backup_<TIMESTAMP>.zip
|
|
305
|
+
unzip <FILENAME>.zip -d restored/
|
|
306
|
+
cd restored/<FILENAME>/
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**For .tar.gz archives:**
|
|
310
|
+
```bash
|
|
311
|
+
# Look for filename with *_backup_<TIMESTAMP>.tar.gz
|
|
312
|
+
tar -xzf <FILENAME>.tar.gz -C restored/
|
|
313
|
+
cd restored/<FILENAME>/
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Inside the extracted directory:
|
|
317
|
+
|
|
318
|
+
```text
|
|
319
|
+
src/ # Your project source code
|
|
320
|
+
meta/
|
|
321
|
+
00_git_status.txt # Git working tree status at backup time
|
|
322
|
+
01_git_diff.txt # Uncommitted changes (if any)
|
|
323
|
+
20_python_version.txt # Python version used
|
|
324
|
+
22_pip_freeze.txt # Exact package versions
|
|
325
|
+
50_copy_manifest.txt # List of files included
|
|
326
|
+
MANIFEST.json # Machine-readable metadata
|
|
327
|
+
SUMMARY.json # Structured summary
|
|
328
|
+
RUN_LOG.txt # Execution log
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
The `src/` directory contains your complete project structure.
|
|
332
|
+
The `meta/22_pip_freeze.txt` file can be used to recreate the exact environment:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
python -m venv venv
|
|
336
|
+
source venv/bin/activate # or venv\Scripts\activate on Windows
|
|
337
|
+
pip install -r meta/22_pip_freeze.txt
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Then copy your source code back:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
cp -r src/* /path/to/your/project/
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### Archive format fallback
|
|
347
|
+
|
|
348
|
+
pybundle uses **zip** by default for maximum portability.
|
|
349
|
+
|
|
350
|
+
If the `zip` command is not available on your system, pybundle **automatically falls back to tar.gz** format without requiring configuration.
|
|
351
|
+
|
|
352
|
+
This ensures backups can be created on any system, regardless of installed compression tools.
|
|
353
|
+
|
|
354
|
+
To explicitly control the format:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
pybundle run backup --format zip # Force zip (requires zip command)
|
|
358
|
+
pybundle run backup --format tar.gz # Force tar.gz (requires tar command)
|
|
359
|
+
pybundle run backup --format auto # Auto-detect (default behavior)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Both formats preserve the same internal structure and metadata.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### 🔍 Analysis Tools
|
|
367
|
+
|
|
368
|
+
The `analysis` and `debug` profiles run comprehensive quality and security checks:
|
|
369
|
+
|
|
370
|
+
#### Code Quality
|
|
371
|
+
* **ruff** - Fast Python linter and formatter checks
|
|
372
|
+
* **mypy** - Static type checking for type hints
|
|
373
|
+
* **pylance** - Syntax error detection and import analysis
|
|
374
|
+
* **vulture** - Dead code detection (v1.3.0+)
|
|
375
|
+
* **radon** - Cyclomatic complexity and maintainability metrics (v1.3.0+)
|
|
376
|
+
* **interrogate** - Docstring coverage analysis (v1.3.0+)
|
|
377
|
+
* **pylint duplication** - Code duplication detection (v1.3.0+)
|
|
378
|
+
|
|
379
|
+
#### Testing & Coverage
|
|
380
|
+
* **pytest** - Test execution and results
|
|
381
|
+
* **coverage** - Code coverage analysis (shows tested vs untested code)
|
|
382
|
+
|
|
383
|
+
#### Security
|
|
384
|
+
* **bandit** - Security vulnerability scanning for Python code
|
|
385
|
+
* **pip-audit** - Dependency vulnerability checking against known CVEs
|
|
386
|
+
|
|
387
|
+
#### Dependency Analysis (v1.3.1+)
|
|
388
|
+
* **pipdeptree** - Full dependency tree with conflict detection
|
|
389
|
+
* **unused dependencies** - Identify installed but unused packages
|
|
390
|
+
* **pip-licenses** - License scanning and compatibility warnings
|
|
391
|
+
* **dependency sizes** - Disk usage analysis per package
|
|
392
|
+
|
|
393
|
+
#### Performance Profiling (v1.4.0+)
|
|
394
|
+
* **cProfile** - CPU profiling to identify bottlenecks
|
|
395
|
+
* **import time analysis** - Detect slow module imports
|
|
396
|
+
* **tracemalloc** - Memory profiling (*enabled by default in v1.4.2+*)
|
|
397
|
+
* **line_profiler** - Line-by-line profiling (optional, requires `@profile` decorators and `--enable-line-profiler`)
|
|
398
|
+
|
|
399
|
+
#### Test Quality & Coverage Enhancement (v1.4.1+)
|
|
400
|
+
* **Colorful progress indicators** - Real-time colored output with step counts (🟢 green = success, 🟡 yellow = skipped, 🔴 red = failed)
|
|
401
|
+
- *v1.4.2: Fixed color support for xterm and other terminals*
|
|
402
|
+
* **Test flakiness detection** - Run tests multiple times to identify non-deterministic failures
|
|
403
|
+
* **Branch coverage** - Enhanced coverage.py integration showing missing branches, not just lines
|
|
404
|
+
* **Slow test identification** - Automatically identify and rank tests exceeding time threshold
|
|
405
|
+
* **Mutation testing** - Optional mutmut integration to measure test suite effectiveness (VERY SLOW - disabled by default)
|
|
406
|
+
|
|
407
|
+
#### Performance Profiling (v1.4.0+)
|
|
408
|
+
* **cProfile integration** - CPU profiling showing slowest functions
|
|
409
|
+
* **import time analysis** - Detect slow module imports
|
|
410
|
+
* **tracemalloc** - Memory profiling (*v1.4.2: enabled by default*)
|
|
411
|
+
* **line_profiler** - Line-by-line profiling (optional, requires `@profile` decorators and `--enable-line-profiler`)
|
|
412
|
+
|
|
413
|
+
#### Pattern Scanning
|
|
414
|
+
* **ripgrep scans** - TODO detection, print statements, bare excepts
|
|
415
|
+
|
|
416
|
+
All tools gracefully skip if not installed. Install recommended tools:
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
pip install ruff mypy pytest pytest-cov bandit pip-audit vulture radon interrogate pylint pipdeptree pip-licenses
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
For ripgrep (system dependency):
|
|
423
|
+
* macOS: `brew install ripgrep`
|
|
424
|
+
* Ubuntu/Debian: `sudo apt install ripgrep`
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### 🤖 AI profile (NEW)
|
|
429
|
+
|
|
430
|
+
The `ai` profile is optimized for handing a project to AI tooling
|
|
431
|
+
(ChatGPT, local LLMs, code assistants, etc.).
|
|
432
|
+
|
|
433
|
+
It prioritizes **source code and reproducible context**, while skipping
|
|
434
|
+
expensive or noisy steps by default.
|
|
435
|
+
|
|
436
|
+
Run it with:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
pybundle run ai
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### What `ai` does by default
|
|
443
|
+
|
|
444
|
+
* ✅ Includes full curated source snapshot (`src/`)
|
|
445
|
+
* ✅ Includes environment + git metadata
|
|
446
|
+
* ✅ Generates `REPRO.md` and `HANDOFF.md`
|
|
447
|
+
* ❌ Skips linting, type-checking, tests
|
|
448
|
+
* ❌ Skips ripgrep scans and error-context expansion
|
|
449
|
+
* ❌ Skips `compileall` unless explicitly enabled
|
|
450
|
+
|
|
451
|
+
The result is a **small, fast, AI-friendly bundle** that still preserves
|
|
452
|
+
determinism and traceability.
|
|
453
|
+
|
|
454
|
+
You may selectively re-enable tools:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
pybundle run ai --ruff --mypy
|
|
458
|
+
pybundle run ai --compileall
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
This makes `ai` suitable for:
|
|
462
|
+
|
|
463
|
+
* AI-assisted refactoring
|
|
464
|
+
* Large-context summarization
|
|
465
|
+
* Code review handoff
|
|
466
|
+
* Offline or local LLM workflows
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
### Common options
|
|
471
|
+
|
|
472
|
+
Most usage customizations are done through flags on `pybundle run`.
|
|
473
|
+
|
|
474
|
+
Example:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
pybundle run analysis \
|
|
478
|
+
--format zip \
|
|
479
|
+
--outdir ./artifacts \
|
|
480
|
+
--name myproject-bundle \
|
|
481
|
+
--strict
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Commonly used options:
|
|
485
|
+
|
|
486
|
+
* `--format {auto,zip,tar.gz}` - archive format
|
|
487
|
+
* `--outdir PATH` - output directory (default: `<project>/artifacts`)
|
|
488
|
+
* `--name NAME` - override archive name prefix
|
|
489
|
+
* `--strict` - fail with non-zero exit code if any step fails
|
|
490
|
+
* `--redact / --no-redact` - control secret redaction
|
|
491
|
+
|
|
492
|
+
Tool execution can be selectively disabled:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
--no-ruff
|
|
496
|
+
--no-mypy
|
|
497
|
+
--no-pylance
|
|
498
|
+
--no-pytest
|
|
499
|
+
--no-bandit
|
|
500
|
+
--no-pip-audit
|
|
501
|
+
--no-coverage
|
|
502
|
+
--no-rg
|
|
503
|
+
--no-error-refs
|
|
504
|
+
--no-context
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
For the full list of options:
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
pybundle run --help
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
### Doctor mode
|
|
516
|
+
|
|
517
|
+
To see which tools are available and what *would* run (without creating a bundle):
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
pybundle doctor
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
You may optionally specify a profile to preview:
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
pybundle doctor analysis
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
This is useful for validating environment readiness (CI, fresh machines, etc.).
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
### Version
|
|
534
|
+
|
|
535
|
+
To check the installed version:
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
pybundle version
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## 🧠 Ignore behavior (important)
|
|
544
|
+
|
|
545
|
+
### If inside a Git repository
|
|
546
|
+
|
|
547
|
+
pybundle uses **Git itself** to determine which files are included:
|
|
548
|
+
|
|
549
|
+
* `.gitignore`
|
|
550
|
+
* `.git/info/exclude`
|
|
551
|
+
* global gitignore rules
|
|
552
|
+
|
|
553
|
+
This guarantees pybundle sees the project **exactly as Git does**.
|
|
554
|
+
|
|
555
|
+
### If Git is unavailable
|
|
556
|
+
|
|
557
|
+
pybundle falls back to safe structural rules:
|
|
558
|
+
|
|
559
|
+
* ignores `__pycache__`, `.ruff_cache`, `.mypy_cache`, `.pytest_cache`, etc.
|
|
560
|
+
* detects virtual environments by structure (`pyvenv.cfg`, `bin/activate`), not by name
|
|
561
|
+
→ works with `.venv`, `.pybundle-venv`, `env-prod-2025`, etc.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## 🧾 Machine-Readable Output (`--json`)
|
|
566
|
+
|
|
567
|
+
All `pybundle` commands support a **machine-readable JSON output mode** via the `--json` flag.
|
|
568
|
+
|
|
569
|
+
When enabled, `pybundle` emits **exactly one JSON object to stdout**, with a **stable schema** intended for:
|
|
570
|
+
|
|
571
|
+
* CI pipelines
|
|
572
|
+
* automation scripts
|
|
573
|
+
* external tooling
|
|
574
|
+
* AI orchestration
|
|
575
|
+
* reproducible analysis
|
|
576
|
+
|
|
577
|
+
No human text or formatting are mixed into the output.
|
|
578
|
+
|
|
579
|
+
### Example
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
pybundle run analysis --json
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Output:
|
|
586
|
+
|
|
587
|
+
```json
|
|
588
|
+
{
|
|
589
|
+
"status": "ok",
|
|
590
|
+
"command": "run",
|
|
591
|
+
"profile": "analysis",
|
|
592
|
+
"files_included": 39,
|
|
593
|
+
"files_excluded": 0,
|
|
594
|
+
"duration_ms": 394,
|
|
595
|
+
"bundle_path": "/home/jessica/repositories/python/pybundle/artifacts/pybundle_analysis_20260103T102440Z.zip"
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
The same structure applies to **all profiles**:
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
pybundle run ai --json
|
|
603
|
+
pybundle run debug --json
|
|
604
|
+
pybundle run backup --json
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
### JSON Field Definitions
|
|
610
|
+
|
|
611
|
+
| Field | Description |
|
|
612
|
+
| ---------------- | -------------------------------------------------- |
|
|
613
|
+
| `status` | `"ok"` or `"fail"` based on execution result |
|
|
614
|
+
| `command` | The command executed (`run` or `doctor`) |
|
|
615
|
+
| `profile` | The profile used (`analysis`, `ai`, `debug`, etc.) |
|
|
616
|
+
| `files_included` | Number of files copied into the bundle |
|
|
617
|
+
| `files_excluded` | Number of *evaluated* files skipped by policy |
|
|
618
|
+
| `duration_ms` | Total execution time in milliseconds |
|
|
619
|
+
| `bundle_path` | Absolute path to the generated archive |
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
### Important Semantics: `files_excluded`
|
|
624
|
+
|
|
625
|
+
`files_excluded` **does not** mean “everything in the repository that was not bundled.”
|
|
626
|
+
|
|
627
|
+
Instead, it means:
|
|
628
|
+
|
|
629
|
+
> Files that were **eligible under the active profile’s policy** and were *explicitly skipped* after evaluation.
|
|
630
|
+
|
|
631
|
+
Files and directories that are **intentionally out of scope** — such as:
|
|
632
|
+
|
|
633
|
+
* `.git/`
|
|
634
|
+
* `node_modules/`
|
|
635
|
+
* virtual environments
|
|
636
|
+
* build artifacts
|
|
637
|
+
* caches
|
|
638
|
+
|
|
639
|
+
are **never considered**, and therefore are **not counted as excluded**.
|
|
640
|
+
|
|
641
|
+
This design keeps metrics honest and avoids inflating counts with known-irrelevant infrastructure.
|
|
642
|
+
|
|
643
|
+
A value of `files_excluded = 0` simply means:
|
|
644
|
+
|
|
645
|
+
> *Everything that was evaluated was worth keeping.*
|
|
646
|
+
|
|
647
|
+
This is expected and normal for clean, well-structured projects — especially in `ai` mode.
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
### JSON Stability Guarantee
|
|
652
|
+
|
|
653
|
+
The JSON schema emitted by `--json` is considered **part of the public API**.
|
|
654
|
+
|
|
655
|
+
Starting with **v1.0**, field names and meanings will remain stable.
|
|
656
|
+
New fields may be added, but existing fields will not be renamed or removed.
|
|
657
|
+
|
|
658
|
+
This allows `pybundle` to be safely embedded into:
|
|
659
|
+
|
|
660
|
+
* CI workflows
|
|
661
|
+
* automation scripts
|
|
662
|
+
* AI pipelines
|
|
663
|
+
* external tooling
|
|
664
|
+
|
|
665
|
+
without fear of breaking changes.
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## 📜 Profiles
|
|
670
|
+
|
|
671
|
+
pybundle is profile-driven. Each profile defines:
|
|
672
|
+
|
|
673
|
+
* what files are collected
|
|
674
|
+
* which tools run
|
|
675
|
+
* what metadata is emitted
|
|
676
|
+
|
|
677
|
+
Example profiles:
|
|
678
|
+
|
|
679
|
+
* `analysis`
|
|
680
|
+
* `source`
|
|
681
|
+
* `minimal`
|
|
682
|
+
|
|
683
|
+
Profiles are extensible - add your own without modifying core logic.
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## 🔐 Safety & Redaction
|
|
688
|
+
|
|
689
|
+
By default, pybundle:
|
|
690
|
+
|
|
691
|
+
* avoids scanning known secret locations
|
|
692
|
+
* supports optional redaction of sensitive strings in logs
|
|
693
|
+
|
|
694
|
+
Use `--redact / --no-redact` to control behavior.
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
## 🔒 Security Considerations
|
|
698
|
+
|
|
699
|
+
**pybundle** is a development tool designed for trusted environments.
|
|
700
|
+
|
|
701
|
+
### Threat Model
|
|
702
|
+
|
|
703
|
+
* **Environment:** Development machines and CI/CD pipelines
|
|
704
|
+
* **Trust Boundary:** Assumes trusted development environment
|
|
705
|
+
* **Execution Context:** Runs external tools (git, ruff, mypy, pytest, etc.)
|
|
706
|
+
* **Input Sources:** Project files, git repository, installed packages
|
|
707
|
+
|
|
708
|
+
### Security Posture
|
|
709
|
+
|
|
710
|
+
**Tool Path Resolution:**
|
|
711
|
+
- All external tools use full resolved paths (via `shutil.which()`)
|
|
712
|
+
- Tools are resolved at detection time and stored in `Tooling` dataclass
|
|
713
|
+
- No dynamic PATH manipulation or shell interpretation
|
|
714
|
+
- Eliminates partial path execution vulnerabilities (B607)
|
|
715
|
+
- **Optional strict-paths mode** for enhanced security (v1.2.0+)
|
|
716
|
+
- **Code quality tools** for dead code, complexity, docstrings, and duplication (v1.3.0+)
|
|
717
|
+
- **Dependency intelligence** for conflict detection, license scanning, and size analysis (v1.3.1+)
|
|
718
|
+
|
|
719
|
+
**Subprocess Execution:**
|
|
720
|
+
- All subprocess calls use `shell=False` (default, secure)
|
|
721
|
+
- Arguments passed as lists, never as strings
|
|
722
|
+
- No user-controlled command construction
|
|
723
|
+
- Commands are hardcoded in source code
|
|
724
|
+
|
|
725
|
+
**Data Handling:**
|
|
726
|
+
- Optional secret redaction for sensitive strings in logs
|
|
727
|
+
- Environment variables and paths logged for reproducibility
|
|
728
|
+
- All file operations respect `.gitignore` rules
|
|
729
|
+
|
|
730
|
+
### Strict-Paths Mode (v1.2.0+)
|
|
731
|
+
|
|
732
|
+
For high-security environments, enable `--strict-paths` to enforce that all tools must be in trusted system directories:
|
|
733
|
+
|
|
734
|
+
```bash
|
|
735
|
+
pybundle run analysis --strict-paths
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
**Trusted directories** (configurable via `PYBUNDLE_TRUSTED_PATHS`):
|
|
739
|
+
- `/usr/bin/`, `/usr/local/bin/`, `/bin/`
|
|
740
|
+
- `/opt/homebrew/bin/` (macOS Homebrew)
|
|
741
|
+
- `/snap/bin/` (Ubuntu snaps)
|
|
742
|
+
- Virtual environment paths (`.venv`, `venv`, `.pybundle-venv`)
|
|
743
|
+
|
|
744
|
+
Tools outside trusted directories are excluded in strict mode. This prevents:
|
|
745
|
+
- Accidental execution of tools from user-writable directories
|
|
746
|
+
- PATH manipulation attacks
|
|
747
|
+
- Use of potentially compromised tool installations
|
|
748
|
+
|
|
749
|
+
**Example:** Verify tool paths before running:
|
|
750
|
+
```bash
|
|
751
|
+
pybundle doctor --strict-paths
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
Output shows trust status:
|
|
755
|
+
```
|
|
756
|
+
🔧 Tool Detection:
|
|
757
|
+
git ✅ /usr/bin/git
|
|
758
|
+
python ✅ /path/to/venv/bin/python
|
|
759
|
+
npm ⚠️ /home/user/.nvm/.../npm (untrusted in strict mode)
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**Configure custom trusted paths:**
|
|
763
|
+
```bash
|
|
764
|
+
export PYBUNDLE_TRUSTED_PATHS="/opt/custom/bin:/company/tools/bin"
|
|
765
|
+
pybundle run debug --strict-paths
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Known Limitations
|
|
769
|
+
|
|
770
|
+
1. **Requires Trusted Environment**
|
|
771
|
+
- Assumes developer controls their machine and installed tools
|
|
772
|
+
- Not designed for untrusted code execution or sandboxing
|
|
773
|
+
- Tool integrity depends on system package management
|
|
774
|
+
|
|
775
|
+
2. **Tool Availability**
|
|
776
|
+
- External tools (git, ruff, mypy) are optional
|
|
777
|
+
- Missing tools result in SKIP status, not failure
|
|
778
|
+
- Use `pybundle doctor` to verify available tools
|
|
779
|
+
|
|
780
|
+
3. **File System Access**
|
|
781
|
+
- Reads entire project tree (respecting ignore rules)
|
|
782
|
+
- Writes to `artifacts/` directory by default
|
|
783
|
+
- No privilege escalation or system modification
|
|
784
|
+
|
|
785
|
+
### For Security Auditors
|
|
786
|
+
|
|
787
|
+
**Bandit Security Scan Results:**
|
|
788
|
+
- 33 low-severity findings (all expected for CLI tool)
|
|
789
|
+
- **B404** (subprocess import): Required for tool functionality
|
|
790
|
+
- **B603** (subprocess calls): Using secure pattern (shell=False, full paths)
|
|
791
|
+
- **B112** (try/except/continue): Acceptable error handling pattern
|
|
792
|
+
|
|
793
|
+
**Risk Classification:** LOW
|
|
794
|
+
- No user-controlled command injection
|
|
795
|
+
- No untrusted input in command execution
|
|
796
|
+
- Full path resolution prevents PATH manipulation attacks
|
|
797
|
+
- Standard development tool security posture
|
|
798
|
+
|
|
799
|
+
**Recommended Usage:**
|
|
800
|
+
```bash
|
|
801
|
+
# Verify tool paths before execution
|
|
802
|
+
pybundle doctor
|
|
803
|
+
|
|
804
|
+
# Review what tools will be used
|
|
805
|
+
pybundle doctor analysis --json
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
## 🧩 Why pybundle?
|
|
810
|
+
|
|
811
|
+
pybundle is designed for:
|
|
812
|
+
|
|
813
|
+
* handing a project to another engineer
|
|
814
|
+
* attaching context to a bug report
|
|
815
|
+
* feeding a codebase to AI tooling
|
|
816
|
+
* generating CI artifacts
|
|
817
|
+
* preserving “what exactly did we run?”
|
|
818
|
+
* producing **AI-consumable project context** without guesswork
|
|
819
|
+
|
|
820
|
+
It prioritizes **determinism, traceability, and automation** over clever heuristics.
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
## 🛠 Development Notes
|
|
825
|
+
|
|
826
|
+
* Python ≥ 3.9
|
|
827
|
+
* Uses modern tooling (ruff, mypy)
|
|
828
|
+
* Fully type-checked
|
|
829
|
+
* Formatter-clean
|
|
830
|
+
* No test suite *yet* (intentional; coming later)
|
|
831
|
+
|
|
832
|
+
During development, run:
|
|
833
|
+
|
|
834
|
+
```bash
|
|
835
|
+
python -m pybundle ...
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
to bypass shell caching.
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
## 📌 Versioning
|
|
843
|
+
|
|
844
|
+
pybundle follows **Semantic Versioning**.
|
|
845
|
+
|
|
846
|
+
Pinned Git tags are recommended when used as a dependency:
|
|
847
|
+
|
|
848
|
+
```txt
|
|
849
|
+
gwc-pybundle @ git+https://github.com/girls-whocode/pybundle.git@v1.3.1
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## 🧠 Philosophy
|
|
855
|
+
|
|
856
|
+
> If a tool produces output, it should also produce metadata about **how** and **why** that output exists.
|
|
857
|
+
|
|
858
|
+
pybundle treats context as a first-class artifact.
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
## 📦 Package naming note
|
|
863
|
+
|
|
864
|
+
The distribution name on PyPI is **`gwc-pybundle`** to avoid conflicts with existing packages.
|
|
865
|
+
|
|
866
|
+
The project name, imports, and CLI remain **`pybundle`**.
|
|
867
|
+
|
|
868
|
+
```bash
|
|
869
|
+
pip install gwc-pybundle
|
|
870
|
+
pybundle run analysis
|
|
871
|
+
```
|
|
872
|
+
Look in the autocreated `artifacts/` folder.
|
|
873
|
+
|
|
874
|
+
## 📄 License
|
|
875
|
+
|
|
876
|
+
MIT License
|