gwc-pybundle 2.1.2__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.

Files changed (82) hide show
  1. gwc_pybundle-2.1.2.dist-info/METADATA +903 -0
  2. gwc_pybundle-2.1.2.dist-info/RECORD +82 -0
  3. gwc_pybundle-2.1.2.dist-info/WHEEL +5 -0
  4. gwc_pybundle-2.1.2.dist-info/entry_points.txt +2 -0
  5. gwc_pybundle-2.1.2.dist-info/licenses/LICENSE.md +25 -0
  6. gwc_pybundle-2.1.2.dist-info/top_level.txt +1 -0
  7. pybundle/__init__.py +0 -0
  8. pybundle/__main__.py +4 -0
  9. pybundle/cli.py +546 -0
  10. pybundle/context.py +404 -0
  11. pybundle/doctor.py +148 -0
  12. pybundle/filters.py +228 -0
  13. pybundle/manifest.py +77 -0
  14. pybundle/packaging.py +45 -0
  15. pybundle/policy.py +132 -0
  16. pybundle/profiles.py +454 -0
  17. pybundle/roadmap_model.py +42 -0
  18. pybundle/roadmap_scan.py +328 -0
  19. pybundle/root_detect.py +14 -0
  20. pybundle/runner.py +180 -0
  21. pybundle/steps/__init__.py +26 -0
  22. pybundle/steps/ai_context.py +791 -0
  23. pybundle/steps/api_docs.py +219 -0
  24. pybundle/steps/asyncio_analysis.py +358 -0
  25. pybundle/steps/bandit.py +72 -0
  26. pybundle/steps/base.py +20 -0
  27. pybundle/steps/blocking_call_detection.py +291 -0
  28. pybundle/steps/call_graph.py +219 -0
  29. pybundle/steps/compileall.py +76 -0
  30. pybundle/steps/config_docs.py +319 -0
  31. pybundle/steps/config_validation.py +302 -0
  32. pybundle/steps/container_image.py +294 -0
  33. pybundle/steps/context_expand.py +272 -0
  34. pybundle/steps/copy_pack.py +293 -0
  35. pybundle/steps/coverage.py +101 -0
  36. pybundle/steps/cprofile_step.py +166 -0
  37. pybundle/steps/dependency_sizes.py +136 -0
  38. pybundle/steps/django_checks.py +214 -0
  39. pybundle/steps/dockerfile_lint.py +282 -0
  40. pybundle/steps/dockerignore.py +311 -0
  41. pybundle/steps/duplication.py +103 -0
  42. pybundle/steps/env_completeness.py +269 -0
  43. pybundle/steps/env_var_usage.py +253 -0
  44. pybundle/steps/error_refs.py +204 -0
  45. pybundle/steps/event_loop_patterns.py +280 -0
  46. pybundle/steps/exception_patterns.py +190 -0
  47. pybundle/steps/fastapi_integration.py +250 -0
  48. pybundle/steps/flask_debugging.py +312 -0
  49. pybundle/steps/git_analytics.py +315 -0
  50. pybundle/steps/handoff_md.py +176 -0
  51. pybundle/steps/import_time.py +175 -0
  52. pybundle/steps/interrogate.py +106 -0
  53. pybundle/steps/license_scan.py +96 -0
  54. pybundle/steps/line_profiler.py +117 -0
  55. pybundle/steps/link_validation.py +287 -0
  56. pybundle/steps/logging_analysis.py +233 -0
  57. pybundle/steps/memory_profile.py +176 -0
  58. pybundle/steps/migration_history.py +336 -0
  59. pybundle/steps/mutation_testing.py +141 -0
  60. pybundle/steps/mypy.py +103 -0
  61. pybundle/steps/orm_optimization.py +316 -0
  62. pybundle/steps/pip_audit.py +45 -0
  63. pybundle/steps/pipdeptree.py +62 -0
  64. pybundle/steps/pylance.py +562 -0
  65. pybundle/steps/pytest.py +66 -0
  66. pybundle/steps/query_pattern_analysis.py +334 -0
  67. pybundle/steps/radon.py +161 -0
  68. pybundle/steps/repro_md.py +161 -0
  69. pybundle/steps/rg_scans.py +78 -0
  70. pybundle/steps/roadmap.py +153 -0
  71. pybundle/steps/ruff.py +117 -0
  72. pybundle/steps/secrets_detection.py +235 -0
  73. pybundle/steps/security_headers.py +309 -0
  74. pybundle/steps/shell.py +74 -0
  75. pybundle/steps/slow_tests.py +178 -0
  76. pybundle/steps/sqlalchemy_validation.py +269 -0
  77. pybundle/steps/test_flakiness.py +184 -0
  78. pybundle/steps/tree.py +116 -0
  79. pybundle/steps/type_coverage.py +277 -0
  80. pybundle/steps/unused_deps.py +211 -0
  81. pybundle/steps/vulture.py +167 -0
  82. pybundle/tools.py +63 -0
pybundle/profiles.py ADDED
@@ -0,0 +1,454 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ import dataclasses
5
+ from .context import RunOptions
6
+ from .steps.shell import ShellStep
7
+ from .steps.tree import TreeStep, LargestFilesStep
8
+ from .steps.compileall import CompileAllStep
9
+ from .steps.ruff import RuffCheckStep, RuffFormatCheckStep
10
+ from .steps.mypy import MypyStep
11
+ from .steps.pylance import PylanceStep
12
+ from .steps.pytest import PytestStep
13
+ from .steps.bandit import BanditStep
14
+ from .steps.pip_audit import PipAuditStep
15
+ from .steps.coverage import CoverageStep
16
+ from .steps.rg_scans import default_rg_steps
17
+ from .steps.error_refs import ErrorReferencedFilesStep
18
+ from .steps.context_expand import ErrorContextExpandStep
19
+ from .steps.copy_pack import CuratedCopyStep
20
+ from .steps.repro_md import ReproMarkdownStep
21
+ from .steps.handoff_md import HandoffMarkdownStep
22
+ from .steps.roadmap import RoadmapStep
23
+
24
+ # Code quality tools (v1.3.0)
25
+ from .steps.vulture import VultureStep
26
+ from .steps.radon import RadonStep
27
+ from .steps.interrogate import InterrogateStep
28
+ from .steps.duplication import DuplicationStep
29
+
30
+ # Dependency analysis tools (v1.3.1)
31
+ from .steps.pipdeptree import PipdeptreeStep
32
+ from .steps.unused_deps import UnusedDependenciesStep
33
+ from .steps.license_scan import LicenseScanStep
34
+ from .steps.dependency_sizes import DependencySizesStep
35
+
36
+ # Performance profiling tools (v1.4.0)
37
+ from .steps.cprofile_step import CProfileStep
38
+ from .steps.import_time import ImportTimeStep
39
+ from .steps.memory_profile import MemoryProfileStep
40
+ from .steps.line_profiler import LineProfilerStep
41
+
42
+ # Test quality & coverage tools (v1.4.1)
43
+ from .steps.test_flakiness import TestFlakinessStep
44
+ from .steps.slow_tests import SlowTestsStep
45
+ from .steps.mutation_testing import MutationTestingStep
46
+
47
+ # Documentation & type quality tools (v1.5.0)
48
+ from .steps.type_coverage import TypeCoverageStep
49
+ from .steps.link_validation import LinkValidationStep
50
+ from .steps.api_docs import ApiDocsStep
51
+
52
+ # AI context generation (v2.1.0)
53
+ from .steps.ai_context import AIContextStep
54
+ from .steps.config_docs import ConfigDocumentationStep
55
+
56
+ # Git analytics tools (v1.5.1)
57
+ from .steps.git_analytics import GitAnalyticsStep
58
+
59
+ # Runtime analysis tools (v1.5.2)
60
+ from .steps.exception_patterns import ExceptionPatternsStep
61
+ from .steps.logging_analysis import LoggingAnalysisStep
62
+ from .steps.call_graph import CallGraphStep
63
+ from .steps.env_var_usage import EnvVarUsageStep
64
+
65
+ # Container & deployment tools (v2.0.0)
66
+ from .steps.dockerfile_lint import DockerfileLintStep
67
+ from .steps.dockerignore import DockerigoreStep
68
+ from .steps.container_image import ContainerImageStep
69
+
70
+ # Configuration & security tools (v2.0.0)
71
+ from .steps.config_validation import ConfigValidationStep
72
+ from .steps.secrets_detection import SecretsDetectionStep
73
+ from .steps.env_completeness import EnvCompletenessStep
74
+ from .steps.security_headers import SecurityHeadersStep
75
+
76
+ # Async & modern Python tools (v2.0.0)
77
+ from .steps.asyncio_analysis import AsyncioAnalysisStep
78
+ from .steps.blocking_call_detection import BlockingCallDetectionStep
79
+ from .steps.event_loop_patterns import EventLoopPatternsStep
80
+
81
+ # Database & data layer tools (v2.0.0)
82
+ from .steps.migration_history import MigrationHistoryStep
83
+ from .steps.query_pattern_analysis import QueryPatternAnalysisStep
84
+ from .steps.orm_optimization import ORMOptimizationStep
85
+
86
+ # Framework-specific tools (v2.0.0)
87
+ from .steps.django_checks import DjangoSystemChecksStep
88
+ from .steps.fastapi_integration import FastAPIIntegrationStep
89
+ from .steps.flask_debugging import FlaskDebuggingStep
90
+ from .steps.sqlalchemy_validation import SQLAlchemyValidationStep
91
+
92
+ from .policy import AIContextPolicy
93
+
94
+
95
+ @dataclass(frozen=True)
96
+ class Profile:
97
+ name: str
98
+ steps: list
99
+
100
+
101
+ def _dedupe_steps(steps: list) -> list:
102
+ seen = set()
103
+ out = []
104
+ for s in steps:
105
+ key = (
106
+ getattr(s, "out", None)
107
+ or getattr(s, "out_md", None)
108
+ or getattr(s, "name", None)
109
+ )
110
+ # fallback to class name if needed
111
+ key = key or s.__class__.__name__
112
+ if key in seen:
113
+ continue
114
+ seen.add(key)
115
+ out.append(s)
116
+ return out
117
+
118
+
119
+ def resolve_defaults(profile: str, opts: RunOptions) -> RunOptions:
120
+ if profile == "ai":
121
+ return dataclasses.replace(
122
+ opts,
123
+ no_ruff=opts.no_ruff if opts.no_ruff is not None else True,
124
+ no_mypy=opts.no_mypy if opts.no_mypy is not None else True,
125
+ no_pytest=opts.no_pytest if opts.no_pytest is not None else True,
126
+ no_rg=opts.no_rg if opts.no_rg is not None else True,
127
+ no_error_refs=opts.no_error_refs
128
+ if opts.no_error_refs is not None
129
+ else True,
130
+ no_context=opts.no_context if opts.no_context is not None else True,
131
+ no_compileall=opts.no_compileall
132
+ if opts.no_compileall is not None
133
+ else True,
134
+ )
135
+ return opts
136
+
137
+
138
+ def _analysis_steps(options: RunOptions) -> list:
139
+ """
140
+ Analysis profile: What the code IS
141
+ - Structure, metrics, dependencies
142
+ - Documentation and codebase understanding
143
+ - No error detection or linting
144
+ """
145
+ policy = AIContextPolicy()
146
+
147
+ steps: list = [
148
+ # Environment & git status
149
+ ShellStep(
150
+ "git status", "meta/00_git_status.txt", ["git", "status"], require_cmd="git"
151
+ ),
152
+ ShellStep(
153
+ "git diff", "meta/01_git_diff.txt", ["git", "diff"], require_cmd="git"
154
+ ),
155
+ ShellStep(
156
+ "uname -a", "meta/21_uname.txt", ["uname", "-a"], require_cmd="uname"
157
+ ),
158
+ ShellStep(
159
+ "python -V",
160
+ "meta/20_python_version.txt",
161
+ ["python", "-V"],
162
+ require_cmd="python",
163
+ ),
164
+ ShellStep(
165
+ "pip freeze",
166
+ "meta/22_pip_freeze.txt",
167
+ ["python", "-m", "pip", "freeze"],
168
+ require_cmd="python",
169
+ ),
170
+ # Code structure
171
+ TreeStep(max_depth=policy.tree_max_depth, policy=policy),
172
+ LargestFilesStep(limit=policy.largest_limit, policy=policy),
173
+ ]
174
+
175
+ # Code quality metrics (what the code looks like)
176
+ if not options.no_radon:
177
+ steps += [RadonStep()]
178
+
179
+ if not options.no_interrogate:
180
+ steps += [InterrogateStep()]
181
+
182
+ if not options.no_duplication:
183
+ steps += [DuplicationStep()]
184
+
185
+ # Dependency analysis (what the project uses)
186
+ if not options.no_pipdeptree:
187
+ steps += [PipdeptreeStep()]
188
+
189
+ if not options.no_license_scan:
190
+ steps += [LicenseScanStep()]
191
+
192
+ if not options.no_dependency_sizes:
193
+ steps += [DependencySizesStep()]
194
+
195
+ # Performance profiling (what the code does)
196
+ if not options.no_profile:
197
+ steps += [CProfileStep()]
198
+ steps += [ImportTimeStep()]
199
+
200
+ if options.profile_memory:
201
+ steps += [MemoryProfileStep()]
202
+
203
+ if options.enable_line_profiler:
204
+ steps += [LineProfilerStep()]
205
+
206
+ # Documentation & type quality (what the code documents/types)
207
+ if not options.no_type_coverage:
208
+ steps += [TypeCoverageStep()]
209
+
210
+ if not options.no_link_check:
211
+ steps += [LinkValidationStep()]
212
+
213
+ if not options.no_api_docs:
214
+ steps += [ApiDocsStep()]
215
+
216
+ if not options.no_config_docs:
217
+ steps += [ConfigDocumentationStep()]
218
+
219
+ # Git analytics (v1.5.1)
220
+ if not options.no_git_analytics:
221
+ steps += [GitAnalyticsStep()]
222
+
223
+ # Runtime analysis (v1.5.2)
224
+ if not options.no_runtime_analysis:
225
+ steps += [
226
+ ExceptionPatternsStep(),
227
+ LoggingAnalysisStep(),
228
+ CallGraphStep(),
229
+ EnvVarUsageStep(),
230
+ ]
231
+
232
+ # Container & deployment (v2.0.0)
233
+ if not options.no_container_analysis:
234
+ steps += [
235
+ DockerfileLintStep(),
236
+ DockerigoreStep(),
237
+ ContainerImageStep(),
238
+ ]
239
+
240
+ # Configuration & security (v2.0.0)
241
+ if not options.no_config_security_analysis:
242
+ steps += [
243
+ ConfigValidationStep(),
244
+ SecretsDetectionStep(),
245
+ EnvCompletenessStep(),
246
+ SecurityHeadersStep(),
247
+ ]
248
+
249
+ # Async & modern Python (v2.0.0)
250
+ if not options.no_async_analysis:
251
+ steps += [
252
+ AsyncioAnalysisStep(),
253
+ BlockingCallDetectionStep(),
254
+ EventLoopPatternsStep(),
255
+ ]
256
+
257
+ # Database & data layer (v2.0.0)
258
+ if not options.no_db_analysis:
259
+ steps += [
260
+ MigrationHistoryStep(),
261
+ QueryPatternAnalysisStep(),
262
+ ORMOptimizationStep(),
263
+ ]
264
+
265
+ # Framework-specific tools (v2.0.0)
266
+ if not options.no_framework_analysis:
267
+ steps += [
268
+ DjangoSystemChecksStep(),
269
+ FastAPIIntegrationStep(),
270
+ FlaskDebuggingStep(),
271
+ SQLAlchemyValidationStep(),
272
+ ]
273
+
274
+ # Source snapshot and documentation
275
+ steps += [
276
+ CuratedCopyStep(policy=policy),
277
+ RoadmapStep(policy=policy),
278
+ HandoffMarkdownStep(),
279
+ ]
280
+
281
+ return _dedupe_steps(steps)
282
+
283
+
284
+ def _debug_steps(options: RunOptions) -> list:
285
+ """
286
+ Debug profile: What's WRONG with the code
287
+ - Linting, type checking, testing
288
+ - Security vulnerabilities
289
+ - Code quality issues
290
+ - Error detection and context
291
+ """
292
+ policy = AIContextPolicy()
293
+
294
+ steps: list = [
295
+ # Environment & git status
296
+ ShellStep(
297
+ "git status", "meta/00_git_status.txt", ["git", "status"], require_cmd="git"
298
+ ),
299
+ ShellStep(
300
+ "git diff", "meta/01_git_diff.txt", ["git", "diff"], require_cmd="git"
301
+ ),
302
+ ShellStep(
303
+ "uname -a", "meta/21_uname.txt", ["uname", "-a"], require_cmd="uname"
304
+ ),
305
+ ShellStep(
306
+ "python -V",
307
+ "meta/20_python_version.txt",
308
+ ["python", "-V"],
309
+ require_cmd="python",
310
+ ),
311
+ ShellStep(
312
+ "pip freeze",
313
+ "meta/22_pip_freeze.txt",
314
+ ["python", "-m", "pip", "freeze"],
315
+ require_cmd="python",
316
+ ),
317
+ ShellStep(
318
+ "pip check",
319
+ "logs/25_pip_check.txt",
320
+ ["python", "-m", "pip", "check"],
321
+ require_cmd="python",
322
+ ),
323
+ # Code structure (for context)
324
+ TreeStep(max_depth=policy.tree_max_depth, policy=policy),
325
+ LargestFilesStep(limit=policy.largest_limit, policy=policy),
326
+ ]
327
+
328
+ # Compilation errors
329
+ if not options.no_compileall:
330
+ steps.append(CompileAllStep())
331
+
332
+ # Linting & type checking (what's wrong with code style/types)
333
+ if not options.no_ruff:
334
+ steps += [
335
+ RuffCheckStep(target=options.ruff_target),
336
+ RuffFormatCheckStep(target=options.ruff_target),
337
+ ]
338
+
339
+ if not options.no_mypy:
340
+ steps += [MypyStep(target=options.mypy_target)]
341
+
342
+ if not options.no_pylance:
343
+ steps += [PylanceStep()]
344
+
345
+ # Testing (what's broken in functionality)
346
+ if not options.no_pytest:
347
+ steps += [PytestStep(args=options.pytest_args or ["-q"])]
348
+
349
+ if not options.no_coverage:
350
+ steps += [CoverageStep()]
351
+
352
+ # Test quality issues
353
+ steps += [TestFlakinessStep()] # Non-deterministic tests
354
+ steps += [SlowTestsStep()] # Performance issues in tests
355
+
356
+ if options.enable_mutation_testing:
357
+ steps += [MutationTestingStep()] # Test effectiveness
358
+
359
+ # Security vulnerabilities
360
+ if not options.no_bandit:
361
+ steps += [BanditStep()]
362
+
363
+ if not options.no_pip_audit:
364
+ steps += [PipAuditStep()]
365
+
366
+ # Code quality issues (dead code, complexity)
367
+ if not options.no_vulture:
368
+ steps += [VultureStep()]
369
+
370
+ if not options.no_radon:
371
+ steps += [RadonStep()]
372
+
373
+ # Dependency issues
374
+ if not options.no_unused_deps:
375
+ steps += [UnusedDependenciesStep()]
376
+
377
+ if not options.no_pipdeptree:
378
+ steps += [PipdeptreeStep()] # For conflict detection
379
+
380
+ # Pattern scanning (anti-patterns, TODOs)
381
+ if not options.no_rg:
382
+ steps += list(default_rg_steps(target="."))
383
+
384
+ # Error context extraction
385
+ if not options.no_error_refs:
386
+ steps += [ErrorReferencedFilesStep(max_files=options.error_max_files)]
387
+
388
+ if not options.no_context:
389
+ steps += [
390
+ ErrorContextExpandStep(
391
+ depth=options.context_depth,
392
+ max_files=options.context_max_files,
393
+ )
394
+ ]
395
+
396
+ # Source snapshot + repro documentation
397
+ steps += [
398
+ CuratedCopyStep(policy=policy),
399
+ ReproMarkdownStep(),
400
+ AIContextStep(), # Generate AI_CONTEXT.md for AI consumption
401
+ HandoffMarkdownStep(),
402
+ ]
403
+
404
+ return _dedupe_steps(steps)
405
+
406
+
407
+ def get_profile(name: str, options: RunOptions) -> Profile:
408
+ if name == "analysis":
409
+ return Profile(name="analysis", steps=_analysis_steps(options))
410
+
411
+ if name == "debug":
412
+ return Profile(name="debug", steps=_debug_steps(options))
413
+
414
+ if name == "backup":
415
+ # Minimal backup: source + environment, no analysis
416
+ policy = AIContextPolicy()
417
+ return Profile(
418
+ name="backup",
419
+ steps=[
420
+ ShellStep(
421
+ "git status",
422
+ "meta/00_git_status.txt",
423
+ ["git", "status"],
424
+ require_cmd="git",
425
+ ),
426
+ ShellStep(
427
+ "git diff",
428
+ "meta/01_git_diff.txt",
429
+ ["git", "diff"],
430
+ require_cmd="git",
431
+ ),
432
+ ShellStep(
433
+ "python -V",
434
+ "meta/20_python_version.txt",
435
+ ["python", "-V"],
436
+ require_cmd="python",
437
+ ),
438
+ ShellStep(
439
+ "pip freeze",
440
+ "meta/22_pip_freeze.txt",
441
+ ["python", "-m", "pip", "freeze"],
442
+ require_cmd="python",
443
+ ),
444
+ CuratedCopyStep(policy=policy), # Copy source code
445
+ ],
446
+ )
447
+
448
+ if name == "ai":
449
+ # AI profile: debug optimized for AI consumption
450
+ # Disables some noisy tools but keeps everything for problem understanding
451
+ opts = resolve_defaults("ai", options)
452
+ return Profile(name="ai", steps=_debug_steps(opts))
453
+
454
+ raise ValueError(f"unknown profile: {name}")
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass
4
+ from typing import Literal
5
+
6
+ Lang = Literal["python", "js", "ts", "rust", "html", "css", "config", "unknown"]
7
+ EdgeType = Literal["import", "require", "use", "mod", "include", "script", "entrypoint"]
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class Node:
12
+ id: str # stable id (usually path)
13
+ path: str # repo-relative
14
+ lang: Lang
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class Edge:
19
+ src: str # node id
20
+ dst: str # node id (or synthetic id)
21
+ type: EdgeType
22
+ note: str = "" # e.g. "from X import Y", "package.json script: dev"
23
+
24
+
25
+ @dataclass
26
+ class EntryPoint:
27
+ node: str # node id
28
+ reason: str # why we think it's an entry
29
+ confidence: int = 2 # 1-3
30
+
31
+
32
+ @dataclass
33
+ class RoadmapGraph:
34
+ version: int
35
+ root: str
36
+ nodes: list[Node]
37
+ edges: list[Edge]
38
+ entrypoints: list[EntryPoint]
39
+ stats: dict[str, int] # counts by lang/edge types/etc.
40
+
41
+ def to_dict(self) -> dict:
42
+ return asdict(self)