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.
This commit is contained in:
mateo-berri 2026-06-28 00:12:59 +00:00
parent 2c75e1f0c3
commit 016c12c866
No known key found for this signature in database
2 changed files with 17 additions and 3 deletions

View file

@ -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) {

View file

@ -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);