Skip to content

Commit efc2878

Browse files
authored
Use python folder name as name of virtual env (microsoft#2564)
1 parent c03b20b commit efc2878

File tree

4 files changed

+48
-66
lines changed

4 files changed

+48
-66
lines changed

news/2 Fixes/2562.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use folder name of the Python interpreter as the name of the virtual environment.

src/client/interpreter/interpreterService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export class InterpreterService implements Disposable, IInterpreterService {
172172
* @memberof InterpreterService
173173
*/
174174
public async getDisplayName(info: Partial<PythonInterpreter>, resource?: Uri): Promise<string> {
175-
const store = this.persistentStateFactory.createGlobalPersistentState<string>(`${info.path}.interpreter.displayName.v1`, undefined, EXPITY_DURATION);
175+
const store = this.persistentStateFactory.createGlobalPersistentState<string>(`${info.path}.interpreter.displayName.v2`, undefined, EXPITY_DURATION);
176176
if (store.value) {
177177
return store.value;
178178
}

src/client/interpreter/virtualEnvs/index.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,7 @@ export class VirtualEnvironmentManager implements IVirtualEnvironmentManager {
3636
return path.basename(workspaceUri.fsPath);
3737
}
3838

39-
// https://stackoverflow.com/questions/1871549/determine-if-python-is-running-inside-virtualenv
40-
// hasattr(sys, 'real_prefix') works for virtualenv while
41-
// '(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))' works for venv
42-
try {
43-
const processService = await this.processServiceFactory.create();
44-
const code = 'import sys\nif hasattr(sys, "real_prefix"):\n print("virtualenv")\nelif hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix:\n print("venv")';
45-
const output = await processService.exec(pythonPath, ['-c', code]);
46-
const envName = output.stdout.trim();
47-
if (envName.length === 0) {
48-
return '';
49-
}
50-
return envName.toUpperCase() === 'VIRTUALENV' ? grandParentDirName : envName;
51-
} catch {
52-
// do nothing.
53-
}
54-
return '';
39+
return grandParentDirName;
5540
}
5641
public async getEnvironmentType(pythonPath: string, resource?: Uri): Promise<InterpreterType> {
5742
const dir = path.dirname(pythonPath);

src/test/interpreters/virtualEnvManager.unit.test.ts

Lines changed: 45 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,78 @@
44
// tslint:disable:no-any
55

66
import { expect } from 'chai';
7-
import { Container } from 'inversify';
87
import * as path from 'path';
98
import * as TypeMoq from 'typemoq';
109
import { Uri, WorkspaceFolder } from 'vscode';
1110
import { IWorkspaceService } from '../../client/common/application/types';
12-
import { FileSystem } from '../../client/common/platform/fileSystem';
13-
import { PlatformService } from '../../client/common/platform/platformService';
14-
import { IFileSystem, IPlatformService } from '../../client/common/platform/types';
15-
import { BufferDecoder } from '../../client/common/process/decoder';
16-
import { ProcessService } from '../../client/common/process/proc';
17-
import { IBufferDecoder, IProcessService, IProcessServiceFactory } from '../../client/common/process/types';
11+
import { IFileSystem } from '../../client/common/platform/types';
12+
import { IProcessServiceFactory } from '../../client/common/process/types';
1813
import { IPipEnvService } from '../../client/interpreter/contracts';
1914
import { VirtualEnvironmentManager } from '../../client/interpreter/virtualEnvs';
20-
import { ServiceContainer } from '../../client/ioc/container';
21-
import { ServiceManager } from '../../client/ioc/serviceManager';
15+
import { IServiceContainer } from '../../client/ioc/types';
2216

2317
suite('Virtual environment manager', () => {
24-
let serviceManager: ServiceManager;
25-
let serviceContainer: ServiceContainer;
2618
const virtualEnvFolderName = 'virtual Env Folder Name';
2719
const pythonPath = path.join('a', 'b', virtualEnvFolderName, 'd', 'python');
28-
setup(async () => {
29-
const cont = new Container();
30-
serviceManager = new ServiceManager(cont);
31-
serviceContainer = new ServiceContainer(cont);
32-
});
3320

34-
test('Plain Python environment suffix', async () => testSuffix('', ''));
35-
test('Plain Python environment suffix with workspace Uri', async () => testSuffix('', '', false, Uri.file(path.join('1', '2', '3', '4'))));
36-
test('Plain Python environment suffix with PipEnv', async () => testSuffix('', 'workspaceName', true, Uri.file(path.join('1', '2', '3', 'workspaceName'))));
37-
test('Venv environment suffix', async () => testSuffix('venv', 'venv'));
38-
test('Virtualenv Python environment suffix', async () => testSuffix('virtualenv', virtualEnvFolderName));
21+
test('Plain Python environment suffix', async () => testSuffix(virtualEnvFolderName));
22+
test('Plain Python environment suffix with workspace Uri', async () => testSuffix(virtualEnvFolderName, false, Uri.file(path.join('1', '2', '3', '4'))));
23+
test('Plain Python environment suffix with PipEnv', async () => testSuffix('workspaceName', true, Uri.file(path.join('1', '2', '3', 'workspaceName'))));
3924

40-
test('Run actual virtual env detection code', async () => {
41-
const processServiceFactory = TypeMoq.Mock.ofType<IProcessServiceFactory>();
42-
processServiceFactory.setup(f => f.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(new ProcessService(new BufferDecoder(), process.env as any)));
43-
serviceManager.addSingletonInstance<IProcessServiceFactory>(IProcessServiceFactory, processServiceFactory.object);
44-
serviceManager.addSingleton<IBufferDecoder>(IBufferDecoder, BufferDecoder);
45-
serviceManager.addSingleton<IFileSystem>(IFileSystem, FileSystem);
46-
serviceManager.addSingleton<IPlatformService>(IPlatformService, PlatformService);
47-
serviceManager.addSingletonInstance<IPipEnvService>(IPipEnvService, TypeMoq.Mock.ofType<IPipEnvService>().object);
25+
test('Use environment folder as env name', async () => {
26+
const serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
27+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IPipEnvService))).returns(() => TypeMoq.Mock.ofType<IPipEnvService>().object);
4828
const workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>();
4929
workspaceService.setup(w => w.hasWorkspaceFolders).returns(() => false);
50-
serviceManager.addSingletonInstance<IWorkspaceService>(IWorkspaceService, workspaceService.object);
51-
const venvManager = new VirtualEnvironmentManager(serviceContainer);
30+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IWorkspaceService))).returns(() => workspaceService.object);
31+
32+
const venvManager = new VirtualEnvironmentManager(serviceContainer.object);
33+
const name = await venvManager.getEnvironmentName(pythonPath);
34+
35+
expect(name).to.be.equal(virtualEnvFolderName);
36+
});
37+
38+
test('Use workspacec name as env name', async () => {
39+
const serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
40+
const pipEnvService = TypeMoq.Mock.ofType<IPipEnvService>();
41+
pipEnvService
42+
.setup(p => p.isRelatedPipEnvironment(TypeMoq.It.isAny(), TypeMoq.It.isValue(pythonPath)))
43+
.returns(() => Promise.resolve(true))
44+
.verifiable(TypeMoq.Times.once());
45+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IProcessServiceFactory))).returns(() => TypeMoq.Mock.ofType<IProcessServiceFactory>().object);
46+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IPipEnvService))).returns(() => pipEnvService.object);
47+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IFileSystem))).returns(() => TypeMoq.Mock.ofType<IFileSystem>().object);
48+
const workspaceUri = Uri.file(path.join('root', 'sub', 'wkspace folder'));
49+
const workspaceFolder: WorkspaceFolder = { name: 'wkspace folder', index: 0, uri: workspaceUri };
50+
const workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>();
51+
workspaceService.setup(w => w.hasWorkspaceFolders).returns(() => true);
52+
workspaceService.setup(w => w.workspaceFolders).returns(() => [workspaceFolder]);
53+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IWorkspaceService))).returns(() => workspaceService.object);
54+
55+
const venvManager = new VirtualEnvironmentManager(serviceContainer.object);
5256
const name = await venvManager.getEnvironmentName(pythonPath);
53-
const result = name === '' || name === 'venv' || name === 'virtualenv';
54-
expect(result).to.be.equal(true, 'Running venv detection code failed.');
57+
58+
expect(name).to.be.equal(path.basename(workspaceUri.fsPath));
59+
pipEnvService.verifyAll();
5560
});
5661

57-
async function testSuffix(virtualEnvProcOutput: string, expectedEnvName: string, isPipEnvironment: boolean = false, resource?: Uri) {
58-
const processService = TypeMoq.Mock.ofType<IProcessService>();
59-
const processServiceFactory = TypeMoq.Mock.ofType<IProcessServiceFactory>();
60-
processService.setup((x: any) => x.then).returns(() => undefined);
61-
processServiceFactory.setup(f => f.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(processService.object));
62-
serviceManager.addSingletonInstance<IProcessServiceFactory>(IProcessServiceFactory, processServiceFactory.object);
63-
serviceManager.addSingletonInstance<IFileSystem>(IFileSystem, TypeMoq.Mock.ofType<IFileSystem>().object);
62+
async function testSuffix(expectedEnvName: string, isPipEnvironment: boolean = false, resource?: Uri) {
63+
const serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
64+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IProcessServiceFactory))).returns(() => TypeMoq.Mock.ofType<IProcessServiceFactory>().object);
65+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IFileSystem))).returns(() => TypeMoq.Mock.ofType<IFileSystem>().object);
6466
const pipEnvService = TypeMoq.Mock.ofType<IPipEnvService>();
6567
pipEnvService.setup(w => w.isRelatedPipEnvironment(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(isPipEnvironment));
66-
serviceManager.addSingletonInstance<IPipEnvService>(IPipEnvService, pipEnvService.object);
68+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IPipEnvService))).returns(() => pipEnvService.object);
6769
const workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>();
6870
workspaceService.setup(w => w.hasWorkspaceFolders).returns(() => false);
6971
if (resource) {
7072
const workspaceFolder = TypeMoq.Mock.ofType<WorkspaceFolder>();
7173
workspaceFolder.setup(w => w.uri).returns(() => resource);
7274
workspaceService.setup(w => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => workspaceFolder.object);
7375
}
74-
serviceManager.addSingletonInstance<IWorkspaceService>(IWorkspaceService, workspaceService.object);
76+
serviceContainer.setup(s => s.get(TypeMoq.It.isValue(IWorkspaceService))).returns(() => workspaceService.object);
7577

76-
const venvManager = new VirtualEnvironmentManager(serviceContainer);
77-
processService
78-
.setup(x => x.exec(pythonPath, TypeMoq.It.isAny()))
79-
.returns(() => Promise.resolve({
80-
stdout: virtualEnvProcOutput,
81-
stderr: ''
82-
}));
78+
const venvManager = new VirtualEnvironmentManager(serviceContainer.object);
8379

8480
const name = await venvManager.getEnvironmentName(pythonPath, resource);
8581
expect(name).to.be.equal(expectedEnvName, 'Virtual envrironment name suffix is incorrect.');

0 commit comments

Comments
 (0)