From 7fc3d7b21c98bf3c42e649023a058b46df868aac Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Mon, 19 Sep 2022 15:12:30 -0700 Subject: [PATCH 1/2] Add info which can be used to differentiate Pyenv global installs from Pyenv virtualenvs --- .../pythonEnvironments/base/info/env.ts | 6 +++++ .../pythonEnvironments/base/info/index.ts | 6 +++++ .../base/locators/composite/resolverUtils.ts | 27 ++++++++++++++++++- .../environmentManagers/simplevirtualenvs.ts | 9 +++++++ .../composite/envsResolver.unit.test.ts | 13 +++++++++ .../composite/resolverUtils.unit.test.ts | 6 +++++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/client/pythonEnvironments/base/info/env.ts b/src/client/pythonEnvironments/base/info/env.ts index e65339b78c27..695e8e706c23 100644 --- a/src/client/pythonEnvironments/base/info/env.ts +++ b/src/client/pythonEnvironments/base/info/env.ts @@ -16,6 +16,7 @@ import { PythonEnvInfo, PythonEnvKind, PythonEnvSource, + PythonEnvType, PythonReleaseLevel, PythonVersion, virtualEnvKinds, @@ -40,6 +41,7 @@ export function buildEnvInfo(init?: { display?: string; sysPrefix?: string; searchLocation?: Uri; + type?: PythonEnvType; }): PythonEnvInfo { const env: PythonEnvInfo = { name: init?.name ?? '', @@ -103,6 +105,7 @@ function updateEnv( location?: string; version?: PythonVersion; searchLocation?: Uri; + type?: PythonEnvType; }, ): void { if (updates.kind !== undefined) { @@ -120,6 +123,9 @@ function updateEnv( if (updates.searchLocation !== undefined) { env.searchLocation = updates.searchLocation; } + if (updates.type !== undefined) { + env.type = updates.type; + } } /** diff --git a/src/client/pythonEnvironments/base/info/index.ts b/src/client/pythonEnvironments/base/info/index.ts index 13d0b29a96e8..4ef512c56ed6 100644 --- a/src/client/pythonEnvironments/base/info/index.ts +++ b/src/client/pythonEnvironments/base/info/index.ts @@ -26,6 +26,11 @@ export enum PythonEnvKind { OtherVirtual = 'virt-other', } +export enum PythonEnvType { + Conda = 'Conda', + Virtual = 'Virtual', +} + export interface EnvPathType { /** * Path to environment folder or path to interpreter that uniquely identifies an environment. @@ -105,6 +110,7 @@ export enum PythonEnvSource { type PythonEnvBaseInfo = { id?: string; kind: PythonEnvKind; + type?: PythonEnvType; executable: PythonExecutableInfo; // One of (name, location) must be non-empty. name: string; diff --git a/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts b/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts index c41c52510280..696139d162cd 100644 --- a/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts +++ b/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts @@ -4,7 +4,14 @@ import * as path from 'path'; import { Uri } from 'vscode'; import { uniq } from 'lodash'; -import { PythonEnvInfo, PythonEnvKind, PythonEnvSource, UNKNOWN_PYTHON_VERSION, virtualEnvKinds } from '../../info'; +import { + PythonEnvInfo, + PythonEnvKind, + PythonEnvSource, + PythonEnvType, + UNKNOWN_PYTHON_VERSION, + virtualEnvKinds, +} from '../../info'; import { buildEnvInfo, comparePythonVersionSpecificity, @@ -26,6 +33,7 @@ import { getRegistryInterpreters, getRegistryInterpretersSync } from '../../../c import { BasicEnvInfo } from '../../locator'; import { parseVersionFromExecutable } from '../../info/executable'; import { traceError, traceWarn } from '../../../../logging'; +import { isVirtualEnvironment } from '../../../common/environmentManagers/simplevirtualenvs'; function getResolvers(): Map Promise> { const resolvers = new Map Promise>(); @@ -62,9 +70,26 @@ export async function resolveBasicEnv(env: BasicEnvInfo, useCache = false): Prom const { ctime, mtime } = await getFileInfo(resolvedEnv.executable.filename); resolvedEnv.executable.ctime = ctime; resolvedEnv.executable.mtime = mtime; + const type = await getEnvType(resolvedEnv); + if (type) { + resolvedEnv.type = type; + } return resolvedEnv; } +async function getEnvType(env: PythonEnvInfo) { + if (env.type) { + return env.type; + } + if (await isVirtualEnvironment(env.executable.filename)) { + return PythonEnvType.Virtual; + } + if (await isCondaEnvironment(env.executable.filename)) { + return PythonEnvType.Conda; + } + return undefined; +} + function getSearchLocation(env: PythonEnvInfo): Uri | undefined { const folders = getWorkspaceFolders(); const isRootedEnv = folders.some((f) => isParentPath(env.executable.filename, f) || isParentPath(env.location, f)); diff --git a/src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts b/src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts index 915bc8950a01..80a60a0580ca 100644 --- a/src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts +++ b/src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts @@ -30,6 +30,15 @@ function getPyvenvConfigPathsFrom(interpreterPath: string): string[] { return [venvPath1, venvPath2]; } +/** + * Checks if the given interpreter is a virtual environment. + * @param {string} interpreterPath: Absolute path to the python interpreter. + * @returns {boolean} : Returns true if the interpreter belongs to a venv environment. + */ +export async function isVirtualEnvironment(interpreterPath: string): Promise { + return isVenvEnvironment(interpreterPath); +} + /** * Checks if the given interpreter belongs to a venv based environment. * @param {string} interpreterPath: Absolute path to the python interpreter. diff --git a/src/test/pythonEnvironments/base/locators/composite/envsResolver.unit.test.ts b/src/test/pythonEnvironments/base/locators/composite/envsResolver.unit.test.ts index 158dab04e875..f0c1a7d022f0 100644 --- a/src/test/pythonEnvironments/base/locators/composite/envsResolver.unit.test.ts +++ b/src/test/pythonEnvironments/base/locators/composite/envsResolver.unit.test.ts @@ -13,6 +13,7 @@ import * as platformApis from '../../../../../client/common/utils/platform'; import { PythonEnvInfo, PythonEnvKind, + PythonEnvType, PythonVersion, UNKNOWN_PYTHON_VERSION, } from '../../../../../client/pythonEnvironments/base/info'; @@ -66,6 +67,9 @@ suite('Python envs locator - Environments Resolver', () => { updatedEnv.arch = Architecture.x64; updatedEnv.display = expectedDisplay; updatedEnv.detailedDisplayName = expectedDisplay; + if (env.kind === PythonEnvKind.Conda) { + env.type = PythonEnvType.Conda; + } return updatedEnv; } @@ -76,6 +80,7 @@ suite('Python envs locator - Environments Resolver', () => { name = '', location = '', display: string | undefined = undefined, + type?: PythonEnvType, ): PythonEnvInfo { return { name, @@ -94,6 +99,7 @@ suite('Python envs locator - Environments Resolver', () => { distro: { org: '' }, searchLocation: Uri.file(location), source: [], + type, }; } suite('iterEnvs()', () => { @@ -128,6 +134,7 @@ suite('Python envs locator - Environments Resolver', () => { 'win1', path.join(testVirtualHomeDir, '.venvs', 'win1'), "Python ('win1': venv)", + PythonEnvType.Virtual, ); const envsReturnedByParentLocator = [env1]; const parentLocator = new SimpleLocator(envsReturnedByParentLocator); @@ -151,6 +158,8 @@ suite('Python envs locator - Environments Resolver', () => { undefined, 'win1', path.join(testVirtualHomeDir, '.venvs', 'win1'), + undefined, + PythonEnvType.Virtual, ); const envsReturnedByParentLocator = [env1]; const parentLocator = new SimpleLocator(envsReturnedByParentLocator); @@ -206,6 +215,8 @@ suite('Python envs locator - Environments Resolver', () => { undefined, 'win1', path.join(testVirtualHomeDir, '.venvs', 'win1'), + undefined, + PythonEnvType.Virtual, ); const envsReturnedByParentLocator = [env]; const didUpdate = new EventEmitter | ProgressNotificationEvent>(); @@ -355,6 +366,8 @@ suite('Python envs locator - Environments Resolver', () => { undefined, 'win1', path.join(testVirtualHomeDir, '.venvs', 'win1'), + undefined, + PythonEnvType.Virtual, ); const parentLocator = new SimpleLocator([]); const resolver = new PythonEnvsResolver(parentLocator, envInfoService); diff --git a/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts b/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts index 893f8bed7655..322a4cb8cc91 100644 --- a/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts +++ b/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts @@ -11,6 +11,7 @@ import { PythonEnvInfo, PythonEnvKind, PythonEnvSource, + PythonEnvType, PythonVersion, UNKNOWN_PYTHON_VERSION, } from '../../../../../client/pythonEnvironments/base/info'; @@ -76,6 +77,7 @@ suite('Resolver Utils', () => { }, source: [], org: 'miniconda3', + type: PythonEnvType.Conda, }); envInfo.location = path.join(testPyenvVersionsDir, 'miniconda3-4.7.12'); envInfo.name = 'base'; @@ -209,6 +211,7 @@ suite('Resolver Utils', () => { version: UNKNOWN_PYTHON_VERSION, fileInfo: undefined, name: 'base', + type: PythonEnvType.Conda, }); setEnvDisplayString(info); return info; @@ -237,6 +240,7 @@ suite('Resolver Utils', () => { searchLocation: undefined, source: [], }; + info.type = PythonEnvType.Conda; setEnvDisplayString(info); return info; } @@ -333,6 +337,7 @@ suite('Resolver Utils', () => { distro: { org: '' }, searchLocation: Uri.file(location), source: [], + type: PythonEnvType.Virtual, }; setEnvDisplayString(info); return info; @@ -623,6 +628,7 @@ suite('Resolver Utils', () => { org: 'ContinuumAnalytics', // Provided by registry name: 'conda3', source: [PythonEnvSource.WindowsRegistry], + type: PythonEnvType.Conda, }); setEnvDisplayString(expected); expected.distro.defaultDisplayName = 'Anaconda py38_4.8.3'; From e74daab88bef2738a3886ebc769e2df69cc2c342 Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Mon, 19 Sep 2022 15:49:54 -0700 Subject: [PATCH 2/2] Add type info if known --- .../base/locators/composite/resolverUtils.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts b/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts index 696139d162cd..a8ad85b05540 100644 --- a/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts +++ b/src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts @@ -156,6 +156,7 @@ async function resolveSimpleEnv(env: BasicEnvInfo): Promise { kind, version: await getPythonVersionFromPath(executablePath), executable: executablePath, + type: PythonEnvType.Virtual, }); const location = getEnvironmentDirFromPath(executablePath); envInfo.location = location; @@ -186,6 +187,7 @@ async function resolveCondaEnv(env: BasicEnvInfo, useCache?: boolean): Promise

{