ballpython 2.0.7__tar.gz → 2.1.0__tar.gz
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.
- {ballpython-2.0.7 → ballpython-2.1.0}/PKG-INFO +1 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/PKG-INFO +1 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/cache.py +3 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/cli.py +40 -14
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/dead_code_detector.py +552 -15
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/dependency_auditor.py +129 -14
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/linter_formatter.py +6 -5
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/modernizer.py +2 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/security_scanner.py +2 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/syntax_healer.py +2 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/verifier.py +3 -2
- {ballpython-2.0.7 → ballpython-2.1.0}/pyproject.toml +1 -1
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cli.py +51 -0
- ballpython-2.1.0/tests/test_dead_code_fixer.py +173 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_dependency_auditor.py +28 -0
- ballpython-2.0.7/tests/test_dead_code_fixer.py +0 -90
- {ballpython-2.0.7 → ballpython-2.1.0}/README.md +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/__init__.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/__main__.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/cli.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/py.typed +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/SOURCES.txt +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/dependency_links.txt +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/entry_points.txt +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/requires.txt +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/top_level.txt +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/__init__.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/__main__.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/baseline.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/complexity_analyzer.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/config.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/discovery.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/explanations.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/frameworks/__init__.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/frameworks/plugins.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/import_resolver.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/pipeline.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/py.typed +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/taint_engine.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/test_generator.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/type_checker.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/typeshed_resolver.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/setup.cfg +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_baseline_and_explain.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cache.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cli_prove.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_complexity_analyzer.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_config.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_dead_code_detector.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_discovery.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_frameworks.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_import_resolver.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_linter_formatter.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_modernizer.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_mutation_test_generator.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_pipeline.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_security_scanner.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_syntax_healer.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_taint_engine.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_test_generator.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_type_checker.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_verifier.py +0 -0
- {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_verifier_pipeline.py +0 -0
|
@@ -15,6 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
import ast
|
|
16
16
|
import hashlib
|
|
17
17
|
import json
|
|
18
|
+
import logging
|
|
18
19
|
import sqlite3
|
|
19
20
|
import time
|
|
20
21
|
from pathlib import Path
|
|
@@ -22,6 +23,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
25
|
from pycleaner.pipeline import CleanResult
|
|
26
|
+
|
|
25
27
|
from pycleaner.verifier import VerificationTier
|
|
26
28
|
|
|
27
29
|
|
|
@@ -46,7 +48,7 @@ def extract_file_dependencies(source: str) -> list[str]:
|
|
|
46
48
|
elif isinstance(node, ast.ImportFrom) and node.module:
|
|
47
49
|
deps.append(node.module.split(".")[0])
|
|
48
50
|
except SyntaxError:
|
|
49
|
-
|
|
51
|
+
logging.getLogger(__name__).debug("Suppressed exception", exc_info=True)
|
|
50
52
|
return sorted(set(deps))
|
|
51
53
|
|
|
52
54
|
|
|
@@ -157,6 +157,11 @@ def _register_fix_subparsers(subparsers: Any) -> None:
|
|
|
157
157
|
def _register_analysis_subparsers(subparsers: Any) -> None:
|
|
158
158
|
audit_p = subparsers.add_parser("audit", help="Audit project dependencies")
|
|
159
159
|
_add_common_args(audit_p)
|
|
160
|
+
audit_p.add_argument(
|
|
161
|
+
"--fix",
|
|
162
|
+
action="store_true",
|
|
163
|
+
help="Auto-fix requirements.txt and pyproject.toml and prune unused packages",
|
|
164
|
+
)
|
|
160
165
|
audit_p.add_argument(
|
|
161
166
|
"--fix-deps", action="store_true", help="Auto-fix requirements.txt"
|
|
162
167
|
)
|
|
@@ -897,15 +902,13 @@ def _render_audit_terminal_output(
|
|
|
897
902
|
f" [red]Missing:[/red] {', '.join(sorted(audit_report.missing_packages))}"
|
|
898
903
|
)
|
|
899
904
|
if not should_fix:
|
|
900
|
-
print_msg(
|
|
901
|
-
" [dim]Tip: Run with -a/--all or --fix-deps to append them[/dim]"
|
|
902
|
-
)
|
|
905
|
+
print_msg(" [dim]Tip: Run with -a/--all or --fix to append them[/dim]")
|
|
903
906
|
if audit_report.unused_packages:
|
|
904
907
|
print_msg(
|
|
905
908
|
f" [yellow]Unused:[/yellow] {', '.join(sorted(audit_report.unused_packages))}"
|
|
906
909
|
)
|
|
907
910
|
if audit_report.fixed_requirements:
|
|
908
|
-
print_msg(" [green]
|
|
911
|
+
print_msg(" [green]Project dependencies synchronized on disk.[/green]")
|
|
909
912
|
|
|
910
913
|
|
|
911
914
|
def _run_fix_audit(
|
|
@@ -918,8 +921,18 @@ def _run_fix_audit(
|
|
|
918
921
|
) -> DependencyAuditReport:
|
|
919
922
|
exclude_patterns = config.exclude if config else ()
|
|
920
923
|
auditor = DependencyAuditor(root_dir, exclude_patterns=exclude_patterns)
|
|
921
|
-
fix_any =
|
|
922
|
-
|
|
924
|
+
fix_any = (
|
|
925
|
+
getattr(args, "fix_deps", False)
|
|
926
|
+
or getattr(args, "fix_all", False)
|
|
927
|
+
or getattr(args, "fix", False)
|
|
928
|
+
or apply_changes
|
|
929
|
+
)
|
|
930
|
+
prune_any = (
|
|
931
|
+
getattr(args, "prune_deps", False)
|
|
932
|
+
or getattr(args, "fix_all", False)
|
|
933
|
+
or getattr(args, "fix", False)
|
|
934
|
+
or apply_changes
|
|
935
|
+
)
|
|
923
936
|
should_fix = apply_changes and fix_any
|
|
924
937
|
should_prune = apply_changes and prune_any
|
|
925
938
|
audit_report = auditor.audit(
|
|
@@ -1009,6 +1022,12 @@ def _cmd_fix(
|
|
|
1009
1022
|
config=config,
|
|
1010
1023
|
target_files=py_files,
|
|
1011
1024
|
)
|
|
1025
|
+
if opts.apply_changes and (
|
|
1026
|
+
audit_report.fixed_requirements
|
|
1027
|
+
or getattr(audit_report, "fixed_pyproject", False)
|
|
1028
|
+
):
|
|
1029
|
+
state.changed_count += 1
|
|
1030
|
+
|
|
1012
1031
|
print_msg(
|
|
1013
1032
|
f"\n[bold]Summary: {len(py_files)} inspected, {state.changed_count} updated, {state.error_count} errors.[/bold]"
|
|
1014
1033
|
)
|
|
@@ -1412,8 +1431,10 @@ def _render_audit_cli_output(
|
|
|
1412
1431
|
)
|
|
1413
1432
|
if not audit_report.missing_packages and not audit_report.unused_packages:
|
|
1414
1433
|
print_msg(" [green]All dependencies clean.[/green]")
|
|
1415
|
-
if audit_report.fixed_requirements
|
|
1416
|
-
|
|
1434
|
+
if audit_report.fixed_requirements or getattr(
|
|
1435
|
+
audit_report, "fixed_pyproject", False
|
|
1436
|
+
):
|
|
1437
|
+
print_msg(" [green]Project dependencies synchronized on disk.[/green]")
|
|
1417
1438
|
|
|
1418
1439
|
return (
|
|
1419
1440
|
1
|
|
@@ -1427,10 +1448,12 @@ def _cmd_audit(args: argparse.Namespace, config: PyCleanerConfig, print_msg) ->
|
|
|
1427
1448
|
root_dir = find_project_root(args.paths[0] if args.paths else None)
|
|
1428
1449
|
|
|
1429
1450
|
is_check = getattr(args, "check", False)
|
|
1451
|
+
fix_flag = getattr(args, "fix", False) or getattr(args, "fix_deps", False)
|
|
1452
|
+
prune_flag = getattr(args, "fix", False) or getattr(args, "prune_deps", False)
|
|
1430
1453
|
auditor = DependencyAuditor(root_dir, exclude_patterns=config.exclude)
|
|
1431
1454
|
audit_report = auditor.audit(
|
|
1432
|
-
fix=
|
|
1433
|
-
prune_unused=
|
|
1455
|
+
fix=fix_flag and not is_check,
|
|
1456
|
+
prune_unused=prune_flag and not is_check,
|
|
1434
1457
|
)
|
|
1435
1458
|
|
|
1436
1459
|
if getattr(args, "json", False):
|
|
@@ -1964,6 +1987,8 @@ def _run_ultimate_phases(
|
|
|
1964
1987
|
print_msg(
|
|
1965
1988
|
"\n[bold blue]Phase 2: Project Dependency Audit & Reconciliation[/bold blue]"
|
|
1966
1989
|
)
|
|
1990
|
+
args.fix = True
|
|
1991
|
+
args.prune_deps = True
|
|
1967
1992
|
audit_rc = _cmd_audit(args, config, print_msg)
|
|
1968
1993
|
print_msg(
|
|
1969
1994
|
"\n[bold blue]Phase 3: Bidirectional Type Verification & Typeshed Resolution[/bold blue]"
|
|
@@ -1981,7 +2006,7 @@ def _run_ultimate_phases(
|
|
|
1981
2006
|
def _cmd_ultimate(
|
|
1982
2007
|
args: argparse.Namespace, config: PyCleanerConfig, print_msg: Any, console: Any
|
|
1983
2008
|
) -> int:
|
|
1984
|
-
"""The Ultimate Python Tool flagship runner: executes full multi-layer analysis."""
|
|
2009
|
+
"""The Ultimate Python Tool flagship runner: executes full multi-layer analysis and automated healing."""
|
|
1985
2010
|
print_msg(
|
|
1986
2011
|
"[bold magenta]=== PyCleaner Ultimate: Full Spectrum Analysis & Healing ===[/bold magenta]\n"
|
|
1987
2012
|
)
|
|
@@ -1989,14 +2014,15 @@ def _cmd_ultimate(
|
|
|
1989
2014
|
args, config, print_msg, console
|
|
1990
2015
|
)
|
|
1991
2016
|
print_msg(
|
|
1992
|
-
"\n[bold blue]Phase 6: Structural Complexity & Dead Code Discovery[/bold blue]"
|
|
2017
|
+
"\n[bold blue]Phase 6: Structural Complexity & Dead Code Discovery & Healing[/bold blue]"
|
|
1993
2018
|
)
|
|
1994
2019
|
_cmd_complexity(args, config, print_msg, console)
|
|
1995
|
-
|
|
2020
|
+
args.fix = True
|
|
2021
|
+
dead_rc = _cmd_dead_code(args, config, print_msg, console)
|
|
1996
2022
|
print_msg(
|
|
1997
2023
|
"\n[bold magenta]=== Ultimate Python Tool: Analysis Complete ===[/bold magenta]"
|
|
1998
2024
|
)
|
|
1999
|
-
return max(fix_rc, audit_rc, type_rc, taint_rc, scan_rc)
|
|
2025
|
+
return max(fix_rc, audit_rc, type_rc, taint_rc, scan_rc, dead_rc)
|
|
2000
2026
|
|
|
2001
2027
|
|
|
2002
2028
|
def _collect_file_mtimes(files: Sequence[Path]) -> dict[Path, float]:
|