From ee35190ed73254a3fb71026b4c95ff9a3993893f Mon Sep 17 00:00:00 2001 From: Austin Dickey Date: Thu, 16 Jul 2026 21:44:07 -0500 Subject: [PATCH] python: reclassify base uv interpreters as Global --- .../common/environmentManagers/uv.ts | 79 +++++++++++---- .../client/pythonEnvironments/nativeAPI.ts | 24 ++++- .../environmentManagers/uv.unit.test.ts | 95 ++++++++++++++++--- .../pythonEnvironments/nativeAPI.unit.test.ts | 82 ++++++++++++---- test/e2e/pages/sessions.ts | 5 +- .../new-folder-flow-python.test.ts | 6 +- 6 files changed, 226 insertions(+), 65 deletions(-) diff --git a/extensions/positron-python/src/client/pythonEnvironments/common/environmentManagers/uv.ts b/extensions/positron-python/src/client/pythonEnvironments/common/environmentManagers/uv.ts index 59d2b7685fac..39983c3dca03 100644 --- a/extensions/positron-python/src/client/pythonEnvironments/common/environmentManagers/uv.ts +++ b/extensions/positron-python/src/client/pythonEnvironments/common/environmentManagers/uv.ts @@ -9,9 +9,9 @@ import * as fs from 'fs'; import { cache } from '../../../common/utils/decorators'; import { clearCache } from '../../../common/utils/cacheUtils'; import { traceError, traceVerbose } from '../../../logging'; -import { exec, pathExists, readFile, resolveSymbolicLink } from '../externalDependencies'; +import { canonicalizePath, exec, isParentPath, pathExists, readFile } from '../externalDependencies'; import { isTestExecution, MINIMUM_PYTHON_VERSION, MAXIMUM_PYTHON_VERSION_EXCLUSIVE } from '../../../common/constants'; -import { getPyvenvConfigPathsFrom } from './simplevirtualenvs'; +import { getPyvenvConfigPathsFrom, isVenvEnvironment } from './simplevirtualenvs'; import { splitLines } from '../../../common/stringUtils'; import { CreateEnv } from '../../../common/utils/localize'; @@ -134,7 +134,60 @@ export function resetUvCache(): void { } /** - * Checks if the given interpreter belongs to a uv-managed environment. + * Checks whether an interpreter resolves to a location under uv's managed Python directory. + * Both paths are canonicalized first (the same technique getEnvIdentity uses), so a symlinked + * intermediate directory or mount point can't hide a path that really lives under the uv python + * dir: uv's own `cpython-3.14` -> `cpython-3.14.6` version-directory symlink (issue #14489), a + * `.venv/bin/python` symlinked to its uv-managed base, or an install dir relocated behind a + * symlink like `/tmp` -> `/private/tmp`. isParentPath then matches on path boundaries, so a + * sibling like `-backup/...` that only shares the string prefix is not counted as inside. + * + * Both a uv-managed standalone install and a uv-created venv canonicalize to a path here, so + * callers that need to tell base installs apart from venvs must apply their own venv check. + * @param interpreterPath Absolute path to the python interpreter. + * @param uvDir The uv-managed Python directory (from `uv python dir`). + */ +async function isUnderUvPythonDir(interpreterPath: string, uvDir: string): Promise { + const [canonicalInterpreter, canonicalUvDir] = await Promise.all([ + canonicalizePath(interpreterPath), + canonicalizePath(uvDir), + ]); + return isParentPath(canonicalInterpreter, canonicalUvDir); +} + +/** + * Checks whether an interpreter is a uv-managed standalone Python installation - a base + * interpreter that uv downloaded (living under `uv python dir`), as distinct from a + * uv-created virtual environment. Standalone installs are base/global interpreters, not + * dedicated environments. + * @param interpreterPath Absolute path to the python interpreter. + * @returns {boolean} Returns true if the interpreter is a uv-managed standalone install. + */ +export async function isUvManagedBasePython(interpreterPath: string): Promise { + const uvUtils = await UvUtils.getUvUtils(); + if (!uvUtils) { + return false; + } + + const uvDir = await uvUtils.getUvDir(); + if (!uvDir) { + return false; + } + + // A virtual environment is never a standalone base install, even when its interpreter + // symlinks into the uv python directory: a uv-created venv points its `python` at the + // uv-managed base it was built from. Exclude anything with a pyvenv.cfg so those venvs + // stay classified as uv environments rather than global base Pythons. + if (await isVenvEnvironment(interpreterPath)) { + return false; + } + + return isUnderUvPythonDir(interpreterPath, uvDir); +} + +/** + * Checks if the given interpreter belongs to a uv-managed environment (a standalone install + * or a uv-created venv). * @param interpreterPath Absolute path to the python interpreter. * @returns {boolean} Returns true if the interpreter belongs to a uv environment. */ @@ -149,27 +202,11 @@ export async function isUvEnvironment(interpreterPath: string): Promise return false; } - // Check if interpreter is directly in the uv directory - const normalizedInterpreterPath = path.normalize(interpreterPath); - const normalizedUvDir = path.normalize(uvDir); - if (normalizedInterpreterPath.startsWith(normalizedUvDir)) { + // A uv-managed standalone Python install lives under the uv python directory. + if (await isUnderUvPythonDir(interpreterPath, uvDir)) { return true; } - // Check if it's a symlink pointing to the uv directory - try { - const resolvedPath = await resolveSymbolicLink(interpreterPath); - if ( - resolvedPath && - resolvedPath !== interpreterPath && - path.normalize(resolvedPath).startsWith(normalizedUvDir) - ) { - return true; - } - } catch (ex) { - traceVerbose(ex); - } - // Check if there's a pyvenv.cfg file with a uv key const configPaths = getPyvenvConfigPathsFrom(interpreterPath); for (const configPath of configPaths) { diff --git a/extensions/positron-python/src/client/pythonEnvironments/nativeAPI.ts b/extensions/positron-python/src/client/pythonEnvironments/nativeAPI.ts index 78cf6ad7ab1f..01e4b7d892ff 100644 --- a/extensions/positron-python/src/client/pythonEnvironments/nativeAPI.ts +++ b/extensions/positron-python/src/client/pythonEnvironments/nativeAPI.ts @@ -41,7 +41,7 @@ import { import { getWorkspaceFolders, onDidChangeWorkspaceFolders } from '../common/vscodeApis/workspaceApis'; // --- Start Positron --- -import { getUvDirs, isUvEnvironment } from './common/environmentManagers/uv'; +import { getUvDirs, isUvEnvironment, isUvManagedBasePython } from './common/environmentManagers/uv'; import { isCustomEnvironment } from '../positron/interpreterSettings'; import { isAdditionalGlobalBinPath } from './common/environmentManagers/globalInstalledEnvs'; // eslint-disable-next-line import/no-duplicates @@ -582,9 +582,25 @@ class NativePythonEnvironments implements IDiscoveryAPI, Disposable { private async addEnv(native: NativeEnvInfo, searchLocation?: Uri): Promise { const info = await toPythonEnvInfo(native, this._condaEnvDirs); if (info) { - if (info.executable.filename && (await isUvEnvironment(info.executable.filename))) { - traceInfo(`Found uv environment: ${info.executable.filename}`); - info.kind = PythonEnvKind.Uv; + if (info.executable.filename) { + if (await isUvManagedBasePython(info.executable.filename)) { + // A uv-managed standalone Python install is a base interpreter, not a + // dedicated environment. Classify it as a global Python so the picker, + // recommendation ranking, health check, and venv-base selection treat + // it like any other standalone Python rather than a uv virtual env. + traceInfo(`Found uv-managed base Python: ${info.executable.filename}`); + info.kind = PythonEnvKind.OtherGlobal; + // toPythonEnvInfo derived type and display name from the pre-override + // kind, which PET reported as Uv (type Virtual, label "(uv)"). Recompute + // both so the corrected global kind is reflected everywhere. + info.type = getEnvType(info.kind); + const display = getDisplayName(info.version, info.kind, info.arch, info.name); + info.detailedDisplayName = display; + info.display = display; + } else if (await isUvEnvironment(info.executable.filename)) { + traceInfo(`Found uv environment: ${info.executable.filename}`); + info.kind = PythonEnvKind.Uv; + } } let old = this._envs.find((item) => item.executable.filename === info.executable.filename); if (!old) { diff --git a/extensions/positron-python/src/test/pythonEnvironments/common/environmentManagers/uv.unit.test.ts b/extensions/positron-python/src/test/pythonEnvironments/common/environmentManagers/uv.unit.test.ts index 6d2477a5745e..f1fbfe17da79 100644 --- a/extensions/positron-python/src/test/pythonEnvironments/common/environmentManagers/uv.unit.test.ts +++ b/extensions/positron-python/src/test/pythonEnvironments/common/environmentManagers/uv.unit.test.ts @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (C) 2025 Posit Software, PBC. All rights reserved. + * Copyright (C) 2025-2026 Posit Software, PBC. All rights reserved. * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. *--------------------------------------------------------------------------------------------*/ @@ -10,6 +10,7 @@ import * as sinon from 'sinon'; import * as fileUtils from '../../../../client/pythonEnvironments/common/externalDependencies'; import { isUvEnvironment, + isUvManagedBasePython, isUvInstalled, getUvDirs, getUvPythonVersionInfo, @@ -21,7 +22,7 @@ import * as logging from '../../../../client/logging'; import * as simplevenv from '../../../../client/pythonEnvironments/common/environmentManagers/simplevirtualenvs'; suite('uv Environment Tests', () => { - let resolveSymbolicLinkStub: sinon.SinonStub; + let canonicalizePathStub: sinon.SinonStub; let getOSTypeStub: sinon.SinonStub; let getEnvironmentVariableStub: sinon.SinonStub; let execStub: sinon.SinonStub; @@ -34,7 +35,7 @@ suite('uv Environment Tests', () => { const exampleUvPython = `${customDir}/cpython-3.12`; setup(() => { - resolveSymbolicLinkStub = sinon.stub(fileUtils, 'resolveSymbolicLink'); + canonicalizePathStub = sinon.stub(fileUtils, 'canonicalizePath'); getOSTypeStub = sinon.stub(platformUtils, 'getOSType'); getEnvironmentVariableStub = sinon.stub(platformUtils, 'getEnvironmentVariable'); execStub = sinon.stub(fileUtils, 'exec'); @@ -46,6 +47,9 @@ suite('uv Environment Tests', () => { getPyvenvConfigPathsStub.returns([]); getOSTypeStub.returns(platformUtils.OSType.Linux); execStub.resolves({ stdout: customDir }); + // Default to identity: a path with no symlinks canonicalizes to itself. Individual + // tests override withArgs to model a symlink/mount resolving to a different real path. + canonicalizePathStub.callsFake(async (p: string) => p); }); teardown(() => { @@ -95,7 +99,9 @@ suite('uv Environment Tests', () => { test('Works on Windows', async () => { const appData = 'C:\\Users\\user\\AppData\\Roaming'; const uvDir = `${appData}\\uv\\data\\python`; - const interpreter = `${uvDir}\\env123\\Scripts\\python.exe`; + // Build the interpreter under uvDir with path.join so the path-boundary match lines + // up with the host separator (this suite simulates Windows on a POSIX test host). + const interpreter = path.join(uvDir, 'env123', 'Scripts', 'python.exe'); getOSTypeStub.returns(platformUtils.OSType.Windows); getEnvironmentVariableStub .withArgs('APPDATA') @@ -108,23 +114,26 @@ suite('uv Environment Tests', () => { assert.strictEqual(result, true); }); - test('Works with a symlink to the python dir', async () => { + test('Works with a symlink into the python dir', async () => { const interpreter = '/path/to/venv/bin/python'; - resolveSymbolicLinkStub.withArgs(interpreter).resolves(exampleUvPython); + canonicalizePathStub.withArgs(interpreter).resolves(exampleUvPython); assert.ok(await isUvEnvironment(interpreter)); }); - test('symlink resolution fails', async () => { - const interpreter = '/path/to/venv/bin/python'; - resolveSymbolicLinkStub.withArgs(interpreter).rejects(new Error('Failed to resolve symlink')); - assert.strictEqual(await isUvEnvironment(interpreter), false); + test('Canonicalizes intermediate directory symlinks into the python dir', async () => { + // uv installs a real `cpython-3.14.6-` dir and a `cpython-3.14-` + // symlink to it (issue #14489). An interpreter reached through the symlinked dir is + // not itself a symlink, so full canonicalization (not leaf-only) is what matches it. + const interpreter = `${customDir}/cpython-3.14-linux/bin/python`; + canonicalizePathStub.withArgs(interpreter).resolves(`${customDir}/cpython-3.14.6-linux/bin/python`); + + assert.strictEqual(await isUvEnvironment(interpreter), true); }); - test('symlink resolves but not to uv directory', async () => { + test('Resolves but not to uv directory', async () => { const interpreter = '/path/to/venv/bin/python'; - const resolvedPath = '/path/to/other/venv/bin/python'; - resolveSymbolicLinkStub.withArgs(interpreter).resolves(resolvedPath); + canonicalizePathStub.withArgs(interpreter).resolves('/path/to/other/venv/bin/python'); assert.strictEqual(await isUvEnvironment(interpreter), false); }); }); @@ -203,6 +212,66 @@ suite('uv Environment Tests', () => { }); }); + suite('isUvManagedBasePython Tests', () => { + test('True for an interpreter directly under the uv python dir', async () => { + assert.strictEqual(await isUvManagedBasePython(exampleUvPython), true); + }); + + test('True for a symlink that resolves into the uv python dir', async () => { + const interpreter = '/home/user/.local/bin/python3.13'; + canonicalizePathStub.withArgs(interpreter).resolves(exampleUvPython); + + assert.strictEqual(await isUvManagedBasePython(interpreter), true); + }); + + test('False when uv is not installed', async () => { + execStub.rejects(new Error('Command failed')); + + assert.strictEqual(await isUvManagedBasePython(exampleUvPython), false); + }); + + test('False for a uv venv (pyvenv.cfg uv key, not under the uv dir)', async () => { + // A uv-created venv is a uv environment but NOT a standalone base install: its + // interpreter lives in the venv, and only a pyvenv.cfg uv key identifies it. + const interpreterPath = '/path/to/venv/bin/python'; + const configPath = '/path/to/venv/pyvenv.cfg'; + getPyvenvConfigPathsStub.returns([configPath]); + pathExistsStub.withArgs(configPath).resolves(true); + readFileStub.withArgs(configPath).resolves('home = /usr/bin\nuv = 0.1.0\nversion = 3.11.0'); + + assert.strictEqual(await isUvManagedBasePython(interpreterPath), false); + // Same env IS recognized as a uv environment, just not a base install. + assert.strictEqual(await isUvEnvironment(interpreterPath), true); + }); + + test('False for a uv venv whose interpreter symlinks into the uv python dir', async () => { + // Regression: a uv-created venv's `.venv/bin/python` symlinks to the uv-managed base + // it was built from, which lives under the uv python dir. It is still a venv, so the + // pyvenv.cfg check must win over the canonicalizes-into-the-uv-dir signal. + // Build the paths with path.join so the pyvenv.cfg lookup inside isVenvEnvironment + // (which uses path.join) lines up with the host separator (this suite runs on both + // POSIX and Windows hosts). + const venvDir = path.join(path.sep, 'workspace', '.venv'); + const interpreterPath = path.join(venvDir, 'bin', 'python'); + const configPath = path.join(venvDir, 'pyvenv.cfg'); + getPyvenvConfigPathsStub.returns([configPath]); + pathExistsStub.withArgs(configPath).resolves(true); + canonicalizePathStub.withArgs(interpreterPath).resolves(exampleUvPython); + + assert.strictEqual(await isUvManagedBasePython(interpreterPath), false); + // The same interpreter is still recognized as a uv environment. + assert.strictEqual(await isUvEnvironment(interpreterPath), true); + }); + + test('False for an interpreter in a sibling dir sharing the uv dir path prefix', async () => { + // Regression: `-backup/...` shares a string prefix with the uv dir but is not + // inside it, so a bare prefix match must not classify it as a uv-managed base Python. + const interpreterPath = `${customDir}-backup/cpython-3.12/bin/python`; + + assert.strictEqual(await isUvManagedBasePython(interpreterPath), false); + }); + }); + suite('isUvInstalled Tests', () => { test('Returns true when uv is installed and working', async () => { execStub.resolves({ stdout: customDir }); diff --git a/extensions/positron-python/src/test/pythonEnvironments/nativeAPI.unit.test.ts b/extensions/positron-python/src/test/pythonEnvironments/nativeAPI.unit.test.ts index 64d1a79072f6..10487aca433b 100644 --- a/extensions/positron-python/src/test/pythonEnvironments/nativeAPI.unit.test.ts +++ b/extensions/positron-python/src/test/pythonEnvironments/nativeAPI.unit.test.ts @@ -39,6 +39,7 @@ suite('Native Python API', () => { let getWorkspaceFoldersStub: sinon.SinonStub; // --- Start Positron --- let isUvEnvironmentStub: sinon.SinonStub; + let isUvManagedBasePythonStub: sinon.SinonStub; // --- End Positron --- const basicEnv: NativeEnvInfo = { @@ -152,6 +153,7 @@ suite('Native Python API', () => { setPyEnvBinaryStub = sinon.stub(pyenvApi, 'setPyEnvBinary'); // --- Start Positron --- isUvEnvironmentStub = sinon.stub(uvApi, 'isUvEnvironment'); + isUvManagedBasePythonStub = sinon.stub(uvApi, 'isUvManagedBasePython'); // --- End Positron --- getWorkspaceFoldersStub = sinon.stub(ws, 'getWorkspaceFolders'); getWorkspaceFoldersStub.returns([]); @@ -349,9 +351,10 @@ suite('Native Python API', () => { }); // --- Start Positron --- - test('uv environment detected and converted during addEnv via triggerRefresh', async () => { - // Create a test environment that looks like a regular VirtualEnv initially - const uvEnv: NativeEnvInfo = { + test('uv-managed base Python classified as global during addEnv via triggerRefresh', async () => { + // A uv-managed standalone Python install lives under the uv python dir. It is a base + // interpreter, not a dedicated environment, so it must be classified as global. + const uvBasePython: NativeEnvInfo = { displayName: 'uv environment', name: 'my_uv_env', executable: '/home/user/.local/share/uv/python/cpython-3.11.5/bin/python', @@ -360,15 +363,16 @@ suite('Native Python API', () => { prefix: '/home/user/.local/share/uv/python/cpython-3.11.5', }; - // Mock isUvEnvironment to return true for this environment - isUvEnvironmentStub.withArgs(uvEnv.executable).resolves(true); + isUvManagedBasePythonStub.withArgs(uvBasePython.executable).resolves(true); + // addEnv awaits getAdditionalEnvDirs (which spawns uv); stub it for a hermetic test. + sinon.stub(nativeFinder, 'getAdditionalEnvDirs').resolves([]); // Setup the finder to return our test env during refresh mockFinder .setup((f) => f.refresh()) .returns(() => { async function* generator() { - yield* [uvEnv]; + yield* [uvBasePython]; } return generator(); }) @@ -377,22 +381,23 @@ suite('Native Python API', () => { // Trigger refresh which will call addEnv internally await api.triggerRefresh(); - // Get the environments and verify the uv environment was converted + // Get the environments and verify the base Python was classified as global const envs = api.getEnvs(); assert.equal(envs.length, 1); const addedEnv = envs[0]; assert.isDefined(addedEnv); - assert.equal(addedEnv.kind, PythonEnvKind.Uv); + assert.equal(addedEnv.kind, PythonEnvKind.OtherGlobal); assert.equal(addedEnv.executable.filename, '/home/user/.local/share/uv/python/cpython-3.11.5/bin/python'); - // Verify isUvEnvironment was called during addEnv - assert.isTrue(isUvEnvironmentStub.calledWith('/home/user/.local/share/uv/python/cpython-3.11.5/bin/python')); + // The base-vs-venv discriminator short-circuits before isUvEnvironment. + assert.isTrue( + isUvManagedBasePythonStub.calledWith('/home/user/.local/share/uv/python/cpython-3.11.5/bin/python'), + ); }); - test('uv environment detected and converted during resolveEnv', async () => { - // Create a test environment - const uvEnv: NativeEnvInfo = { + test('uv-managed base Python classified as global during resolveEnv', async () => { + const uvBasePython: NativeEnvInfo = { displayName: 'uv Python', name: 'uv_python', executable: '/home/user/.local/share/uv/python/cpython-3.10', @@ -401,25 +406,60 @@ suite('Native Python API', () => { prefix: '/home/user/.local/share/uv/python', }; - // Mock the isUvEnvironment to return true for this environment - isUvEnvironmentStub.withArgs(uvEnv.executable).resolves(true); + isUvManagedBasePythonStub.withArgs(uvBasePython.executable).resolves(true); + // addEnv awaits getAdditionalEnvDirs (which spawns uv); stub it for a hermetic test. + sinon.stub(nativeFinder, 'getAdditionalEnvDirs').resolves([]); // Setup the finder to return our test env when resolving mockFinder .setup((f) => f.resolve('/home/user/.local/share/uv/python/cpython-3.10')) - .returns(() => Promise.resolve(uvEnv)) + .returns(() => Promise.resolve(uvBasePython)) .verifiable(typemoq.Times.once()); // Resolve the environment const resolved = await api.resolveEnv('/home/user/.local/share/uv/python/cpython-3.10'); - // Verify the environment was recognized as Uv + // Verify the base Python was classified as global assert.isDefined(resolved); - assert.equal(resolved?.kind, PythonEnvKind.Uv); + assert.equal(resolved?.kind, PythonEnvKind.OtherGlobal); + + // The classifier is consulted for this path during resolution. + assert.isTrue(isUvManagedBasePythonStub.calledWith('/home/user/.local/share/uv/python/cpython-3.10')); + }); + + test('uv venv kept as Uv during addEnv via triggerRefresh', async () => { + // A uv-created venv is a uv environment but not a standalone base install, so it stays + // classified as Uv (a dedicated environment). + const uvVenv: NativeEnvInfo = { + displayName: 'uv venv', + name: 'my_project', + executable: '/home/user/projects/my_project/.venv/bin/python', + kind: NativePythonEnvironmentKind.VirtualEnv, + version: '3.12.1', + prefix: '/home/user/projects/my_project/.venv', + }; - // Verify isUvEnvironment was called twice (once when adding; once when resolving) - assert.isTrue(isUvEnvironmentStub.calledTwice); - assert.isTrue(isUvEnvironmentStub.calledWith('/home/user/.local/share/uv/python/cpython-3.10')); + isUvManagedBasePythonStub.withArgs(uvVenv.executable).resolves(false); + isUvEnvironmentStub.withArgs(uvVenv.executable).resolves(true); + // addEnv awaits getAdditionalEnvDirs (which spawns uv); stub it for a hermetic test. + sinon.stub(nativeFinder, 'getAdditionalEnvDirs').resolves([]); + + mockFinder + .setup((f) => f.refresh()) + .returns(() => { + async function* generator() { + yield* [uvVenv]; + } + return generator(); + }) + .verifiable(typemoq.Times.once()); + + await api.triggerRefresh(); + + const envs = api.getEnvs(); + assert.equal(envs.length, 1); + assert.equal(envs[0]?.kind, PythonEnvKind.Uv); + assert.isTrue(isUvEnvironmentStub.calledWith('/home/user/projects/my_project/.venv/bin/python')); }); test('Pre-release version (alpha) is included in display name', async () => { diff --git a/test/e2e/pages/sessions.ts b/test/e2e/pages/sessions.ts index 22cf3454b8d2..ea8ad74a34ee 100644 --- a/test/e2e/pages/sessions.ts +++ b/test/e2e/pages/sessions.ts @@ -24,10 +24,7 @@ export const DISCONNECTED_STATUS_ICON = '.codicon-positron-runtime-status-discon // base pyenv both shown as "Python 3.10.12"); when that happens we want the real // environment, not the base install. The values match the "(" portion of // the quick pick label produced by getRuntimeSourceAndShortName. -// -// '(uv)' keeps its closing paren so it matches only a standalone uv-managed Python, -// not a uv project venv labeled "(uv: )" -- the venv is what we want to keep. -export const DEPRIORITIZED_PYTHON_SOURCES = ['(Pyenv', '(Global', '(System', '(Unknown', '(uv)']; +export const DEPRIORITIZED_PYTHON_SOURCES = ['(Pyenv', '(Global', '(System', '(Unknown']; // Quickpick labels - keep in sync with languageRuntimeActions.ts const INTERPRETER_SESSIONS_LABEL = 'Interpreter Sessions'; diff --git a/test/e2e/tests/new-folder-flow/new-folder-flow-python.test.ts b/test/e2e/tests/new-folder-flow/new-folder-flow-python.test.ts index 84fcea63d1d2..efbe61b9b22d 100644 --- a/test/e2e/tests/new-folder-flow/new-folder-flow-python.test.ts +++ b/test/e2e/tests/new-folder-flow/new-folder-flow-python.test.ts @@ -40,7 +40,7 @@ test.describe('New Folder Flow: Python Project', { // untagged windows because we cannot find any way to copy text from the terminal now that its a canvas // passing in python to ensure a valid version is used - test('New env: Git initialized', { tag: [tags.CRITICAL] }, async function ({ app, settings, python }) { + test('New env: Git initialized', { tag: [tags.CRITICAL] }, async function ({ app, sessions, settings, python }) { const folderName = addRandomNumSuffix('git-init'); await settings.set({ 'files.exclude': { '**/.git': false, '**/.gitignore': false } }, { waitMs: 1000 }); @@ -50,6 +50,7 @@ test.describe('New Folder Flow: Python Project', { initGitRepo: true, status: 'new', pythonEnv: 'venv', + interpreterPath: (await sessions.getSelectedSessionInfo()).path, createPyprojectToml: true, }); @@ -79,7 +80,7 @@ test.describe('New Folder Flow: Python Project', { }); // passing in python to ensure a valid version is used - test('New env: Venv environment', { tag: [tags.CRITICAL, tags.WIN] }, async function ({ app, python }) { + test('New env: Venv environment', { tag: [tags.CRITICAL, tags.WIN] }, async function ({ app, sessions, python }) { const folderName = addRandomNumSuffix('new-venv'); await createNewFolder(app, { @@ -87,6 +88,7 @@ test.describe('New Folder Flow: Python Project', { folderName, status: 'new', pythonEnv: 'venv', + interpreterPath: (await sessions.getSelectedSessionInfo()).path, createPyprojectToml: false, });