litellm/scripts/prisma_generate_if_needed.py
Mateo Wang cf6fdac304
perf(lint): skip and cache base gate passes, parallelize make lint, skip redundant prisma generate (#32000)
* perf(lint): skip and cache base gate passes, parallelize make lint, skip redundant prisma generate

make pre-commit paid for a full second basedpyright pass over a merge-base
worktree on every run even when no rule was over its ceiling, re-generated an
unchanged Prisma client, and ran seven independent checks sequentially. The
basedpyright and ruff strict gates now skip the base pass when head is within
every limit (the same early-out type_discipline_gate already had), the
basedpyright base counts are cached under the git common dir keyed by
merge-base commit, pyrightconfig.json, and uv.lock, prisma generate only runs
when the schema or prisma version changed, and make lint fans its checks out
through a parallel sub-make after a single setup phase

* fix(lint): keep the base-cache scratch file out of the prune glob

The tmp+rename scratch in store_counts was named basedpyright-base-<hash>.json.tmp,
which the stale-entry prune glob (basedpyright-base-*) also matches, so a concurrent
lint run from another worktree sharing the same git common dir could unlink it between
write_text and replace and crash the gate with FileNotFoundError. The scratch is now
dot-prefixed so the glob can never see it, pid-suffixed so concurrent writers of the
same entry never share a scratch, and the prune glob is restricted to committed
*.json entries
2026-07-02 19:24:00 -07:00

69 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Run ``prisma generate`` only when its inputs changed since the last run.
The generated client is a pure function of ``litellm/proxy/schema.prisma`` and
the installed prisma package version, so a stamp of those two written next to
the venv is enough to prove the client is current. The stamp lives under
``sys.prefix`` so recreating the venv discards it, and a missing generated
client (a fresh or reinstalled prisma package) forces a regenerate even when
the stamp matches. The prisma package itself is never imported here: once
generated it re-exports the whole client on import, which costs more than the
generate this script exists to skip.
"""
import hashlib
import importlib.metadata
import importlib.util
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
SCHEMA = REPO_ROOT / "litellm" / "proxy" / "schema.prisma"
STAMP = Path(sys.prefix) / "litellm-prisma-schema.stamp"
def stamp_value(schema_bytes: bytes, prisma_version: str) -> str:
return f"{hashlib.sha256(schema_bytes).hexdigest()}:{prisma_version}"
def should_skip(stamp: Path, expected: str, client_generated: bool) -> bool:
if not client_generated:
return False
try:
return stamp.read_text() == expected
except OSError:
return False
def client_is_generated() -> bool:
spec = importlib.util.find_spec("prisma")
if spec is None or not spec.submodule_search_locations:
return False
return any(
(Path(location) / "client.py").exists()
for location in spec.submodule_search_locations
)
def main() -> int:
version = importlib.metadata.version("prisma")
expected = stamp_value(SCHEMA.read_bytes(), version)
if should_skip(STAMP, expected, client_is_generated()):
print(
f"Prisma client already generated for {SCHEMA.relative_to(REPO_ROOT)} "
f"(prisma {version}); skipping prisma generate"
)
return 0
result = subprocess.run(
[sys.executable, "-m", "prisma", "generate", "--schema", str(SCHEMA)],
cwd=REPO_ROOT,
)
if result.returncode != 0:
return result.returncode
STAMP.write_text(expected)
return 0
if __name__ == "__main__":
raise SystemExit(main())