Skip to content

Run python code using env variables from activated envs #3930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 52 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
68a566d
Misc
DonJayamanne Jan 2, 2019
eea64b7
Merge branch 'master' of https://github.com/DonJayamanne/pythonVSCode
DonJayamanne Jan 8, 2019
93119d2
Merge branch 'master' of https://github.com/DonJayamanne/pythonVSCode
DonJayamanne Jan 10, 2019
fa9c397
Run python code using env variables from activated envs
DonJayamanne Jan 8, 2019
bfc634a
Improve readability
DonJayamanne Jan 8, 2019
cf1535a
Give preference to version returned by python process
DonJayamanne Jan 9, 2019
eb69a75
Fix trace message
DonJayamanne Jan 9, 2019
a5ae72d
Fix typo
DonJayamanne Jan 9, 2019
8bec994
Fixed errors, ensure vsc, console does not leak into debug adapter code
DonJayamanne Jan 9, 2019
f5e2b97
Fixes
DonJayamanne Jan 9, 2019
85f77d9
Fixed tests
DonJayamanne Jan 9, 2019
817a4df
More tests for caching
DonJayamanne Jan 9, 2019
917fb36
Update src/client/common/utils/cacheUtils.ts
brettcannon Jan 9, 2019
14c8e93
Update src/client/common/utils/cacheUtils.ts
brettcannon Jan 9, 2019
3f58161
Update src/test/common/process/pythonExecutionFactory.unit.test.ts
brettcannon Jan 9, 2019
d3dc620
Update src/test/common/process/pythonExecutionFactory.unit.test.ts
brettcannon Jan 9, 2019
79316af
Update src/client/common/utils/cacheUtils.ts
brettcannon Jan 9, 2019
3b4dbcf
Update src/test/common/terminals/environmentActivationProviders/pipEn…
brettcannon Jan 9, 2019
d341e01
Update src/test/common/terminals/environmentActivationProviders/pipEn…
brettcannon Jan 9, 2019
1777227
Use default shells
DonJayamanne Jan 9, 2019
bd863c6
Change time
DonJayamanne Jan 9, 2019
b5948f2
Log command
DonJayamanne Jan 9, 2019
dc5f730
Rename PipEnv to Pipenv
DonJayamanne Jan 10, 2019
10ec5d4
Write tests
DonJayamanne Jan 10, 2019
901465b
Fixed tests
DonJayamanne Jan 10, 2019
135fbf3
Fix tests
DonJayamanne Jan 10, 2019
cffda9a
Fix test
DonJayamanne Jan 10, 2019
30c40b5
Fix tests
DonJayamanne Jan 10, 2019
a715423
Always pass value into get configuration
DonJayamanne Jan 10, 2019
6947f18
Fix tests
DonJayamanne Jan 10, 2019
b909447
Fix tests
DonJayamanne Jan 10, 2019
ac4414d
cleaner
DonJayamanne Jan 10, 2019
a1faa8b
Register services
DonJayamanne Jan 10, 2019
46d0bb3
Fix svc registrations
DonJayamanne Jan 10, 2019
d1ea8dc
Address code review comments
DonJayamanne Jan 10, 2019
5cd8061
Add telemetry
DonJayamanne Jan 10, 2019
a496df3
Log errors
DonJayamanne Jan 10, 2019
cdd5d49
Fix tests
DonJayamanne Jan 10, 2019
5e530bf
Add news entry
DonJayamanne Jan 10, 2019
a25695a
Fix references
DonJayamanne Jan 10, 2019
34a6779
Fixed tests
DonJayamanne Jan 10, 2019
77adb2b
Address review comments
DonJayamanne Jan 10, 2019
3f5268f
Update news/3 Code Health/3746.md
brettcannon Jan 10, 2019
eeac026
Update news/2 Fixes/3330.md
brettcannon Jan 10, 2019
ac0a360
Fix tests
DonJayamanne Jan 10, 2019
2ce0659
Merge branch 'issueCondaActivation' of https://github.com/DonJayamann…
DonJayamanne Jan 10, 2019
1d22e7b
More fixes
DonJayamanne Jan 10, 2019
2fcd998
Fixes
DonJayamanne Jan 10, 2019
66bd123
Fixed tests
DonJayamanne Jan 10, 2019
c8de453
Fixes
DonJayamanne Jan 10, 2019
58ab538
Fix tests
DonJayamanne Jan 10, 2019
1b29756
Fix tests
DonJayamanne Jan 10, 2019
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes


1. Lowering threshold for Language Server support on a platform.
([#3693](https://github.com/Microsoft/vscode-python/issues/3693))
1. Fix bug affecting multiple linters used in a workspace.
Expand Down
5 changes: 1 addition & 4 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,6 @@ gulp.task("compile", () => {


gulp.task('compile-webviews', async () => spawnAsync('npx', ['webpack', '--config', 'webpack.datascience-ui.config.js', '--mode', 'production']));
gulp.task('webpack', async () => {
await spawnAsync('npx', ['webpack', '--mode', 'production', '--inline', '--progress']);
await spawnAsync('npx', ['webpack', '--config', './build/webpack/webpack.extension.config.js', '--mode', 'production', '--inline', '--progress']);
});

gulp.task('webpack', async () => {
await spawnAsync('npx', ['webpack', '--mode', 'production']);
Expand Down Expand Up @@ -708,6 +704,7 @@ function getFilesToProcess(fileList) {
* @param {hygieneOptions} options
*/
function getFileListToProcess(options) {
return [];
const mode = options ? options.mode : 'all';
const gulpSrcOptions = { base: '.' };

Expand Down
1 change: 1 addition & 0 deletions news/1 Enhancements/2855.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Activate `pipenv` environments in the shell using the command `pipenv shell`.
1 change: 1 addition & 0 deletions news/2 Fixes/3330.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Activate any selected Python Environment when running unit tests.
1 change: 1 addition & 0 deletions news/2 Fixes/3953.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove duplicates from interpreters listed in the interpreter selection list.
1 change: 1 addition & 0 deletions news/3 Code Health/3746.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Detect usage of `xonsh` shells (this does **not** add support for `xonsh` itself)
7 changes: 7 additions & 0 deletions pythonFiles/printEnvVariables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import os
import json

print(json.dumps(dict(os.environ)))
30 changes: 18 additions & 12 deletions src/client/common/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Logger implements ILogger {
}
}

enum LogOptions {
export enum LogOptions {
None = 0,
Arguments = 1,
ReturnValue = 2
Expand All @@ -57,6 +57,9 @@ function argsToLogString(args: any[]): string {
try {
return (args || []).map((item, index) => {
try {
if (item.fsPath) {
return `Arg ${index + 1}: <Uri:${item.fsPath}>`;
}
return `Arg ${index + 1}: ${JSON.stringify(item)}`;
} catch {
return `Arg ${index + 1}: UNABLE TO DETERMINE VALUE`;
Expand All @@ -69,15 +72,18 @@ function argsToLogString(args: any[]): string {

// tslint:disable-next-line:no-any
function returnValueToLogString(returnValue: any): string {
let returnValueMessage = 'Return Value: ';
if (returnValue) {
try {
returnValueMessage += `${JSON.stringify(returnValue)}`;
} catch {
returnValueMessage += 'UNABLE TO DETERMINE VALUE';
}
const returnValueMessage = 'Return Value: ';
if (returnValue === undefined) {
return `${returnValueMessage}undefined`;
}
if (returnValue === null) {
return `${returnValueMessage}null`;
}
try {
return `${returnValueMessage}${JSON.stringify(returnValue)}`;
} catch {
return `${returnValueMessage}<Return value cannot be serialized for logging>`;
}
return returnValueMessage;
}

export function traceVerbose(message: string) {
Expand All @@ -91,10 +97,10 @@ export function traceInfo(message: string) {
}

export namespace traceDecorators {
export function verbose(message: string) {
return trace(message, LogOptions.Arguments | LogOptions.ReturnValue);
export function verbose(message: string, options: LogOptions = LogOptions.Arguments | LogOptions.ReturnValue) {
return trace(message, options);
}
export function error(message: string, ex?: Error) {
export function error(message: string) {
return trace(message, LogOptions.Arguments | LogOptions.ReturnValue, LogLevel.Error);
}
export function info(message: string) {
Expand Down
2 changes: 0 additions & 2 deletions src/client/common/platform/fileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import * as glob from 'glob';
import { inject, injectable } from 'inversify';
import * as path from 'path';
import * as tmp from 'tmp';
import { traceDecorators } from '../logger';
import { createDeferred } from '../utils/async';
import { IFileSystem, IPlatformService, TemporaryFile } from './types';

Expand Down Expand Up @@ -144,7 +143,6 @@ export class FileSystem implements IFileSystem {
return deferred.promise;
}

@traceDecorators.error('Failed to get FileHash')
public getFileHash(filePath: string): Promise<string | undefined> {
return new Promise<string | undefined>(resolve => {
fs.lstat(filePath, (err, stats) => {
Expand Down
3 changes: 0 additions & 3 deletions src/client/common/platform/platformService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as os from 'os';
import { coerce, SemVer } from 'semver';
import { sendTelemetryEvent } from '../../telemetry';
import { PLATFORM_INFO, PlatformErrors } from '../../telemetry/constants';
import { traceDecorators, traceError } from '../logger';
import { OSType } from '../utils/platform';
import { parseVersion } from '../utils/version';
import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants';
Expand All @@ -23,7 +22,6 @@ export class PlatformService implements IPlatformService {
public get virtualEnvBinName() {
return this.isWindows ? 'Scripts' : 'bin';
}
@traceDecorators.verbose('Get Platform Version')
public async getVersion(): Promise<SemVer> {
if (this.version) {
return this.version;
Expand All @@ -43,7 +41,6 @@ export class PlatformService implements IPlatformService {
throw new Error('Unable to parse version');
} catch (ex) {
sendTelemetryEvent(PLATFORM_INFO, undefined, { failureType: PlatformErrors.FailedToParseVersion });
traceError(`Failed to parse Version ${os.release()}`, ex);
return parseVersion(os.release());
}
default:
Expand Down
11 changes: 5 additions & 6 deletions src/client/common/process/proc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import { exec, spawn } from 'child_process';
import { Observable } from 'rxjs/Observable';
import * as tk from 'tree-kill';
import { Disposable } from 'vscode';

import { IDisposable } from '../types';
import { createDeferred } from '../utils/async';
import { EnvironmentVariables } from '../variables/types';
import { DEFAULT_ENCODING } from './constants';
Expand Down Expand Up @@ -47,11 +46,11 @@ export class ProcessService implements IProcessService {
let procExited = false;

const output = new Observable<Output<string>>(subscriber => {
const disposables: Disposable[] = [];
const disposables: IDisposable[] = [];

const on = (ee: NodeJS.EventEmitter, name: string, fn: Function) => {
ee.on(name, fn as any);
disposables.push({ dispose: () => ee.removeListener(name, fn as any) });
disposables.push({ dispose: () => ee.removeListener(name, fn as any) as any });
};

if (options.token) {
Expand Down Expand Up @@ -102,11 +101,11 @@ export class ProcessService implements IProcessService {
const encoding = spawnOptions.encoding ? spawnOptions.encoding : 'utf8';
const proc = spawn(file, args, spawnOptions);
const deferred = createDeferred<ExecutionResult<string>>();
const disposables: Disposable[] = [];
const disposables: IDisposable[] = [];

const on = (ee: NodeJS.EventEmitter, name: string, fn: Function) => {
ee.on(name, fn as any);
disposables.push({ dispose: () => ee.removeListener(name, fn as any) });
disposables.push({ dispose: () => ee.removeListener(name, fn as any) as any});
};

if (options.token) {
Expand Down
30 changes: 22 additions & 8 deletions src/client/common/process/pythonExecutionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,37 @@
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import { Uri } from 'vscode';
import { IEnvironmentActivationService } from '../../interpreter/activation/types';
import { IServiceContainer } from '../../ioc/types';
import { IConfigurationService } from '../types';
import { sendTelemetryEvent } from '../../telemetry';
import { PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES } from '../../telemetry/constants';
import { IConfigurationService, Resource } from '../types';
import { ProcessService } from './proc';
import { PythonExecutionService } from './pythonProcess';
import { ExecutionFactoryCreationOptions, IProcessServiceFactory, IPythonExecutionFactory, IPythonExecutionService } from './types';
import { ExecutionFactoryCreationOptions, IBufferDecoder, IProcessServiceFactory, IPythonExecutionFactory, IPythonExecutionService } from './types';

@injectable()
export class PythonExecutionFactory implements IPythonExecutionFactory {
private readonly configService: IConfigurationService;
private processServiceFactory: IProcessServiceFactory;
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
this.processServiceFactory = serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
this.configService = serviceContainer.get<IConfigurationService>(IConfigurationService);
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer,
@inject(IEnvironmentActivationService) private readonly activationHelper: IEnvironmentActivationService,
@inject(IProcessServiceFactory) private readonly processServiceFactory: IProcessServiceFactory,
@inject(IConfigurationService) private readonly configService: IConfigurationService,
@inject(IBufferDecoder) private readonly decoder: IBufferDecoder) {
}
public async create(options: ExecutionFactoryCreationOptions): Promise<IPythonExecutionService> {
const pythonPath = options.pythonPath ? options.pythonPath : this.configService.getSettings(options.resource).pythonPath;
const processService = await this.processServiceFactory.create(options.resource);
return new PythonExecutionService(this.serviceContainer, processService, pythonPath);
}
public async createActivatedEnvironment(resource: Resource): Promise<IPythonExecutionService> {
const envVars = await this.activationHelper.getActivatedEnvironmentVariables(resource);
const hasEnvVars = envVars && Object.keys(envVars).length > 0;
sendTelemetryEvent(PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES, undefined, { hasEnvVars });
if (!hasEnvVars) {
return this.create({ resource });
}
const pythonPath = this.configService.getSettings(resource).pythonPath;
const processService = new ProcessService(this.decoder, { ...envVars });
return new PythonExecutionService(this.serviceContainer, processService, pythonPath);
}
}
3 changes: 2 additions & 1 deletion src/client/common/process/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { ChildProcess, ExecOptions, SpawnOptions as ChildProcessSpawnOptions } from 'child_process';
import { Observable } from 'rxjs/Observable';
import { CancellationToken, Uri } from 'vscode';
import { ExecutionInfo, Version } from '../types';
import { ExecutionInfo, Resource, Version } from '../types';
import { Architecture } from '../utils/platform';
import { EnvironmentVariables } from '../variables/types';

Expand Down Expand Up @@ -57,6 +57,7 @@ export type ExecutionFactoryCreationOptions = {
};
export interface IPythonExecutionFactory {
create(options: ExecutionFactoryCreationOptions): Promise<IPythonExecutionService>;
createActivatedEnvironment(resource: Resource): Promise<IPythonExecutionService>;
}
export type ReleaseLevel = 'alpha' | 'beta' | 'candidate' | 'final' | 'unknown';
export type PythonVersionInfo = [number, number, number, ReleaseLevel];
Expand Down
15 changes: 11 additions & 4 deletions src/client/common/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import { TerminalActivator } from './terminal/activator';
import { PowershellTerminalActivationFailedHandler } from './terminal/activator/powershellFailedHandler';
import { Bash } from './terminal/environmentActivationProviders/bash';
import { CommandPromptAndPowerShell } from './terminal/environmentActivationProviders/commandPrompt';
import { CondaActivationCommandProvider } from './terminal/environmentActivationProviders/condaActivationProvider';
import { PipEnvActivationCommandProvider } from './terminal/environmentActivationProviders/pipEnvActivationProvider';
import { PyEnvActivationCommandProvider } from './terminal/environmentActivationProviders/pyenvActivationProvider';
import { TerminalServiceFactory } from './terminal/factory';
import { TerminalHelper } from './terminal/helper';
Expand All @@ -45,7 +47,8 @@ import {
ITerminalActivationHandler,
ITerminalActivator,
ITerminalHelper,
ITerminalServiceFactory
ITerminalServiceFactory,
TerminalActivationProviders
} from './terminal/types';
import {
IAsyncDisposableRegistry,
Expand Down Expand Up @@ -93,11 +96,15 @@ export function registerTypes(serviceManager: IServiceManager) {

serviceManager.addSingleton<ITerminalHelper>(ITerminalHelper, TerminalHelper);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
ITerminalActivationCommandProvider, Bash, 'bashCShellFish');
ITerminalActivationCommandProvider, Bash, TerminalActivationProviders.bashCShellFish);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
ITerminalActivationCommandProvider, CommandPromptAndPowerShell, 'commandPromptAndPowerShell');
ITerminalActivationCommandProvider, CommandPromptAndPowerShell, TerminalActivationProviders.commandPromptAndPowerShell);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
ITerminalActivationCommandProvider, PyEnvActivationCommandProvider, 'pyenv');
ITerminalActivationCommandProvider, PyEnvActivationCommandProvider, TerminalActivationProviders.pyenv);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
ITerminalActivationCommandProvider, CondaActivationCommandProvider, TerminalActivationProviders.conda);
serviceManager.addSingleton<ITerminalActivationCommandProvider>(
ITerminalActivationCommandProvider, PipEnvActivationCommandProvider, TerminalActivationProviders.pipenv);
serviceManager.addSingleton<IFeatureDeprecationManager>(IFeatureDeprecationManager, FeatureDeprecationManager);

serviceManager.addSingleton<IAsyncDisposableRegistry>(IAsyncDisposableRegistry, AsyncDisposableRegistry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

'use strict';

import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import * as path from 'path';
import { Uri } from 'vscode';
import { ICondaService } from '../../../interpreter/contracts';
Expand All @@ -19,7 +19,7 @@ import { ITerminalActivationCommandProvider, TerminalShellType } from '../types'
@injectable()
export class CondaActivationCommandProvider implements ITerminalActivationCommandProvider {
constructor(
private readonly serviceContainer: IServiceContainer
@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer
) { }

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import { inject, injectable } from 'inversify';
import { Uri } from 'vscode';
import { IInterpreterService, InterpreterType } from '../../../interpreter/contracts';
import { ITerminalActivationCommandProvider, TerminalShellType } from '../types';

@injectable()
export class PipEnvActivationCommandProvider implements ITerminalActivationCommandProvider {
constructor(@inject(IInterpreterService) private readonly interpreterService: IInterpreterService) { }

public isShellSupported(_targetShell: TerminalShellType): boolean {
return true;
}

public async getActivationCommands(resource: Uri | undefined, _: TerminalShellType): Promise<string[] | undefined> {
const interpreter = await this.interpreterService.getActiveInterpreter(resource);
if (!interpreter || interpreter.type !== InterpreterType.Pipenv) {
return;
}

return ['pipenv shell'];
}
}
Loading