Ctrl K
ComunidadGuías…

scripts/audit_entrypoints.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Verify console-script targets resolve to real top-level callables in src/dm."""
from __future__ import annotations

import argparse
import ast
import tomllib
from pathlib import Path

from scripts.audit_common import print_failures, require_root


def _target_path(root: Path, module: str) -> Path:
    parts = module.split(".")
    if not parts or parts[0] != "dm" or any(not part.isidentifier() for part in parts):
        raise ValueError(f"unsupported entrypoint module: {module}")
    return root / "src" / Path(*parts).with_suffix(".py")


def audit(root: Path) -> list[str]:
    root = require_root(root)
    try:
        data = tomllib.loads((root / "pyproject.toml").read_text(encoding="utf-8"))
    except (OSError, UnicodeError, tomllib.TOMLDecodeError) as exc:
        return [f"pyproject.toml: could not parse entrypoints ({exc})"]
    scripts = data.get("project", {}).get("scripts", {})
    if not isinstance(scripts, dict):
        return ["pyproject.toml: [project.scripts] table is missing"]
    failures: list[str] = []
    for name, target in sorted(scripts.items()):
        if not isinstance(target, str) or target.count(":") != 1:
            failures.append(f"{name}: entrypoint must use module:function syntax"); continue
        module, function = target.split(":", 1)
        if not function.isidentifier():
            failures.append(f"{name}: invalid entrypoint function {function!r}"); continue
        try: path = _target_path(root, module)
        except ValueError as exc: failures.append(f"{name}: {exc}"); continue
        if not path.is_file():
            failures.append(f"{name}: entrypoint module is missing: {path.relative_to(root)}"); continue
        try: tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
        except (OSError, UnicodeError, SyntaxError) as exc:
            failures.append(f"{name}: could not parse entrypoint module ({exc})"); continue
        if not any(isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == function for node in tree.body):
            failures.append(f"{name}: top-level callable {function} is missing in {path.relative_to(root)}")
    return failures


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description=__doc__); parser.add_argument("root", nargs="?", default=".")
    args = parser.parse_args(argv); return print_failures(audit(Path(args.root)))


if __name__ == "__main__": raise SystemExit(main())