diff --git a/src/client/interpreter/display/index.ts b/src/client/interpreter/display/index.ts index ff5abaddd331..1c19a75f2e70 100644 --- a/src/client/interpreter/display/index.ts +++ b/src/client/interpreter/display/index.ts @@ -67,7 +67,7 @@ export class InterpreterDisplay implements IInterpreterDisplay { await Promise.all([ this.fileSystem.fileExistsAsync(pythonPath), this.versionProvider.getVersion(pythonPath, defaultDisplayName), - this.getVirtualEnvironmentName(pythonPath) + this.getVirtualEnvironmentName(pythonPath).catch(() => '') ]) .then(([interpreterExists, displayName, virtualEnvName]) => { const dislayNameSuffix = virtualEnvName.length > 0 ? ` (${virtualEnvName})` : ''; diff --git a/src/client/interpreter/interpreterService.ts b/src/client/interpreter/interpreterService.ts index 361689fcc635..84fa7f8cdb57 100644 --- a/src/client/interpreter/interpreterService.ts +++ b/src/client/interpreter/interpreterService.ts @@ -3,7 +3,6 @@ import * as path from 'path'; import { ConfigurationTarget, Disposable, Event, EventEmitter, Uri } from 'vscode'; import { IDocumentManager, IWorkspaceService } from '../common/application/types'; import { PythonSettings } from '../common/configSettings'; -import { IFileSystem } from '../common/platform/types'; import { IPythonExecutionFactory } from '../common/process/types'; import { IConfigurationService, IDisposableRegistry } from '../common/types'; import * as utils from '../common/utils'; @@ -21,13 +20,11 @@ export class InterpreterService implements Disposable, IInterpreterService { private readonly locator: IInterpreterLocatorService; private readonly pythonPathUpdaterService: IPythonPathUpdaterServiceManager; private readonly helper: IInterpreterHelper; - private readonly fs: IFileSystem; private readonly didChangeInterpreterEmitter = new EventEmitter(); constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.locator = serviceContainer.get(IInterpreterLocatorService, INTERPRETER_LOCATOR_SERVICE); this.helper = serviceContainer.get(IInterpreterHelper); - this.fs = this.serviceContainer.get(IFileSystem); this.pythonPathUpdaterService = this.serviceContainer.get(IPythonPathUpdaterServiceManager); } @@ -134,21 +131,14 @@ export class InterpreterService implements Disposable, IInterpreterService { return false; } if (activeWorkspace.configTarget === ConfigurationTarget.Workspace) { - return !await this.isPythonPathDefined(pythonPathInConfig!.workspaceValue); + return pythonPathInConfig!.workspaceValue === undefined || pythonPathInConfig!.workspaceValue === 'python'; } if (activeWorkspace.configTarget === ConfigurationTarget.WorkspaceFolder) { - return !await this.isPythonPathDefined(pythonPathInConfig!.workspaceFolderValue); + return pythonPathInConfig!.workspaceFolderValue === undefined || pythonPathInConfig!.workspaceFolderValue === 'python'; } return false; } - private async isPythonPathDefined(pythonPath: string | undefined): Promise { - if (pythonPath === undefined || pythonPath === 'python') { - return false; - } - return await this.fs.directoryExistsAsync(pythonPath); - } - private onConfigChanged = () => { this.didChangeInterpreterEmitter.fire(); const interpreterDisplay = this.serviceContainer.get(IInterpreterDisplay); diff --git a/src/client/interpreter/locators/services/pipEnvService.ts b/src/client/interpreter/locators/services/pipEnvService.ts index dea1f040404b..f511dede8302 100644 --- a/src/client/interpreter/locators/services/pipEnvService.ts +++ b/src/client/interpreter/locators/services/pipEnvService.ts @@ -5,72 +5,40 @@ import { inject, injectable } from 'inversify'; import * as path from 'path'; import { Uri } from 'vscode'; import { IApplicationShell, IWorkspaceService } from '../../../common/application/types'; -import { createDeferred, Deferred } from '../../../common/helpers'; import { IFileSystem } from '../../../common/platform/types'; import { IProcessService } from '../../../common/process/types'; import { getPythonExecutable } from '../../../debugger/Common/Utils'; import { IServiceContainer } from '../../../ioc/types'; -import { IInterpreterLocatorService, IInterpreterVersionService, InterpreterType, PythonInterpreter } from '../../contracts'; +import { IInterpreterVersionService, InterpreterType, PythonInterpreter } from '../../contracts'; +import { CacheableLocatorService } from './cacheableLocatorService'; const execName = 'pipenv'; -const CACHE_TIMEOUT = 2000; @injectable() -export class PipEnvService implements IInterpreterLocatorService { +export class PipEnvService extends CacheableLocatorService { private readonly versionService: IInterpreterVersionService; private readonly process: IProcessService; private readonly workspace: IWorkspaceService; private readonly fs: IFileSystem; - private pendingPromises: Deferred[] = []; - private readonly cachedInterpreters = new Map(); - - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { + constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { + super('PipEnvService', serviceContainer); this.versionService = this.serviceContainer.get(IInterpreterVersionService); this.process = this.serviceContainer.get(IProcessService); this.workspace = this.serviceContainer.get(IWorkspaceService); this.fs = this.serviceContainer.get(IFileSystem); } - - public getInterpreters(resource?: Uri): Promise { + // tslint:disable-next-line:no-empty + public dispose() { } + protected getInterpretersImplementation(resource?: Uri): Promise { const pipenvCwd = this.getPipenvWorkingDirectory(resource); if (!pipenvCwd) { return Promise.resolve([]); } - // Try cache first - const interpreter = this.cachedInterpreters[pipenvCwd]; - if (interpreter) { - return Promise.resolve([interpreter]); - } - // We don't want multiple requests executing pipenv - const deferred = createDeferred(); - this.pendingPromises.push(deferred); - if (this.pendingPromises.length === 1) { - // First call, start worker - this.getInterpreter(pipenvCwd) - .then(x => this.resolveDeferred(x ? [x] : [])) - .catch(e => this.resolveDeferred([])); - } - return deferred.promise; - } - - public dispose() { - this.resolveDeferred([]); - } - - private resolveDeferred(result: PythonInterpreter[]) { - this.pendingPromises.forEach(p => p.resolve(result)); - this.pendingPromises = []; - } - - private async getInterpreter(pipenvCwd: string): Promise { - const interpreter = await this.getInterpreterFromPipenv(pipenvCwd); - if (interpreter) { - this.cachedInterpreters[pipenvCwd] = interpreter; - setTimeout(() => this.cachedInterpreters.clear(), CACHE_TIMEOUT); - } - return interpreter; + return this.getInterpreterFromPipenv(pipenvCwd) + .then(item => item ? [item] : []) + .catch(() => []); } private async getInterpreterFromPipenv(pipenvCwd: string): Promise { @@ -78,6 +46,7 @@ export class PipEnvService implements IInterpreterLocatorService { if (!interpreterPath) { return; } + const pythonExecutablePath = getPythonExecutable(interpreterPath); const ver = await this.versionService.getVersion(pythonExecutablePath, ''); return {