From 016c12c866ce4a82a77638216f457210211aa7b1 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sun, 28 Jun 2026 00:12:59 +0000 Subject: [PATCH] fix(dashboard): honor an activated $VIRTUAL_ENV before the repo .venv A stale repo .venv should not shadow an environment the developer has already activated; precedence is now LITELLM_PYTHON, $VIRTUAL_ENV, repo .venv, python3. --- ui/litellm-dashboard/scripts/gen-api-types.mjs | 13 ++++++++++--- ui/litellm-dashboard/tests/gen-api-types.test.ts | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/scripts/gen-api-types.mjs b/ui/litellm-dashboard/scripts/gen-api-types.mjs index dc988d9297f..974a391b747 100644 --- a/ui/litellm-dashboard/scripts/gen-api-types.mjs +++ b/ui/litellm-dashboard/scripts/gen-api-types.mjs @@ -20,11 +20,18 @@ import { fileURLToPath } from "node:url"; const MIN_PYTHON = { major: 3, minor: 10 }; +function venvInterpreter(root) { + return [join(root, "bin", "python"), join(root, "Scripts", "python.exe")]; +} + export function resolvePythonCommand(env, repoRoot, exists = existsSync) { if (env.LITELLM_PYTHON) return env.LITELLM_PYTHON.split(" ").filter(Boolean); - const venvCandidates = [join(repoRoot, ".venv", "bin", "python"), join(repoRoot, ".venv", "Scripts", "python.exe")]; - const venvPython = venvCandidates.find((candidate) => exists(candidate)); - return venvPython ? [venvPython] : ["python3"]; + const candidates = [ + ...(env.VIRTUAL_ENV ? venvInterpreter(env.VIRTUAL_ENV) : []), + ...venvInterpreter(join(repoRoot, ".venv")), + ]; + const found = candidates.find((candidate) => exists(candidate)); + return found ? [found] : ["python3"]; } export function parsePythonVersion(stdout) { diff --git a/ui/litellm-dashboard/tests/gen-api-types.test.ts b/ui/litellm-dashboard/tests/gen-api-types.test.ts index 80c396930d4..f6946b87632 100644 --- a/ui/litellm-dashboard/tests/gen-api-types.test.ts +++ b/ui/litellm-dashboard/tests/gen-api-types.test.ts @@ -14,6 +14,13 @@ describe("resolvePythonCommand", () => { expect(cmd).toEqual(["uv", "run", "--no-sync", "python"]); }); + it("prefers an activated $VIRTUAL_ENV over the repo's .venv", () => { + const active = "/active/bin/python"; + const repoVenv = `${repoRoot}/.venv/bin/python`; + const cmd = resolvePythonCommand({ VIRTUAL_ENV: "/active" }, repoRoot, (p) => p === active || p === repoVenv); + expect(cmd).toEqual([active]); + }); + it("prefers the repo's .venv interpreter over a bare python3", () => { const venv = `${repoRoot}/.venv/bin/python`; const cmd = resolvePythonCommand({}, repoRoot, (p) => p === venv);