Ctrl K
ComunidadGuías…

scripts/check-uv-lock-export-drift.py

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

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Fail unless requirements.lock is the exact frozen export of uv.lock."""

from __future__ import annotations

import shutil
import subprocess
from pathlib import Path

REPO = Path(__file__).resolve().parents[1]
UV_LOCK = REPO / "uv.lock"
REQUIREMENTS_LOCK = REPO / "requirements.lock"
_EXPORT_ARGS = (
    "export",
    "--frozen",
    "--no-emit-workspace",
    "--no-dev",
    "--format",
    "requirements-txt",
    "--no-emit-package",
    "kotakneoapi",
    "--no-emit-package",
    "upstox-python-sdk",
)


class ExportError(RuntimeError):
    """Raised when a fresh frozen uv export cannot be produced."""


def _export_requirements() -> str:
    uv = shutil.which("uv")
    if uv is None:
        raise ExportError("uv is unavailable; cannot verify requirements.lock")
    try:
        completed = subprocess.run(  # noqa: S603 - resolved trusted tool with fixed arguments
            [uv, *_EXPORT_ARGS],
            cwd=REPO,
            check=False,
            capture_output=True,
            text=True,
            timeout=120,
        )
    except (OSError, subprocess.TimeoutExpired) as exc:
        raise ExportError(f"uv export failed: {type(exc).__name__}") from exc
    if completed.returncode != 0:
        detail = completed.stderr.strip().splitlines()
        suffix = f": {detail[-1]}" if detail else ""
        raise ExportError(f"uv export failed with exit {completed.returncode}{suffix}")
    if not completed.stdout:
        raise ExportError("uv export returned no requirements")
    return completed.stdout


def _without_generated_header(value: str) -> str:
    lines = value.splitlines(keepends=True)
    if (
        len(lines) >= 2
        and lines[0].startswith("# This file was autogenerated by uv")
        and lines[1].startswith("#    uv export")
    ):
        return "".join(lines[2:])
    return value


def main() -> int:
    missing = [str(path) for path in (UV_LOCK, REQUIREMENTS_LOCK) if not path.is_file()]
    if missing:
        print("missing lockfile(s): " + ", ".join(missing))
        return 1
    try:
        actual = REQUIREMENTS_LOCK.read_text(encoding="utf-8")
        exported = _export_requirements()
    except (OSError, UnicodeError, ExportError) as exc:
        print(str(exc))
        return 1
    if _without_generated_header(actual) != _without_generated_header(exported):
        command = "uv " + " ".join(_EXPORT_ARGS) + " --output-file requirements.lock"
        print("requirements.lock does not match the frozen uv export")
        print(f"regenerate with: {command}")
        return 1
    return 0


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