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.
Files changed (63) hide show
  1. {ballpython-2.0.7 → ballpython-2.1.0}/PKG-INFO +1 -1
  2. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/PKG-INFO +1 -1
  3. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/cache.py +3 -1
  4. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/cli.py +40 -14
  5. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/dead_code_detector.py +552 -15
  6. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/dependency_auditor.py +129 -14
  7. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/linter_formatter.py +6 -5
  8. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/modernizer.py +2 -1
  9. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/security_scanner.py +2 -1
  10. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/syntax_healer.py +2 -1
  11. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/verifier.py +3 -2
  12. {ballpython-2.0.7 → ballpython-2.1.0}/pyproject.toml +1 -1
  13. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cli.py +51 -0
  14. ballpython-2.1.0/tests/test_dead_code_fixer.py +173 -0
  15. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_dependency_auditor.py +28 -0
  16. ballpython-2.0.7/tests/test_dead_code_fixer.py +0 -90
  17. {ballpython-2.0.7 → ballpython-2.1.0}/README.md +0 -0
  18. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/__init__.py +0 -0
  19. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/__main__.py +0 -0
  20. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/cli.py +0 -0
  21. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython/py.typed +0 -0
  22. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/SOURCES.txt +0 -0
  23. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/dependency_links.txt +0 -0
  24. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/entry_points.txt +0 -0
  25. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/requires.txt +0 -0
  26. {ballpython-2.0.7 → ballpython-2.1.0}/ballpython.egg-info/top_level.txt +0 -0
  27. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/__init__.py +0 -0
  28. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/__main__.py +0 -0
  29. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/baseline.py +0 -0
  30. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/complexity_analyzer.py +0 -0
  31. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/config.py +0 -0
  32. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/discovery.py +0 -0
  33. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/explanations.py +0 -0
  34. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/frameworks/__init__.py +0 -0
  35. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/frameworks/plugins.py +0 -0
  36. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/import_resolver.py +0 -0
  37. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/pipeline.py +0 -0
  38. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/py.typed +0 -0
  39. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/taint_engine.py +0 -0
  40. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/test_generator.py +0 -0
  41. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/type_checker.py +0 -0
  42. {ballpython-2.0.7 → ballpython-2.1.0}/pycleaner/typeshed_resolver.py +0 -0
  43. {ballpython-2.0.7 → ballpython-2.1.0}/setup.cfg +0 -0
  44. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_baseline_and_explain.py +0 -0
  45. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cache.py +0 -0
  46. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_cli_prove.py +0 -0
  47. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_complexity_analyzer.py +0 -0
  48. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_config.py +0 -0
  49. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_dead_code_detector.py +0 -0
  50. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_discovery.py +0 -0
  51. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_frameworks.py +0 -0
  52. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_import_resolver.py +0 -0
  53. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_linter_formatter.py +0 -0
  54. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_modernizer.py +0 -0
  55. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_mutation_test_generator.py +0 -0
  56. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_pipeline.py +0 -0
  57. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_security_scanner.py +0 -0
  58. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_syntax_healer.py +0 -0
  59. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_taint_engine.py +0 -0
  60. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_test_generator.py +0 -0
  61. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_type_checker.py +0 -0
  62. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_verifier.py +0 -0
  63. {ballpython-2.0.7 → ballpython-2.1.0}/tests/test_verifier_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ballpython
3
- Version: 2.0.7
3
+ Version: 2.1.0
4
4
  Summary: The Ultimate Static Python Intelligence, Healing, Type Verification, and Security Suite
5
5
  Author: Developer
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ballpython
3
- Version: 2.0.7
3
+ Version: 2.1.0
4
4
  Summary: The Ultimate Static Python Intelligence, Healing, Type Verification, and Security Suite
5
5
  Author: Developer
6
6
  License-Expression: MIT
@@ -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
- pass # Best-effort dependency extraction; syntax errors handled downstream
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]requirements.txt synchronized.[/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 = getattr(args, "fix_deps", False) or getattr(args, "fix_all", False)
922
- prune_any = getattr(args, "prune_deps", False) or getattr(args, "fix_all", False)
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
- print_msg(" [green]requirements.txt synchronized.[/green]")
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=getattr(args, "fix_deps", False) and not is_check,
1433
- prune_unused=getattr(args, "prune_deps", False) and not is_check,
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
- _cmd_dead_code(args, config, print_msg, console)
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]: