From 0b818f8ca62c1ae90db6d911d4a8916111d65eef Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 21 Feb 2020 08:55:42 -0800 Subject: [PATCH 1/5] Fix to return env variables of interpreter that is not current interpreter (#10251) For #10250 * Bug fix --- CHANGELOG.md | 2 + news/2 Fixes/10250.md | 1 + package.json | 2 +- src/client/common/logger.ts | 6 +- src/client/interpreter/activation/service.ts | 56 ++++++++-- .../activation/service.unit.test.ts | 103 ++++++++++++++---- 6 files changed, 140 insertions(+), 30 deletions(-) create mode 100644 news/2 Fixes/10250.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 139b22a79769..ef23add58bc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 2020.2.2 (20 February 2020) + ## 2020.2.2 (19 February 2020) ### Fixes diff --git a/news/2 Fixes/10250.md b/news/2 Fixes/10250.md new file mode 100644 index 000000000000..e3ed4fd36c48 --- /dev/null +++ b/news/2 Fixes/10250.md @@ -0,0 +1 @@ +Ensure to correctly return env variables of the activated interpreter, when dealing with non-workspace interpreters. diff --git a/package.json b/package.json index 8e11ca5be90e..8768b25f01b0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "python", "displayName": "Python", "description": "Linting, Debugging (multi-threaded, remote), Intellisense, Jupyter Notebooks, code formatting, refactoring, unit tests, snippets, and more.", - "version": "2020.2.2", + "version": "2020.2.3", "languageServerVersion": "0.5.30", "publisher": "ms-python", "author": { diff --git a/src/client/common/logger.ts b/src/client/common/logger.ts index 3c75f1abf0a2..89c048af58d7 100644 --- a/src/client/common/logger.ts +++ b/src/client/common/logger.ts @@ -285,7 +285,11 @@ function trace(message: string, options: LogOptions = LogOptions.None, logLevel? // tslint:disable-next-line:no-any function writeToLog(elapsedTime: number, returnValue?: any, ex?: Error) { const messagesToLog = [message]; - messagesToLog.push(`Class name = ${className}, completed in ${elapsedTime}ms`); + messagesToLog.push( + `Class name = ${className}, completed in ${elapsedTime}ms, has a ${ + returnValue ? 'truthy' : 'falsy' + } return value` + ); if ((options && LogOptions.Arguments) === LogOptions.Arguments) { messagesToLog.push(argsToLogString(args)); } diff --git a/src/client/interpreter/activation/service.ts b/src/client/interpreter/activation/service.ts index 8311f329c6cf..96c684065977 100644 --- a/src/client/interpreter/activation/service.ts +++ b/src/client/interpreter/activation/service.ts @@ -6,19 +6,24 @@ import '../../common/extensions'; import { inject, injectable } from 'inversify'; import * as path from 'path'; +import { IWorkspaceService } from '../../common/application/types'; import { PYTHON_WARNINGS } from '../../common/constants'; import { LogOptions, traceDecorators, traceError, traceVerbose } from '../../common/logger'; import { IPlatformService } from '../../common/platform/types'; import { IProcessServiceFactory } from '../../common/process/types'; import { ITerminalHelper, TerminalShellType } from '../../common/terminal/types'; import { ICurrentProcess, IDisposable, Resource } from '../../common/types'; +<<<<<<< HEAD import { cacheResourceSpecificInterpreterData, clearCachedResourceSpecificIngterpreterData } from '../../common/utils/decorators'; +======= +import { InMemoryCache } from '../../common/utils/cacheUtils'; +>>>>>>> ae86ae46f... Fix to return env variables of interpreter that is not current interpreter (#10251) import { OSType } from '../../common/utils/platform'; import { IEnvironmentVariablesProvider } from '../../common/variables/types'; import { EXTENSION_ROOT_DIR } from '../../constants'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; -import { PythonInterpreter } from '../contracts'; +import { IInterpreterService, PythonInterpreter } from '../contracts'; import { IEnvironmentActivationService } from './types'; const getEnvironmentPrefix = 'e8b39361-0157-4923-80e1-22d70d46dee6'; @@ -36,14 +41,27 @@ const defaultShells = { @injectable() export class EnvironmentActivationService implements IEnvironmentActivationService, IDisposable { private readonly disposables: IDisposable[] = []; + private readonly activatedEnvVariablesCache = new Map>(); constructor( @inject(ITerminalHelper) private readonly helper: ITerminalHelper, @inject(IPlatformService) private readonly platform: IPlatformService, @inject(IProcessServiceFactory) private processServiceFactory: IProcessServiceFactory, @inject(ICurrentProcess) private currentProcess: ICurrentProcess, + @inject(IWorkspaceService) private workspace: IWorkspaceService, + @inject(IInterpreterService) private interpreterService: IInterpreterService, @inject(IEnvironmentVariablesProvider) private readonly envVarsService: IEnvironmentVariablesProvider ) { - this.envVarsService.onDidEnvironmentVariablesChange(this.onDidEnvironmentVariablesChange, this, this.disposables); + this.envVarsService.onDidEnvironmentVariablesChange( + () => this.activatedEnvVariablesCache.clear(), + this, + this.disposables + ); + + this.interpreterService.onDidChangeInterpreter( + () => this.activatedEnvVariablesCache.clear(), + this, + this.disposables + ); } public dispose(): void { @@ -51,8 +69,34 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi } @traceDecorators.verbose('getActivatedEnvironmentVariables', LogOptions.Arguments) @captureTelemetry(EventName.PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES, { failed: false }, true) - @cacheResourceSpecificInterpreterData('ActivatedEnvironmentVariables', cacheDuration) - public async getActivatedEnvironmentVariables(resource: Resource, interpreter?: PythonInterpreter, allowExceptions?: boolean): Promise { + public async getActivatedEnvironmentVariables( + resource: Resource, + interpreter?: PythonInterpreter, + allowExceptions?: boolean + ): Promise { + // Cache key = resource + interpreter. + const workspaceKey = this.workspace.getWorkspaceFolderIdentifier(resource); + const interpreterPath = this.platform.isWindows ? interpreter?.path.toLowerCase() : interpreter?.path; + const cacheKey = `${workspaceKey}_${interpreterPath}`; + + if (this.activatedEnvVariablesCache.get(cacheKey)?.hasData) { + return this.activatedEnvVariablesCache.get(cacheKey)!.data; + } + + // Cache only if successful, else keep trying & failing if necessary. + const cache = new InMemoryCache(cacheDuration, ''); + return this.getActivatedEnvironmentVariablesImpl(resource, interpreter, allowExceptions).then(vars => { + cache.data = vars; + this.activatedEnvVariablesCache.set(cacheKey, cache); + return vars; + }); + } + + public async getActivatedEnvironmentVariablesImpl( + resource: Resource, + interpreter?: PythonInterpreter, + allowExceptions?: boolean + ): Promise { const shellInfo = defaultShells[this.platform.osType]; if (!shellInfo) { return; @@ -115,9 +159,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi } } } - protected onDidEnvironmentVariablesChange(affectedResource: Resource) { - clearCachedResourceSpecificIngterpreterData('ActivatedEnvironmentVariables', affectedResource); - } + protected fixActivationCommands(commands: string[]): string[] { // Replace 'source ' with '. ' as that works in shell exec return commands.map(cmd => cmd.replace(/^source\s+/, '. ')); diff --git a/src/test/interpreters/activation/service.unit.test.ts b/src/test/interpreters/activation/service.unit.test.ts index d01db1f13565..41ca137097c0 100644 --- a/src/test/interpreters/activation/service.unit.test.ts +++ b/src/test/interpreters/activation/service.unit.test.ts @@ -7,8 +7,9 @@ import { EOL } from 'os'; import * as path from 'path'; import { SemVer } from 'semver'; import { anything, capture, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { EventEmitter, Uri, workspace as workspaceType, WorkspaceConfiguration } from 'vscode'; +import { EventEmitter, Uri } from 'vscode'; +import { IWorkspaceService } from '../../../client/common/application/types'; +import { WorkspaceService } from '../../../client/common/application/workspace'; import { PlatformService } from '../../../client/common/platform/platformService'; import { IPlatformService } from '../../../client/common/platform/types'; import { CurrentProcess } from '../../../client/common/process/currentProcess'; @@ -18,15 +19,14 @@ import { IProcessService, IProcessServiceFactory } from '../../../client/common/ import { TerminalHelper } from '../../../client/common/terminal/helper'; import { ITerminalHelper } from '../../../client/common/terminal/types'; import { ICurrentProcess } from '../../../client/common/types'; -import { clearCache } from '../../../client/common/utils/cacheUtils'; import { getNamesAndValues } from '../../../client/common/utils/enum'; import { Architecture, OSType } from '../../../client/common/utils/platform'; import { EnvironmentVariablesProvider } from '../../../client/common/variables/environmentVariablesProvider'; import { IEnvironmentVariablesProvider } from '../../../client/common/variables/types'; import { EXTENSION_ROOT_DIR } from '../../../client/constants'; import { EnvironmentActivationService } from '../../../client/interpreter/activation/service'; -import { InterpreterType, PythonInterpreter } from '../../../client/interpreter/contracts'; -import { mockedVSCodeNamespaces } from '../../vscode-mock'; +import { IInterpreterService, InterpreterType, PythonInterpreter } from '../../../client/interpreter/contracts'; +import { InterpreterService } from '../../../client/interpreter/interpreterService'; const getEnvironmentPrefix = 'e8b39361-0157-4923-80e1-22d70d46dee6'; const defaultShells = { @@ -45,8 +45,10 @@ suite('Interpreters Activation - Python Environment Variables', () => { let processService: IProcessService; let currentProcess: ICurrentProcess; let envVarsService: IEnvironmentVariablesProvider; - let workspace: typemoq.IMock; - + let workspace: IWorkspaceService; + let interpreterService: IInterpreterService; + let onDidChangeEnvVariables: EventEmitter; + let onDidChangeInterpreter: EventEmitter; const pythonInterpreter: PythonInterpreter = { path: '/foo/bar/python.exe', version: new SemVer('3.6.6-final'), @@ -63,21 +65,22 @@ suite('Interpreters Activation - Python Environment Variables', () => { processService = mock(ProcessService); currentProcess = mock(CurrentProcess); envVarsService = mock(EnvironmentVariablesProvider); - workspace = mockedVSCodeNamespaces.workspace!; - when(envVarsService.onDidEnvironmentVariablesChange).thenReturn(new EventEmitter().event); - service = new EnvironmentActivationService(instance(helper), instance(platform), instance(processServiceFactory), instance(currentProcess), instance(envVarsService)); - - const cfg = typemoq.Mock.ofType(); - workspace.setup(w => w.getConfiguration(typemoq.It.isValue('python'), typemoq.It.isAny())).returns(() => cfg.object); - workspace.setup(w => w.workspaceFolders).returns(() => []); - cfg.setup(c => c.inspect(typemoq.It.isValue('pythonPath'))).returns(() => { - return { globalValue: 'GlobalValuepython' } as any; - }); - clearCache(); + interpreterService = mock(InterpreterService); + workspace = mock(WorkspaceService); + onDidChangeEnvVariables = new EventEmitter(); + onDidChangeInterpreter = new EventEmitter(); + when(envVarsService.onDidEnvironmentVariablesChange).thenReturn(onDidChangeEnvVariables.event); + when(interpreterService.onDidChangeInterpreter).thenReturn(onDidChangeInterpreter.event); + service = new EnvironmentActivationService( + instance(helper), + instance(platform), + instance(processServiceFactory), + instance(currentProcess), + instance(workspace), + instance(interpreterService), + instance(envVarsService) + ); } - teardown(() => { - mockedVSCodeNamespaces.workspace!.reset(); - }); function title(resource?: Uri, interpreter?: PythonInterpreter) { return `${resource ? 'With a resource' : 'Without a resource'}${interpreter ? ' and an interpreter' : ''}`; @@ -218,6 +221,64 @@ suite('Interpreters Activation - Python Environment Variables', () => { verify(envVarsService.getEnvironmentVariables(resource)).once(); verify(processService.shellExec(anything(), anything())).once(); }); + test('Cache Variables', async () => { + const cmd = ['1', '2']; + const varsFromEnv = { one: '11', two: '22', HELLO: 'xxx' }; + const stdout = `${getEnvironmentPrefix}${EOL}${JSON.stringify(varsFromEnv)}`; + when(platform.osType).thenReturn(osType.value); + when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd); + when(processServiceFactory.create(resource)).thenResolve(instance(processService)); + when(envVarsService.getEnvironmentVariables(resource)).thenResolve({}); + when(processService.shellExec(anything(), anything())).thenResolve({ stdout: stdout }); + + const env = await service.getActivatedEnvironmentVariables(resource, interpreter); + const env2 = await service.getActivatedEnvironmentVariables(resource, interpreter); + const env3 = await service.getActivatedEnvironmentVariables(resource, interpreter); + + expect(env).to.deep.equal(varsFromEnv); + // All same objects. + expect(env) + .to.equal(env2) + .to.equal(env3); + + // All methods invoked only once. + verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once(); + verify(processServiceFactory.create(resource)).once(); + verify(envVarsService.getEnvironmentVariables(resource)).once(); + verify(processService.shellExec(anything(), anything())).once(); + }); + async function testClearingCache(bustCache: Function) { + const cmd = ['1', '2']; + const varsFromEnv = { one: '11', two: '22', HELLO: 'xxx' }; + const stdout = `${getEnvironmentPrefix}${EOL}${JSON.stringify(varsFromEnv)}`; + when(platform.osType).thenReturn(osType.value); + when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd); + when(processServiceFactory.create(resource)).thenResolve(instance(processService)); + when(envVarsService.getEnvironmentVariables(resource)).thenResolve({}); + when(processService.shellExec(anything(), anything())).thenResolve({ stdout: stdout }); + + const env = await service.getActivatedEnvironmentVariables(resource, interpreter); + bustCache(); + const env2 = await service.getActivatedEnvironmentVariables(resource, interpreter); + + expect(env).to.deep.equal(varsFromEnv); + // Objects are different (not same reference). + expect(env).to.not.equal(env2); + // However variables are the same. + expect(env).to.deep.equal(env2); + + // All methods invoked twice as cache was blown. + verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).twice(); + verify(processServiceFactory.create(resource)).twice(); + verify(envVarsService.getEnvironmentVariables(resource)).twice(); + verify(processService.shellExec(anything(), anything())).twice(); + } + test('Cache Variables get cleared when changing interpreter', async () => { + await testClearingCache(onDidChangeInterpreter.fire.bind(onDidChangeInterpreter)); + }); + test('Cache Variables get cleared when changing env variables file', async () => { + await testClearingCache(onDidChangeEnvVariables.fire.bind(onDidChangeEnvVariables)); + }); }); }); }); From c519755200ece13b0bba8d05096a835eb52acfb5 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 21 Feb 2020 09:22:07 -0800 Subject: [PATCH 2/5] Update change log --- CHANGELOG.md | 60 ++++++++++++++++++++++++++++++++++++++++++- news/2 Fixes/10250.md | 1 - 2 files changed, 59 insertions(+), 2 deletions(-) delete mode 100644 news/2 Fixes/10250.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ef23add58bc0..c539ba3814be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,64 @@ # Changelog -## 2020.2.2 (20 February 2020) +## 2020.2.3 (20 February 2020) + +### Fixes + +1. Ensure to correctly return env variables of the activated interpreter, when dealing with non-workspace interpreters. + ([#10250](https://github.com/Microsoft/vscode-python/issues/10250)) + +### Thanks + +Thanks to the following projects which we fully rely on to provide some of +our features: + +- [isort](https://pypi.org/project/isort/) +- [jedi](https://pypi.org/project/jedi/) + and [parso](https://pypi.org/project/parso/) +- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server) +- [ptvsd](https://pypi.org/project/ptvsd/) +- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed) +- [rope](https://pypi.org/project/rope/) (user-installed) + +Also thanks to the various projects we provide integrations with which help +make this extension useful: + +- Debugging support: + [Django](https://pypi.org/project/Django/), + [Flask](https://pypi.org/project/Flask/), + [gevent](https://pypi.org/project/gevent/), + [Jinja](https://pypi.org/project/Jinja/), + [Pyramid](https://pypi.org/project/pyramid/), + [PySpark](https://pypi.org/project/pyspark/), + [Scrapy](https://pypi.org/project/Scrapy/), + [Watson](https://pypi.org/project/Watson/) +- Formatting: + [autopep8](https://pypi.org/project/autopep8/), + [black](https://pypi.org/project/black/), + [yapf](https://pypi.org/project/yapf/) +- Interpreter support: + [conda](https://conda.io/), + [direnv](https://direnv.net/), + [pipenv](https://pypi.org/project/pipenv/), + [pyenv](https://github.com/pyenv/pyenv), + [venv](https://docs.python.org/3/library/venv.html#module-venv), + [virtualenv](https://pypi.org/project/virtualenv/) +- Linting: + [bandit](https://pypi.org/project/bandit/), + [flake8](https://pypi.org/project/flake8/), + [mypy](https://pypi.org/project/mypy/), + [prospector](https://pypi.org/project/prospector/), + [pylint](https://pypi.org/project/pylint/), + [pydocstyle](https://pypi.org/project/pydocstyle/), + [pylama](https://pypi.org/project/pylama/) +- Testing: + [nose](https://pypi.org/project/nose/), + [pytest](https://pypi.org/project/pytest/), + [unittest](https://docs.python.org/3/library/unittest.html#module-unittest) + +And finally thanks to the [Python](https://www.python.org/) development team and +community for creating a fantastic programming language and community to be a +part of! ## 2020.2.2 (19 February 2020) diff --git a/news/2 Fixes/10250.md b/news/2 Fixes/10250.md deleted file mode 100644 index e3ed4fd36c48..000000000000 --- a/news/2 Fixes/10250.md +++ /dev/null @@ -1 +0,0 @@ -Ensure to correctly return env variables of the activated interpreter, when dealing with non-workspace interpreters. From 4812063a63075dd0684a72c387f5b60f787f7cb6 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 21 Feb 2020 09:22:27 -0800 Subject: [PATCH 3/5] Fix date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c539ba3814be..a0ab79d9d231 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2020.2.3 (20 February 2020) +## 2020.2.3 (21 February 2020) ### Fixes From 4d7450c9cf1a318f85ca5ab7ee2bf65538fb3a6e Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 21 Feb 2020 09:27:53 -0800 Subject: [PATCH 4/5] Oops --- src/client/interpreter/activation/service.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/client/interpreter/activation/service.ts b/src/client/interpreter/activation/service.ts index 96c684065977..2f708d2319e8 100644 --- a/src/client/interpreter/activation/service.ts +++ b/src/client/interpreter/activation/service.ts @@ -13,11 +13,7 @@ import { IPlatformService } from '../../common/platform/types'; import { IProcessServiceFactory } from '../../common/process/types'; import { ITerminalHelper, TerminalShellType } from '../../common/terminal/types'; import { ICurrentProcess, IDisposable, Resource } from '../../common/types'; -<<<<<<< HEAD -import { cacheResourceSpecificInterpreterData, clearCachedResourceSpecificIngterpreterData } from '../../common/utils/decorators'; -======= import { InMemoryCache } from '../../common/utils/cacheUtils'; ->>>>>>> ae86ae46f... Fix to return env variables of interpreter that is not current interpreter (#10251) import { OSType } from '../../common/utils/platform'; import { IEnvironmentVariablesProvider } from '../../common/variables/types'; import { EXTENSION_ROOT_DIR } from '../../constants'; From 8d322dcca2bee44b17f0b413031823c3ada29685 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 21 Feb 2020 09:40:32 -0800 Subject: [PATCH 5/5] Fix linter --- src/client/common/logger.ts | 6 +---- src/client/interpreter/activation/service.ts | 26 ++++---------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/client/common/logger.ts b/src/client/common/logger.ts index 89c048af58d7..88a88a05199d 100644 --- a/src/client/common/logger.ts +++ b/src/client/common/logger.ts @@ -285,11 +285,7 @@ function trace(message: string, options: LogOptions = LogOptions.None, logLevel? // tslint:disable-next-line:no-any function writeToLog(elapsedTime: number, returnValue?: any, ex?: Error) { const messagesToLog = [message]; - messagesToLog.push( - `Class name = ${className}, completed in ${elapsedTime}ms, has a ${ - returnValue ? 'truthy' : 'falsy' - } return value` - ); + messagesToLog.push(`Class name = ${className}, completed in ${elapsedTime}ms, has a ${returnValue ? 'truthy' : 'falsy'} return value`); if ((options && LogOptions.Arguments) === LogOptions.Arguments) { messagesToLog.push(argsToLogString(args)); } diff --git a/src/client/interpreter/activation/service.ts b/src/client/interpreter/activation/service.ts index 2f708d2319e8..bb27a8fc65cc 100644 --- a/src/client/interpreter/activation/service.ts +++ b/src/client/interpreter/activation/service.ts @@ -47,17 +47,9 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi @inject(IInterpreterService) private interpreterService: IInterpreterService, @inject(IEnvironmentVariablesProvider) private readonly envVarsService: IEnvironmentVariablesProvider ) { - this.envVarsService.onDidEnvironmentVariablesChange( - () => this.activatedEnvVariablesCache.clear(), - this, - this.disposables - ); - - this.interpreterService.onDidChangeInterpreter( - () => this.activatedEnvVariablesCache.clear(), - this, - this.disposables - ); + this.envVarsService.onDidEnvironmentVariablesChange(() => this.activatedEnvVariablesCache.clear(), this, this.disposables); + + this.interpreterService.onDidChangeInterpreter(() => this.activatedEnvVariablesCache.clear(), this, this.disposables); } public dispose(): void { @@ -65,11 +57,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi } @traceDecorators.verbose('getActivatedEnvironmentVariables', LogOptions.Arguments) @captureTelemetry(EventName.PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES, { failed: false }, true) - public async getActivatedEnvironmentVariables( - resource: Resource, - interpreter?: PythonInterpreter, - allowExceptions?: boolean - ): Promise { + public async getActivatedEnvironmentVariables(resource: Resource, interpreter?: PythonInterpreter, allowExceptions?: boolean): Promise { // Cache key = resource + interpreter. const workspaceKey = this.workspace.getWorkspaceFolderIdentifier(resource); const interpreterPath = this.platform.isWindows ? interpreter?.path.toLowerCase() : interpreter?.path; @@ -88,11 +76,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi }); } - public async getActivatedEnvironmentVariablesImpl( - resource: Resource, - interpreter?: PythonInterpreter, - allowExceptions?: boolean - ): Promise { + public async getActivatedEnvironmentVariablesImpl(resource: Resource, interpreter?: PythonInterpreter, allowExceptions?: boolean): Promise { const shellInfo = defaultShells[this.platform.osType]; if (!shellInfo) { return;