|
| 1 | +import ast |
| 2 | +from pathlib import Path |
| 3 | + |
| 4 | +from connector_linter.models import ConnectorContext |
| 5 | + |
| 6 | +# --------------------------------------------------------------------------- |
| 7 | +# Source reading |
| 8 | +# --------------------------------------------------------------------------- |
| 9 | + |
| 10 | + |
| 11 | +def read_all_python_sources(ctx: ConnectorContext) -> dict[Path, str]: |
| 12 | + """Read all Python source files from the connector's src/ directory.""" |
| 13 | + sources: dict[Path, str] = {} |
| 14 | + # Convention: all connector Python code lives under <connector>/src/ |
| 15 | + src_dir = ctx.path / "src" |
| 16 | + if not src_dir.exists(): |
| 17 | + return sources |
| 18 | + for py_file in src_dir.rglob("*.py"): |
| 19 | + # Key by relative path (from connector root) for portable reporting |
| 20 | + rel_path = py_file.relative_to(ctx.path) |
| 21 | + try: |
| 22 | + # errors="replace" avoids UnicodeDecodeError on malformed files |
| 23 | + sources[rel_path] = py_file.read_text(encoding="utf-8", errors="replace") |
| 24 | + except OSError: |
| 25 | + # Skip unreadable files (permissions, broken symlinks, etc.) |
| 26 | + continue |
| 27 | + return sources |
| 28 | + |
| 29 | + |
| 30 | +# --------------------------------------------------------------------------- |
| 31 | +# AST helpers — structural analysis of Python source |
| 32 | +# --------------------------------------------------------------------------- |
| 33 | + |
| 34 | + |
| 35 | +def parse_sources(sources: dict[Path, str]) -> dict[Path, ast.Module]: |
| 36 | + """Parse all source files into AST modules. |
| 37 | +
|
| 38 | + Files that fail to parse (syntax errors) are silently skipped. |
| 39 | + """ |
| 40 | + trees: dict[Path, ast.Module] = {} |
| 41 | + for file_path, content in sources.items(): |
| 42 | + try: |
| 43 | + trees[file_path] = ast.parse(content, filename=str(file_path)) |
| 44 | + except SyntaxError: |
| 45 | + # Silently skip files with syntax errors — they can't be analyzed |
| 46 | + # structurally, but other checks (regex-based) may still find issues. |
| 47 | + continue |
| 48 | + return trees |
0 commit comments