Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7352a0a
Cherry pick fix for native notebook support into release branch (#15369)
rchiodo Feb 9, 2021
3f78ccb
Add extraPaths support to JediLSP (#15365)
karthiknadig Feb 9, 2021
525ec78
Ignore directories with the same name as python binaries (#15367)
karthiknadig Feb 9, 2021
338af89
Correct pipenv activation provider when in discovery experiment (#15319)
Feb 9, 2021
b47cac4
In PythonEnvsReducer.resolveEnv(), always fall back to the wrapped lo…
Feb 9, 2021
9622cd0
Fix issue with missing interpreter info for some cases (#15376)
karthiknadig Feb 11, 2021
fda2505
Add reference to CVE-2020-16977 fixed in Oct 2020. (#15381)
Feb 11, 2021
3e56c96
Fix CI failing with the number of constructor arguments error (#15347)
Feb 9, 2021
6db5c5e
Fix Command 'workbench.action.closeAllEditors' timed out failure on C…
Feb 9, 2021
d619de6
Ensure environment variables provider can be created using standard c…
Feb 11, 2021
18c2637
Fix ESLint errors for environment variable provider (#15383)
Feb 11, 2021
ca8cbdf
Fix problem with notebook apis not being used. (#15366)
rchiodo Feb 9, 2021
875e5a9
Merge pull request #15378 from karthiknadig/cherry1
karthiknadig Feb 11, 2021
5553953
Show Python: Launch TensorBoard command in command palette (#15382) (…
joyceerhl Feb 11, 2021
2179b30
Cherry picks from main to release (#15421)
karthiknadig Feb 17, 2021
0eeaab4
Release final (#15433)
karthiknadig Feb 17, 2021
492fc99
Ensure pyenv virtual envs are not skipped when in discovery experimen…
karthiknadig Feb 19, 2021
9f7789a
Register Jedi regardless of what language server is configured (#15452)
Feb 19, 2021
d9c00fb
Only call component adapter behind the discovery experiment (#15459)
Feb 19, 2021
8809079
Merge pull request #15461 from karthiknadig/cherry1
karthiknadig Feb 19, 2021
ba1dc7d
Update version and change log for point release (#15463)
karthiknadig Feb 19, 2021
ec0fb4f
Update start-up telemetry for Jedi LSP (#15419) (#15571)
karthiknadig Mar 5, 2021
08565f1
Version and change log update for point release (#15572)
karthiknadig Mar 5, 2021
62bd685
Merge back release into main
karthiknadig Mar 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Ensure environment variables provider can be created using standard c…
…lasses (#15377)

* Ensure environment variables provider can be created using standard classes

* Fix unit tests
  • Loading branch information
Kartik Raj authored and karthiknadig committed Feb 11, 2021
commit d619de6ca23961b117ec04be81816023a20976bc
17 changes: 12 additions & 5 deletions src/client/common/variables/environmentVariablesProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { inject, injectable, optional } from 'inversify';
import { ConfigurationChangeEvent, Disposable, Event, EventEmitter, FileSystemWatcher, Uri } from 'vscode';
import { sendFileCreationTelemetry } from '../../telemetry/envFileTelemetry';
import { IWorkspaceService } from '../application/types';
import { PythonSettings } from '../configSettings';
import { traceVerbose } from '../logger';
import { IPlatformService } from '../platform/types';
import { IConfigurationService, ICurrentProcess, IDisposableRegistry } from '../types';
import { ICurrentProcess, IDisposableRegistry } from '../types';
import { InMemoryCache } from '../utils/cacheUtils';
import { SystemVariables } from './systemVariables';
import { EnvironmentVariables, IEnvironmentVariablesProvider, IEnvironmentVariablesService } from './types';

const CACHE_DURATION = 60 * 60 * 1000;
Expand All @@ -25,7 +27,6 @@ export class EnvironmentVariablesProvider implements IEnvironmentVariablesProvid
@inject(IDisposableRegistry) disposableRegistry: Disposable[],
@inject(IPlatformService) private platformService: IPlatformService,
@inject(IWorkspaceService) private workspaceService: IWorkspaceService,
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
@inject(ICurrentProcess) private process: ICurrentProcess,
@optional() private cacheDuration: number = CACHE_DURATION,
) {
Expand Down Expand Up @@ -86,11 +87,17 @@ export class EnvironmentVariablesProvider implements IEnvironmentVariablesProvid
return mergedVars;
}
public async getCustomEnvironmentVariables(resource?: Uri): Promise<EnvironmentVariables | undefined> {
const settings = this.configurationService.getSettings(resource);
const systemVariables: SystemVariables = new SystemVariables(
undefined,
PythonSettings.getSettingsUriAndTarget(resource, this.workspaceService).uri?.fsPath,
this.workspaceService,
);
const envFileSetting = this.workspaceService.getConfiguration('python', resource).get<string>('envFile');
const envFile = systemVariables.resolveAny(envFileSetting)!;
const workspaceFolderUri = this.getWorkspaceFolderUri(resource);
this.trackedWorkspaceFolders.add(workspaceFolderUri ? workspaceFolderUri.fsPath : '');
this.createFileWatcher(settings.envFile, workspaceFolderUri);
return this.envVarsService.parseFile(settings.envFile, this.process.env);
this.createFileWatcher(envFile, workspaceFolderUri);
return this.envVarsService.parseFile(envFile, this.process.env);
}
public configurationChanged(e: ConfigurationChangeEvent) {
this.trackedWorkspaceFolders.forEach((item) => {
Expand Down
2 changes: 0 additions & 2 deletions src/client/extensionActivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
IOutputChannel,
} from './common/types';
import { noop } from './common/utils/misc';
import { registerTypes as variableRegisterTypes } from './common/variables/serviceRegistry';
import { DebuggerTypeName } from './debugger/constants';
import { DebugSessionEventDispatcher } from './debugger/extension/hooks/eventHandlerDispatcher';
import { IDebugSessionEventHandlers } from './debugger/extension/hooks/types';
Expand Down Expand Up @@ -112,7 +111,6 @@ async function activateLegacy(ext: ExtensionState): Promise<ActivationResult> {
const { enableProposedApi } = applicationEnv.packageJson;
serviceManager.addSingletonInstance<boolean>(UseProposedApi, enableProposedApi);
// Feature specific registrations.
variableRegisterTypes(serviceManager);
unitTestsRegisterTypes(serviceManager);
lintersRegisterTypes(serviceManager);
interpretersRegisterTypes(serviceManager);
Expand Down
2 changes: 2 additions & 0 deletions src/client/extensionInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
IOutputChannel,
WORKSPACE_MEMENTO,
} from './common/types';
import { registerTypes as variableRegisterTypes } from './common/variables/serviceRegistry';
import { OutputChannelNames } from './common/utils/localize';
import { ExtensionState } from './components';
import { ServiceContainer } from './ioc/container';
Expand Down Expand Up @@ -69,6 +70,7 @@ export function initializeStandard(ext: ExtensionState): void {
const { serviceManager } = ext.legacyIOC;
// Core registrations (non-feature specific).
commonRegisterTypes(serviceManager);
variableRegisterTypes(serviceManager);
platformRegisterTypes(serviceManager);
processRegisterTypes(serviceManager);

Expand Down
3 changes: 0 additions & 3 deletions src/test/common/variables/envVarsProvider.multiroot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as path from 'path';
import { anything, instance, mock, when } from 'ts-mockito';
import { ConfigurationTarget, Disposable, Uri, workspace } from 'vscode';
import { WorkspaceService } from '../../../client/common/application/workspace';
import { ConfigurationService } from '../../../client/common/configuration/service';
import { PlatformService } from '../../../client/common/platform/platformService';
import { IFileSystem } from '../../../client/common/platform/types';
import { IDisposableRegistry, IPathUtils } from '../../../client/common/types';
Expand Down Expand Up @@ -76,14 +75,12 @@ suite('Multiroot Environment Variables Provider', () => {
const variablesService = new EnvironmentVariablesService(pathUtils, fs);
const disposables = ioc.serviceContainer.get<Disposable[]>(IDisposableRegistry);
ioc.serviceManager.addSingletonInstance(IInterpreterAutoSelectionService, new MockAutoSelectionService());
const cfgService = new ConfigurationService(ioc.serviceContainer);
const workspaceService = new WorkspaceService();
return new EnvironmentVariablesProvider(
variablesService,
disposables,
new PlatformService(),
workspaceService,
cfgService,
mockProcess,
);
}
Expand Down
41 changes: 15 additions & 26 deletions src/test/common/variables/environmentVariablesProvider.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import * as typemoq from 'typemoq';
import { ConfigurationChangeEvent, FileSystemWatcher, Uri } from 'vscode';
import { IWorkspaceService } from '../../../client/common/application/types';
import { WorkspaceService } from '../../../client/common/application/workspace';
import { PythonSettings } from '../../../client/common/configSettings';
import { ConfigurationService } from '../../../client/common/configuration/service';
import { PlatformService } from '../../../client/common/platform/platformService';
import { IPlatformService } from '../../../client/common/platform/types';
import { CurrentProcess } from '../../../client/common/process/currentProcess';
import { IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types';
import { ICurrentProcess } from '../../../client/common/types';
import { sleep } from '../../../client/common/utils/async';
import { EnvironmentVariablesService } from '../../../client/common/variables/environment';
import { EnvironmentVariablesProvider } from '../../../client/common/variables/environmentVariablesProvider';
Expand All @@ -29,26 +27,27 @@ suite('Multiroot Environment Variables Provider', () => {
let envVarsService: IEnvironmentVariablesService;
let platform: IPlatformService;
let workspace: IWorkspaceService;
let configuration: IConfigurationService;
let currentProcess: ICurrentProcess;
let settings: IPythonSettings;
let envFile: string;

setup(() => {
envFile = '';
envVarsService = mock(EnvironmentVariablesService);
platform = mock(PlatformService);
workspace = mock(WorkspaceService);
configuration = mock(ConfigurationService);
currentProcess = mock(CurrentProcess);
settings = mock(PythonSettings);

when(configuration.getSettings(anything())).thenReturn(instance(settings));
when(workspace.onDidChangeConfiguration).thenReturn(noop as any);
when(workspace.getConfiguration('python', anything())).thenReturn({
get: (settingName: string) => {
return settingName === 'envFile' ? envFile : '';
},
} as any);
provider = new EnvironmentVariablesProvider(
instance(envVarsService),
[],
instance(platform),
instance(workspace),
instance(configuration),
instance(currentProcess),
);

Expand Down Expand Up @@ -198,62 +197,56 @@ suite('Multiroot Environment Variables Provider', () => {
});

test(`Getting environment variables (without an envfile, without PATH in current env, without PYTHONPATH in current env) & ${workspaceTitle}`, async () => {
const envFile = path.join('a', 'b', 'env.file');
envFile = path.join('a', 'b', 'env.file');
const workspaceFolder = workspaceUri ? { name: '', index: 0, uri: workspaceUri } : undefined;
const currentProcEnv = { SOMETHING: 'wow' };

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(workspaceUri)).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenResolve(undefined);
when(platform.pathVariableName).thenReturn('PATH');

const vars = await provider.getEnvironmentVariables(workspaceUri);

verify(currentProcess.env).atLeast(1);
verify(settings.envFile).atLeast(1);
verify(envVarsService.parseFile(envFile, currentProcEnv)).atLeast(1);
verify(envVarsService.mergeVariables(deepEqual(currentProcEnv), deepEqual({}))).once();
verify(platform.pathVariableName).atLeast(1);
assert.deepEqual(vars, {});
});
test(`Getting environment variables (with an envfile, without PATH in current env, without PYTHONPATH in current env) & ${workspaceTitle}`, async () => {
const envFile = path.join('a', 'b', 'env.file');
envFile = path.join('a', 'b', 'env.file');
const workspaceFolder = workspaceUri ? { name: '', index: 0, uri: workspaceUri } : undefined;
const currentProcEnv = { SOMETHING: 'wow' };
const envFileVars = { MY_FILE: '1234' };

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(workspaceUri)).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenCall(async () => ({ ...envFileVars }));
when(platform.pathVariableName).thenReturn('PATH');

const vars = await provider.getEnvironmentVariables(workspaceUri);

verify(currentProcess.env).atLeast(1);
verify(settings.envFile).atLeast(1);
verify(envVarsService.parseFile(envFile, currentProcEnv)).atLeast(1);
verify(envVarsService.mergeVariables(deepEqual(currentProcEnv), deepEqual(envFileVars))).once();
verify(platform.pathVariableName).atLeast(1);
assert.deepEqual(vars, envFileVars);
});
test(`Getting environment variables (with an envfile, with PATH in current env, with PYTHONPATH in current env) & ${workspaceTitle}`, async () => {
const envFile = path.join('a', 'b', 'env.file');
envFile = path.join('a', 'b', 'env.file');
const workspaceFolder = workspaceUri ? { name: '', index: 0, uri: workspaceUri } : undefined;
const currentProcEnv = { SOMETHING: 'wow', PATH: 'some path value', PYTHONPATH: 'some python path value' };
const envFileVars = { MY_FILE: '1234' };

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(workspaceUri)).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenCall(async () => ({ ...envFileVars }));
when(platform.pathVariableName).thenReturn('PATH');

const vars = await provider.getEnvironmentVariables(workspaceUri);

verify(currentProcess.env).atLeast(1);
verify(settings.envFile).atLeast(1);
verify(envVarsService.parseFile(envFile, currentProcEnv)).atLeast(1);
verify(envVarsService.mergeVariables(deepEqual(currentProcEnv), deepEqual(envFileVars))).once();
verify(envVarsService.appendPath(deepEqual(envFileVars), currentProcEnv.PATH)).once();
Expand All @@ -263,12 +256,11 @@ suite('Multiroot Environment Variables Provider', () => {
});

test(`Getting environment variables which are already cached does not reinvoke the method ${workspaceTitle}`, async () => {
const envFile = path.join('a', 'b', 'env.file');
envFile = path.join('a', 'b', 'env.file');
const workspaceFolder = workspaceUri ? { name: '', index: 0, uri: workspaceUri } : undefined;
const currentProcEnv = { SOMETHING: 'wow' };

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(workspaceUri)).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenResolve(undefined);
when(platform.pathVariableName).thenReturn('PATH');
Expand All @@ -280,7 +272,7 @@ suite('Multiroot Environment Variables Provider', () => {
await provider.getEnvironmentVariables(workspaceUri);

// Verify that the contents of `_getEnvironmentVariables()` method are only invoked once
verify(configuration.getSettings(anything())).once();
verify(workspace.getConfiguration('python', anything())).once();
assert.deepEqual(vars, {});
});

Expand All @@ -290,7 +282,6 @@ suite('Multiroot Environment Variables Provider', () => {
const currentProcEnv = { SOMETHING: 'wow' };

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(workspaceUri)).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenResolve(undefined);
when(platform.pathVariableName).thenReturn('PATH');
Expand All @@ -300,7 +291,6 @@ suite('Multiroot Environment Variables Provider', () => {
[],
instance(platform),
instance(workspace),
instance(configuration),
instance(currentProcess),
100,
);
Expand All @@ -312,14 +302,14 @@ suite('Multiroot Environment Variables Provider', () => {
await provider.getEnvironmentVariables(workspaceUri);

// Verify that the contents of `_getEnvironmentVariables()` method are invoked twice
verify(configuration.getSettings(anything())).twice();
verify(workspace.getConfiguration('python', anything())).twice();
assert.deepEqual(vars, {});
});

test(`Environment variables are updated when env file changes ${workspaceTitle}`, async () => {
const root = workspaceUri?.fsPath ?? '';
const sourceDir = path.join(root, 'a', 'b');
const envFile = path.join(sourceDir, 'env.file');
envFile = path.join(sourceDir, 'env.file');
const sourceFile = path.join(sourceDir, 'main.py');

const workspaceFolder = workspaceUri ? { name: '', index: 0, uri: workspaceUri } : undefined;
Expand All @@ -339,7 +329,6 @@ suite('Multiroot Environment Variables Provider', () => {
when(workspace.createFileSystemWatcher(envFile)).thenReturn(fileSystemWatcher.object);

when(currentProcess.env).thenReturn(currentProcEnv);
when(settings.envFile).thenReturn(envFile);
when(workspace.getWorkspaceFolder(anything())).thenReturn(workspaceFolder);
when(envVarsService.parseFile(envFile, currentProcEnv)).thenCall(async () => ({ ...envFileVars }));
when(platform.pathVariableName).thenReturn('PATH');
Expand Down