Skip to content

Commit c69eb7a

Browse files
Kartik Rajeleanorjboyd
Kartik Raj
authored andcommitted
Add type info which can be used to differentiate Pyenv global installs from Pyenv virtualenvs (microsoft#19862)
1 parent 66e4b71 commit c69eb7a

File tree

6 files changed

+71
-2
lines changed

6 files changed

+71
-2
lines changed

src/client/pythonEnvironments/base/info/env.ts

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
PythonEnvInfo,
1717
PythonEnvKind,
1818
PythonEnvSource,
19+
PythonEnvType,
1920
PythonReleaseLevel,
2021
PythonVersion,
2122
virtualEnvKinds,
@@ -40,6 +41,7 @@ export function buildEnvInfo(init?: {
4041
display?: string;
4142
sysPrefix?: string;
4243
searchLocation?: Uri;
44+
type?: PythonEnvType;
4345
}): PythonEnvInfo {
4446
const env: PythonEnvInfo = {
4547
name: init?.name ?? '',
@@ -103,6 +105,7 @@ function updateEnv(
103105
location?: string;
104106
version?: PythonVersion;
105107
searchLocation?: Uri;
108+
type?: PythonEnvType;
106109
},
107110
): void {
108111
if (updates.kind !== undefined) {
@@ -120,6 +123,9 @@ function updateEnv(
120123
if (updates.searchLocation !== undefined) {
121124
env.searchLocation = updates.searchLocation;
122125
}
126+
if (updates.type !== undefined) {
127+
env.type = updates.type;
128+
}
123129
}
124130

125131
/**

src/client/pythonEnvironments/base/info/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export enum PythonEnvKind {
2626
OtherVirtual = 'virt-other',
2727
}
2828

29+
export enum PythonEnvType {
30+
Conda = 'Conda',
31+
Virtual = 'Virtual',
32+
}
33+
2934
export interface EnvPathType {
3035
/**
3136
* Path to environment folder or path to interpreter that uniquely identifies an environment.
@@ -105,6 +110,7 @@ export enum PythonEnvSource {
105110
type PythonEnvBaseInfo = {
106111
id?: string;
107112
kind: PythonEnvKind;
113+
type?: PythonEnvType;
108114
executable: PythonExecutableInfo;
109115
// One of (name, location) must be non-empty.
110116
name: string;

src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts

+31-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
import * as path from 'path';
55
import { Uri } from 'vscode';
66
import { uniq } from 'lodash';
7-
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource, UNKNOWN_PYTHON_VERSION, virtualEnvKinds } from '../../info';
7+
import {
8+
PythonEnvInfo,
9+
PythonEnvKind,
10+
PythonEnvSource,
11+
PythonEnvType,
12+
UNKNOWN_PYTHON_VERSION,
13+
virtualEnvKinds,
14+
} from '../../info';
815
import {
916
buildEnvInfo,
1017
comparePythonVersionSpecificity,
@@ -26,6 +33,7 @@ import { getRegistryInterpreters, getRegistryInterpretersSync } from '../../../c
2633
import { BasicEnvInfo } from '../../locator';
2734
import { parseVersionFromExecutable } from '../../info/executable';
2835
import { traceError, traceWarn } from '../../../../logging';
36+
import { isVirtualEnvironment } from '../../../common/environmentManagers/simplevirtualenvs';
2937

3038
function getResolvers(): Map<PythonEnvKind, (env: BasicEnvInfo, useCache?: boolean) => Promise<PythonEnvInfo>> {
3139
const resolvers = new Map<PythonEnvKind, (_: BasicEnvInfo, useCache?: boolean) => Promise<PythonEnvInfo>>();
@@ -62,9 +70,26 @@ export async function resolveBasicEnv(env: BasicEnvInfo, useCache = false): Prom
6270
const { ctime, mtime } = await getFileInfo(resolvedEnv.executable.filename);
6371
resolvedEnv.executable.ctime = ctime;
6472
resolvedEnv.executable.mtime = mtime;
73+
const type = await getEnvType(resolvedEnv);
74+
if (type) {
75+
resolvedEnv.type = type;
76+
}
6577
return resolvedEnv;
6678
}
6779

80+
async function getEnvType(env: PythonEnvInfo) {
81+
if (env.type) {
82+
return env.type;
83+
}
84+
if (await isVirtualEnvironment(env.executable.filename)) {
85+
return PythonEnvType.Virtual;
86+
}
87+
if (await isCondaEnvironment(env.executable.filename)) {
88+
return PythonEnvType.Conda;
89+
}
90+
return undefined;
91+
}
92+
6893
function getSearchLocation(env: PythonEnvInfo): Uri | undefined {
6994
const folders = getWorkspaceFolders();
7095
const isRootedEnv = folders.some((f) => isParentPath(env.executable.filename, f) || isParentPath(env.location, f));
@@ -131,6 +156,7 @@ async function resolveSimpleEnv(env: BasicEnvInfo): Promise<PythonEnvInfo> {
131156
kind,
132157
version: await getPythonVersionFromPath(executablePath),
133158
executable: executablePath,
159+
type: PythonEnvType.Virtual,
134160
});
135161
const location = getEnvironmentDirFromPath(executablePath);
136162
envInfo.location = location;
@@ -161,6 +187,7 @@ async function resolveCondaEnv(env: BasicEnvInfo, useCache?: boolean): Promise<P
161187
location: prefix,
162188
source: [],
163189
version: executable ? await getPythonVersionFromPath(executable) : undefined,
190+
type: PythonEnvType.Conda,
164191
});
165192
if (name) {
166193
info.name = name;
@@ -175,7 +202,9 @@ async function resolveCondaEnv(env: BasicEnvInfo, useCache?: boolean): Promise<P
175202
);
176203
// Environment could still be valid, resolve as a simple env.
177204
env.kind = PythonEnvKind.Unknown;
178-
return resolveSimpleEnv(env);
205+
const envInfo = await resolveSimpleEnv(env);
206+
envInfo.type = PythonEnvType.Conda;
207+
return envInfo;
179208
}
180209

181210
async function resolvePyenvEnv(env: BasicEnvInfo): Promise<PythonEnvInfo> {

src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts

+9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ function getPyvenvConfigPathsFrom(interpreterPath: string): string[] {
3030
return [venvPath1, venvPath2];
3131
}
3232

33+
/**
34+
* Checks if the given interpreter is a virtual environment.
35+
* @param {string} interpreterPath: Absolute path to the python interpreter.
36+
* @returns {boolean} : Returns true if the interpreter belongs to a venv environment.
37+
*/
38+
export async function isVirtualEnvironment(interpreterPath: string): Promise<boolean> {
39+
return isVenvEnvironment(interpreterPath);
40+
}
41+
3342
/**
3443
* Checks if the given interpreter belongs to a venv based environment.
3544
* @param {string} interpreterPath: Absolute path to the python interpreter.

src/test/pythonEnvironments/base/locators/composite/envsResolver.unit.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as platformApis from '../../../../../client/common/utils/platform';
1313
import {
1414
PythonEnvInfo,
1515
PythonEnvKind,
16+
PythonEnvType,
1617
PythonVersion,
1718
UNKNOWN_PYTHON_VERSION,
1819
} from '../../../../../client/pythonEnvironments/base/info';
@@ -66,6 +67,9 @@ suite('Python envs locator - Environments Resolver', () => {
6667
updatedEnv.arch = Architecture.x64;
6768
updatedEnv.display = expectedDisplay;
6869
updatedEnv.detailedDisplayName = expectedDisplay;
70+
if (env.kind === PythonEnvKind.Conda) {
71+
env.type = PythonEnvType.Conda;
72+
}
6973
return updatedEnv;
7074
}
7175

@@ -76,6 +80,7 @@ suite('Python envs locator - Environments Resolver', () => {
7680
name = '',
7781
location = '',
7882
display: string | undefined = undefined,
83+
type?: PythonEnvType,
7984
): PythonEnvInfo {
8085
return {
8186
name,
@@ -94,6 +99,7 @@ suite('Python envs locator - Environments Resolver', () => {
9499
distro: { org: '' },
95100
searchLocation: Uri.file(location),
96101
source: [],
102+
type,
97103
};
98104
}
99105
suite('iterEnvs()', () => {
@@ -128,6 +134,7 @@ suite('Python envs locator - Environments Resolver', () => {
128134
'win1',
129135
path.join(testVirtualHomeDir, '.venvs', 'win1'),
130136
"Python ('win1': venv)",
137+
PythonEnvType.Virtual,
131138
);
132139
const envsReturnedByParentLocator = [env1];
133140
const parentLocator = new SimpleLocator<BasicEnvInfo>(envsReturnedByParentLocator);
@@ -151,6 +158,8 @@ suite('Python envs locator - Environments Resolver', () => {
151158
undefined,
152159
'win1',
153160
path.join(testVirtualHomeDir, '.venvs', 'win1'),
161+
undefined,
162+
PythonEnvType.Virtual,
154163
);
155164
const envsReturnedByParentLocator = [env1];
156165
const parentLocator = new SimpleLocator<BasicEnvInfo>(envsReturnedByParentLocator);
@@ -206,6 +215,8 @@ suite('Python envs locator - Environments Resolver', () => {
206215
undefined,
207216
'win1',
208217
path.join(testVirtualHomeDir, '.venvs', 'win1'),
218+
undefined,
219+
PythonEnvType.Virtual,
209220
);
210221
const envsReturnedByParentLocator = [env];
211222
const didUpdate = new EventEmitter<PythonEnvUpdatedEvent<BasicEnvInfo> | ProgressNotificationEvent>();
@@ -355,6 +366,8 @@ suite('Python envs locator - Environments Resolver', () => {
355366
undefined,
356367
'win1',
357368
path.join(testVirtualHomeDir, '.venvs', 'win1'),
369+
undefined,
370+
PythonEnvType.Virtual,
358371
);
359372
const parentLocator = new SimpleLocator([]);
360373
const resolver = new PythonEnvsResolver(parentLocator, envInfoService);

src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
PythonEnvInfo,
1212
PythonEnvKind,
1313
PythonEnvSource,
14+
PythonEnvType,
1415
PythonVersion,
1516
UNKNOWN_PYTHON_VERSION,
1617
} from '../../../../../client/pythonEnvironments/base/info';
@@ -76,6 +77,7 @@ suite('Resolver Utils', () => {
7677
},
7778
source: [],
7879
org: 'miniconda3',
80+
type: PythonEnvType.Conda,
7981
});
8082
envInfo.location = path.join(testPyenvVersionsDir, 'miniconda3-4.7.12');
8183
envInfo.name = 'base';
@@ -209,6 +211,7 @@ suite('Resolver Utils', () => {
209211
version: UNKNOWN_PYTHON_VERSION,
210212
fileInfo: undefined,
211213
name: 'base',
214+
type: PythonEnvType.Conda,
212215
});
213216
setEnvDisplayString(info);
214217
return info;
@@ -237,6 +240,7 @@ suite('Resolver Utils', () => {
237240
searchLocation: undefined,
238241
source: [],
239242
};
243+
info.type = PythonEnvType.Conda;
240244
setEnvDisplayString(info);
241245
return info;
242246
}
@@ -333,6 +337,7 @@ suite('Resolver Utils', () => {
333337
distro: { org: '' },
334338
searchLocation: Uri.file(location),
335339
source: [],
340+
type: PythonEnvType.Virtual,
336341
};
337342
setEnvDisplayString(info);
338343
return info;
@@ -623,6 +628,7 @@ suite('Resolver Utils', () => {
623628
org: 'ContinuumAnalytics', // Provided by registry
624629
name: 'conda3',
625630
source: [PythonEnvSource.WindowsRegistry],
631+
type: PythonEnvType.Conda,
626632
});
627633
setEnvDisplayString(expected);
628634
expected.distro.defaultDisplayName = 'Anaconda py38_4.8.3';

0 commit comments

Comments
 (0)