({
pythonVersion,
venvPath,
uvPath,
uvCacheDir,
quiet,
}: {
pythonVersion: { pythonPath: string; major?: number; minor?: number };
venvPath: string;
uvPath?: string | null;
uvCacheDir?: string;
quiet?: boolean;
})
| 77 | } |
| 78 | |
| 79 | export async function ensureVenv({ |
| 80 | pythonVersion, |
| 81 | venvPath, |
| 82 | uvPath, |
| 83 | uvCacheDir, |
| 84 | quiet, |
| 85 | }: { |
| 86 | pythonVersion: { pythonPath: string; major?: number; minor?: number }; |
| 87 | venvPath: string; |
| 88 | uvPath?: string | null; |
| 89 | uvCacheDir?: string; |
| 90 | quiet?: boolean; |
| 91 | }) { |
| 92 | const marker = join(venvPath, 'pyvenv.cfg'); |
| 93 | let venvExists = false; |
| 94 | |
| 95 | try { |
| 96 | await fs.promises.access(marker); |
| 97 | venvExists = true; |
| 98 | } catch { |
| 99 | // venv doesn't exist yet |
| 100 | } |
| 101 | |
| 102 | // Invalidate if the cached venv was built with a different Python version. |
| 103 | if ( |
| 104 | venvExists && |
| 105 | pythonVersion.major != null && |
| 106 | pythonVersion.minor != null |
| 107 | ) { |
| 108 | const expected = `${pythonVersion.major}.${pythonVersion.minor}`; |
| 109 | const cachedVersion = await readVenvPythonVersion(marker); |
| 110 | if (cachedVersion && cachedVersion !== expected) { |
| 111 | if (!quiet) { |
| 112 | console.log( |
| 113 | `Cached venv Python ${cachedVersion} differs from requested ${expected}, recreating...` |
| 114 | ); |
| 115 | } |
| 116 | await fs.promises.rm(venvPath, { recursive: true, force: true }); |
| 117 | venvExists = false; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | if (venvExists) { |
| 122 | debug(`Refreshing cached virtual environment at "${venvPath}"`); |
| 123 | } else { |
| 124 | await fs.promises.mkdir(venvPath, { recursive: true }); |
| 125 | if (!quiet) { |
| 126 | console.log(`Creating virtual environment at "${venvPath}"...`); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | if (uvPath) { |
| 131 | // --allow-existing allows uv to reuse a cached venv |
| 132 | // --seed installs pip into the venv so custom install commands can use it |
| 133 | const args = ['venv', venvPath, '--allow-existing', '--seed']; |
| 134 | if (pythonVersion.major != null && pythonVersion.minor != null) { |
| 135 | args.push('--python', `${pythonVersion.major}.${pythonVersion.minor}`); |
| 136 | } |
no test coverage detected