ballpython 2.0.5__py3-none-any.whl → 2.1.0__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.
ballpython/__init__.py CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import Any
6
+
5
7
  import pycleaner
6
- from pycleaner import *
8
+ from pycleaner import __all__ as __all__
9
+ from pycleaner import __version__ as __version__
10
+
7
11
 
8
- __version__ = pycleaner.__version__
9
- __all__ = pycleaner.__all__
12
+ def __getattr__(name: str) -> Any:
13
+ return getattr(pycleaner, name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ballpython
3
- Version: 2.0.5
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
@@ -0,0 +1,34 @@
1
+ ballpython/__init__.py,sha256=GSB-LHdou1Un6DS6Zmh8tv_zrwh6HQHO3Py2z8GO39o,304
2
+ ballpython/__main__.py,sha256=aCRr0vnZfKYHDrPHBsYSjX5xTxtFJpTTSPVUSZTBK-I,136
3
+ ballpython/cli.py,sha256=LllCLRAQQ-fRR_lIXwmd2e3Q7DLCIvf-5jHBXsAhJWs,125
4
+ ballpython/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ pycleaner/__init__.py,sha256=VzmbjUip6i0wpKh-s6XBwgBkIeUgI1duGyKDIiv7Pls,3042
6
+ pycleaner/__main__.py,sha256=8QBFrPyxId563F6cipPMNVEBTG8TIZUgxQfp8gk1VSI,135
7
+ pycleaner/baseline.py,sha256=ljED3x3akie0SB3fzhVno_1UHlI2id-9vta0NIGC0mw,3857
8
+ pycleaner/cache.py,sha256=T3JIxYg8ZezRbSpXYXPD-SyMUkjg4nfKsdO0IuNypOY,10774
9
+ pycleaner/cli.py,sha256=NswwV_3cbHiL63Pj6qDtSpV_98zXvGo7UuBHwNAxpQ8,73752
10
+ pycleaner/complexity_analyzer.py,sha256=j2ktzgR-isWE4xWMe56N3JFLLuYCi-S84BIlRBe0v-I,14975
11
+ pycleaner/config.py,sha256=XhloyaY_9pdwbQuc3QaAPCerLeXz-i1da4xT50h-pjY,8514
12
+ pycleaner/dead_code_detector.py,sha256=uufGt7EtGusQdtbX3rUCHIrF8IAu-S16jrViBJdnV-g,52092
13
+ pycleaner/dependency_auditor.py,sha256=EmSqr_ayUqmdSZ7Nm4QAT4qfikF9VToLL8eXVecIDpw,23395
14
+ pycleaner/discovery.py,sha256=dt3OmHg886hy_Z0p80ccMyDkITQxz4biaJY_zB3MU_g,6151
15
+ pycleaner/explanations.py,sha256=2OOU_l3YL5o_Br_6fP6MF8HlY75-1JRmw3eTYT2lu8M,14219
16
+ pycleaner/import_resolver.py,sha256=Wgrch335AQVsnDv5-7F0l4Zm2oQPkNebPEgTRa7ayAg,32855
17
+ pycleaner/linter_formatter.py,sha256=wdTjwguPWzkJ9KRMcQpFHEirb3ogc9qay69yiphz16Y,21356
18
+ pycleaner/modernizer.py,sha256=kd9_G5EzdW_O-9zm1hA6v33Sb__UbpMZzSvopF-UK5w,16820
19
+ pycleaner/pipeline.py,sha256=ZG7_9PNz0jBadFrZoiI7juLtUJXglGQhLgQhrLJqEac,20612
20
+ pycleaner/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ pycleaner/security_scanner.py,sha256=8nyRtoCjBYAB_sI5azlNsEMm2S0s2zE7fPhc7QCHWR0,23527
22
+ pycleaner/syntax_healer.py,sha256=5VYclqkI3WFnm6yfG0zRLMkHN4QMU4aN4ZYCcSUsmZk,27408
23
+ pycleaner/taint_engine.py,sha256=-bBq38YoQgbO2FHCDxDctZpXWQTqwuS56CEWFNOY000,26870
24
+ pycleaner/test_generator.py,sha256=MM3t0Dx5lyJB5s144IKXq2tXrE8ohKcSvicPR3c9MlU,19680
25
+ pycleaner/type_checker.py,sha256=zkUqi-BNLUzJT0tIECNh7_7GP29Y7_6fMXhVuguwMKg,37881
26
+ pycleaner/typeshed_resolver.py,sha256=N-kWU_CI5DG59lQMkt7wMW9sHYjNCBdfFS42b4y2Kr4,12742
27
+ pycleaner/verifier.py,sha256=QlBwnsrhWWRK3LzvJjpNix474drCNp6LP7FiUgJxMsg,19333
28
+ pycleaner/frameworks/__init__.py,sha256=SOuSRl39af86eoQx7Qm8rTJGD4jsnEvgyhhQ6cVmRVA,3462
29
+ pycleaner/frameworks/plugins.py,sha256=qunMzS3q7xp1GEGxqkuhrnm-raiSRhYQMzmDxsEhSUg,11452
30
+ ballpython-2.1.0.dist-info/METADATA,sha256=98OjKH0i9ih05fQ9JX2eriRljEboAEOVIgk4TwQ9hQ8,3466
31
+ ballpython-2.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
32
+ ballpython-2.1.0.dist-info/entry_points.txt,sha256=6ux-5UxoVSmlK5p9M-GDVt24sCdwTQq9wgRDkpMIYU8,81
33
+ ballpython-2.1.0.dist-info/top_level.txt,sha256=u6lmy8RWZ_saxCZAQTL7EijB4sunegOiVyk5fHjpwLk,21
34
+ ballpython-2.1.0.dist-info/RECORD,,
pycleaner/__init__.py CHANGED
@@ -20,6 +20,8 @@ from pycleaner.discovery import (
20
20
 
21
21
  __version__ = "2.0.5"
22
22
  __all__ = [
23
+ "DEFAULT_IGNORED_DIRS",
24
+ "PROTECTED_FILE_PATTERNS",
23
25
  "BaselineFingerprint",
24
26
  "BaselineManager",
25
27
  "CleanPipeline",
@@ -55,7 +57,10 @@ __all__ = [
55
57
  "TypeReport",
56
58
  "TypeshedResolver",
57
59
  "VerificationTier",
60
+ "collect_project_python_files",
58
61
  "get_explanation",
62
+ "is_ignored_directory",
63
+ "is_protected_file",
59
64
  "list_rules",
60
65
  "load_config",
61
66
  ]
pycleaner/baseline.py CHANGED
@@ -54,7 +54,7 @@ class BaselineManager:
54
54
  data = json.loads(self.baseline_path.read_text(encoding="utf-8"))
55
55
  fingerprints = data.get("fingerprints", [])
56
56
  return {
57
- fp.get("hash")
57
+ str(fp["hash"])
58
58
  for fp in fingerprints
59
59
  if isinstance(fp, dict) and fp.get("hash")
60
60
  }
pycleaner/cache.py CHANGED
@@ -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
 
pycleaner/cli.py CHANGED
@@ -40,7 +40,6 @@ from pycleaner.verifier import CounterExample, ProofReceipt, VerificationTier
40
40
 
41
41
  try:
42
42
  from rich.console import Console
43
- from rich.panel import Panel
44
43
  from rich.progress import (
45
44
  BarColumn,
46
45
  Progress,
@@ -158,6 +157,11 @@ def _register_fix_subparsers(subparsers: Any) -> None:
158
157
  def _register_analysis_subparsers(subparsers: Any) -> None:
159
158
  audit_p = subparsers.add_parser("audit", help="Audit project dependencies")
160
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
+ )
161
165
  audit_p.add_argument(
162
166
  "--fix-deps", action="store_true", help="Auto-fix requirements.txt"
163
167
  )
@@ -714,17 +718,17 @@ def _report_file_modifications(
714
718
  action = "Cleaned" if apply_changes else "Would modify"
715
719
  print_msg(f"[green]{action}:[/green] {py_file.name}")
716
720
  for repair in result.syntax_repairs:
717
- print_msg(f" Syntax: {repair}", style="cyan")
721
+ print_msg(f" - Syntax: {repair}", style="cyan")
718
722
  for mod in result.modernize_transforms:
719
- print_msg(f" Modernize: {mod}", style="green")
723
+ print_msg(f" - Modernize: {mod}", style="green")
720
724
  for dc in result.dead_code_pruned:
721
- print_msg(f" Dead-code: {dc}", style="yellow")
725
+ print_msg(f" - Dead-code: {dc}", style="yellow")
722
726
  for imp in result.resolved_imports:
723
- print_msg(f" Import: {imp}", style="magenta")
727
+ print_msg(f" - Import: {imp}", style="magenta")
724
728
  if result.lint_changed:
725
- print_msg(" Lint: fixed errors and pruned unused imports", style="blue")
729
+ print_msg(" - Lint: fixed errors and pruned unused imports", style="blue")
726
730
  if result.format_changed:
727
- print_msg(" Format: applied PEP 8 formatting", style="blue")
731
+ print_msg(" - Format: applied PEP 8 formatting", style="blue")
728
732
 
729
733
 
730
734
  def _accumulate_result(
@@ -750,11 +754,11 @@ def _accumulate_result(
750
754
  elif result.verification_tier == VerificationTier.TIER_C_REFUSED:
751
755
  if not is_json:
752
756
  print_msg(
753
- f"[bold red]Refused (Tier C):[/bold red] {py_file.name} transformation falsified by differential fuzzing; rolled back!"
757
+ f"[bold red]Refused (Tier C):[/bold red] {py_file.name} - transformation falsified by differential fuzzing; rolled back!"
754
758
  )
755
759
  for ce in result.refused_changes:
756
760
  print_msg(
757
- f" {ce.callable_name} diverged on args={ce.arguments} kwargs={ce.keyword_arguments}"
761
+ f" - {ce.callable_name} diverged on args={ce.arguments} kwargs={ce.keyword_arguments}"
758
762
  )
759
763
  print_msg(
760
764
  f" original={ce.original_result or ce.original_error} vs transformed={ce.transformed_result or ce.transformed_error} (seed {ce.seed})"
@@ -898,15 +902,13 @@ def _render_audit_terminal_output(
898
902
  f" [red]Missing:[/red] {', '.join(sorted(audit_report.missing_packages))}"
899
903
  )
900
904
  if not should_fix:
901
- print_msg(
902
- " [dim]Tip: Run with -a/--all or --fix-deps to append them[/dim]"
903
- )
905
+ print_msg(" [dim]Tip: Run with -a/--all or --fix to append them[/dim]")
904
906
  if audit_report.unused_packages:
905
907
  print_msg(
906
908
  f" [yellow]Unused:[/yellow] {', '.join(sorted(audit_report.unused_packages))}"
907
909
  )
908
910
  if audit_report.fixed_requirements:
909
- print_msg(" [green]requirements.txt synchronized.[/green]")
911
+ print_msg(" [green]Project dependencies synchronized on disk.[/green]")
910
912
 
911
913
 
912
914
  def _run_fix_audit(
@@ -919,8 +921,18 @@ def _run_fix_audit(
919
921
  ) -> DependencyAuditReport:
920
922
  exclude_patterns = config.exclude if config else ()
921
923
  auditor = DependencyAuditor(root_dir, exclude_patterns=exclude_patterns)
922
- fix_any = getattr(args, "fix_deps", False) or getattr(args, "fix_all", False)
923
- 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
+ )
924
936
  should_fix = apply_changes and fix_any
925
937
  should_prune = apply_changes and prune_any
926
938
  audit_report = auditor.audit(
@@ -1010,6 +1022,12 @@ def _cmd_fix(
1010
1022
  config=config,
1011
1023
  target_files=py_files,
1012
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
+
1013
1031
  print_msg(
1014
1032
  f"\n[bold]Summary: {len(py_files)} inspected, {state.changed_count} updated, {state.error_count} errors.[/bold]"
1015
1033
  )
@@ -1022,15 +1040,15 @@ def _cmd_fix(
1022
1040
  if not is_json:
1023
1041
  print_msg("\n[bold cyan]Verification Receipts (Trust Ladder):[/bold cyan]")
1024
1042
  print_msg(
1025
- f" [bold green] Proven (Tier A):[/bold green] {total_proven_callables} callable(s) invariant-preserving across {pipeline.proof_iterations} input(s)"
1043
+ f" [bold green]- Proven (Tier A):[/bold green] {total_proven_callables} callable(s) invariant-preserving across {pipeline.proof_iterations} input(s)"
1026
1044
  )
1027
1045
  if state.suggested_count > 0:
1028
1046
  print_msg(
1029
- f" [yellow] Suggested (Tier B):[/yellow] {state.suggested_count} module(s) (not isolated for dynamic fuzzing)"
1047
+ f" [yellow]- Suggested (Tier B):[/yellow] {state.suggested_count} module(s) (not isolated for dynamic fuzzing)"
1030
1048
  )
1031
1049
  if total_refused_callables > 0:
1032
1050
  print_msg(
1033
- f" [bold red] Refused (Tier C):[/bold red] {total_refused_callables} transformation(s) diverged; rolled back"
1051
+ f" [bold red]- Refused (Tier C):[/bold red] {total_refused_callables} transformation(s) diverged; rolled back"
1034
1052
  )
1035
1053
 
1036
1054
  output_report_path = getattr(
@@ -1098,20 +1116,20 @@ def _cmd_fix(
1098
1116
  )
1099
1117
  if tolerated:
1100
1118
  print_msg(
1101
- f" Baseline tolerated: [yellow]{len(tolerated)}[/yellow] existing issue(s)"
1119
+ f" - Baseline tolerated: [yellow]{len(tolerated)}[/yellow] existing issue(s)"
1102
1120
  )
1103
1121
  if new_debt:
1104
1122
  print_msg(
1105
- f" [bold red]Ratchet Violation:[/bold red] {len(new_debt)} new technical debt issue(s) detected!"
1123
+ f" - [bold red]Ratchet Violation:[/bold red] {len(new_debt)} new technical debt issue(s) detected!"
1106
1124
  )
1107
1125
  for nd in new_debt:
1108
1126
  print_msg(
1109
- f" [red] [X] {nd.rule} at {nd.file}:{nd.line} ({nd.symbol})[/red]"
1127
+ f" [red]- [X] {nd.rule} at {nd.file}:{nd.line} ({nd.symbol})[/red]"
1110
1128
  )
1111
1129
  return 1
1112
1130
  else:
1113
1131
  print_msg(
1114
- " [bold green]Ratchet Passed:[/bold green] 0 new technical debt issues introduced."
1132
+ " - [bold green]Ratchet Passed:[/bold green] 0 new technical debt issues introduced."
1115
1133
  )
1116
1134
  elif new_debt:
1117
1135
  return 1
@@ -1223,9 +1241,9 @@ def _cmd_baseline(
1223
1241
  manager = BaselineManager(output_path)
1224
1242
  saved_file = manager.save_baseline(fingerprints, root_dir)
1225
1243
 
1226
- print_msg(f"\n[bold green]Baseline successfully recorded![/bold green]")
1227
- print_msg(f" Issues snapshotted: [bold yellow]{len(fingerprints)}[/bold yellow]")
1228
- print_msg(f" Output file: [bold]{saved_file}[/bold]")
1244
+ print_msg("\n[bold green]Baseline successfully recorded![/bold green]")
1245
+ print_msg(f" - Issues snapshotted: [bold yellow]{len(fingerprints)}[/bold yellow]")
1246
+ print_msg(f" - Output file: [bold]{saved_file}[/bold]")
1229
1247
  print_msg(
1230
1248
  "\n[dim]Ratchet Guarantee: Technical debt in this repository is now locked. Run CI with:[/dim]"
1231
1249
  )
@@ -1413,8 +1431,10 @@ def _render_audit_cli_output(
1413
1431
  )
1414
1432
  if not audit_report.missing_packages and not audit_report.unused_packages:
1415
1433
  print_msg(" [green]All dependencies clean.[/green]")
1416
- if audit_report.fixed_requirements:
1417
- 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]")
1418
1438
 
1419
1439
  return (
1420
1440
  1
@@ -1428,10 +1448,12 @@ def _cmd_audit(args: argparse.Namespace, config: PyCleanerConfig, print_msg) ->
1428
1448
  root_dir = find_project_root(args.paths[0] if args.paths else None)
1429
1449
 
1430
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)
1431
1453
  auditor = DependencyAuditor(root_dir, exclude_patterns=config.exclude)
1432
1454
  audit_report = auditor.audit(
1433
- fix=getattr(args, "fix_deps", False) and not is_check,
1434
- 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,
1435
1457
  )
1436
1458
 
1437
1459
  if getattr(args, "json", False):
@@ -1501,7 +1523,7 @@ def _render_scan_cli_summary(
1501
1523
  print_msg(f"\n Findings by category: {cat_summary}")
1502
1524
 
1503
1525
  print_msg(
1504
- f"\n Total: {report.count} finding(s) "
1526
+ f"\n Total: {report.count} finding(s) - "
1505
1527
  f"[red]{report.critical_count} critical[/red], [red]{report.high_count} high[/red]"
1506
1528
  )
1507
1529
  return 1 if report.critical_count > 0 else 0
@@ -1604,7 +1626,7 @@ def _render_complexity_cli_output(
1604
1626
  else:
1605
1627
  for f in violations:
1606
1628
  print_msg(
1607
- f" {f.qualified_name} CC:{f.cyclomatic} Cog:{f.cognitive} Ln:{f.lines} Args:{f.args}"
1629
+ f" {f.qualified_name} - CC:{f.cyclomatic} Cog:{f.cognitive} Ln:{f.lines} Args:{f.args}"
1608
1630
  )
1609
1631
  print_msg(f"\n {len(violations)} function(s) exceed threshold(s).")
1610
1632
  return 1
@@ -1661,7 +1683,7 @@ def _render_dead_code_kind_group(
1661
1683
  rel_path = _try_relative(item.filepath, target_base)
1662
1684
  conf_tag = f" [{item.confidence}]" if item.confidence != "high" else ""
1663
1685
  print_msg(
1664
- f" L{item.lineno} {rel_path}: {item.name} {item.reason}{conf_tag}"
1686
+ f" L{item.lineno} {rel_path}: {item.name} - {item.reason}{conf_tag}"
1665
1687
  )
1666
1688
  if len(kind_items) > 20:
1667
1689
  print_msg(f" ... and {len(kind_items) - 20} more")
@@ -1781,7 +1803,7 @@ def _render_types_cli_summary(
1781
1803
  for f in report.findings:
1782
1804
  rel = _try_relative(f.filepath, target_base)
1783
1805
  print_msg(
1784
- f" [{f.severity.upper()}] {rel}:{f.lineno} {f.message} (expected {f.expected_type}, got {f.actual_type})"
1806
+ f" [{f.severity.upper()}] {rel}:{f.lineno} - {f.message} (expected {f.expected_type}, got {f.actual_type})"
1785
1807
  )
1786
1808
 
1787
1809
  print_msg(f"\n Total: {report.count} type finding(s) detected.")
@@ -1965,6 +1987,8 @@ def _run_ultimate_phases(
1965
1987
  print_msg(
1966
1988
  "\n[bold blue]Phase 2: Project Dependency Audit & Reconciliation[/bold blue]"
1967
1989
  )
1990
+ args.fix = True
1991
+ args.prune_deps = True
1968
1992
  audit_rc = _cmd_audit(args, config, print_msg)
1969
1993
  print_msg(
1970
1994
  "\n[bold blue]Phase 3: Bidirectional Type Verification & Typeshed Resolution[/bold blue]"
@@ -1982,7 +2006,7 @@ def _run_ultimate_phases(
1982
2006
  def _cmd_ultimate(
1983
2007
  args: argparse.Namespace, config: PyCleanerConfig, print_msg: Any, console: Any
1984
2008
  ) -> int:
1985
- """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."""
1986
2010
  print_msg(
1987
2011
  "[bold magenta]=== PyCleaner Ultimate: Full Spectrum Analysis & Healing ===[/bold magenta]\n"
1988
2012
  )
@@ -1990,14 +2014,15 @@ def _cmd_ultimate(
1990
2014
  args, config, print_msg, console
1991
2015
  )
1992
2016
  print_msg(
1993
- "\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]"
1994
2018
  )
1995
2019
  _cmd_complexity(args, config, print_msg, console)
1996
- _cmd_dead_code(args, config, print_msg, console)
2020
+ args.fix = True
2021
+ dead_rc = _cmd_dead_code(args, config, print_msg, console)
1997
2022
  print_msg(
1998
2023
  "\n[bold magenta]=== Ultimate Python Tool: Analysis Complete ===[/bold magenta]"
1999
2024
  )
2000
- 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)
2001
2026
 
2002
2027
 
2003
2028
  def _collect_file_mtimes(files: Sequence[Path]) -> dict[Path, float]:
@@ -318,7 +318,7 @@ class _NestingDepthCounter(ast.NodeVisitor):
318
318
  def visit_FunctionDef(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
319
319
  self._function_depth += 1
320
320
  if self._function_depth == 1:
321
- # Entry function being scored walk its body normally.
321
+ # Entry function being scored - walk its body normally.
322
322
  self.generic_visit(node)
323
323
  # A nested def starts counting from its own zero depth in its own
324
324
  # report entry; it must not extend the enclosing function's depth.