Skip to content

Commit 8fc8648

Browse files
author
Kartik Raj
authored
Use conda run for conda environments for running python files (#18520)
* Use conda run when running python files * News * Use conda run for installation * Modify API * Do not modify instqallation
1 parent 24297ad commit 8fc8648

File tree

10 files changed

+61
-12
lines changed

10 files changed

+61
-12
lines changed

news/1 Enhancements/18479.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use `conda run` for conda environments for running python files and installing modules.

src/client/common/process/pythonEnvironment.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,13 @@ export async function createCondaEnv(
149149
// These are used to generate the deps.
150150
procs: IProcessService,
151151
fs: IFileSystem,
152+
executeAsAProcess?: boolean,
152153
): Promise<PythonEnvironment | undefined> {
153154
const conda = await Conda.getConda();
154-
const pythonArgv = await conda?.getRunPythonArgs({ name: condaInfo.name, prefix: condaInfo.path });
155+
const pythonArgv = await conda?.getRunPythonArgs(
156+
{ name: condaInfo.name, prefix: condaInfo.path },
157+
executeAsAProcess,
158+
);
155159
if (!pythonArgv) {
156160
return undefined;
157161
}

src/client/common/process/pythonExecutionFactory.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ export class PythonExecutionFactory implements IPythonExecutionFactory {
7777
}
7878
const processService: IProcessService = await this.processServiceFactory.create(options.resource);
7979

80-
const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService);
80+
const condaExecutionService = await this.createCondaExecutionService(
81+
pythonPath,
82+
processService,
83+
options.executeAsAProcess,
84+
);
8185
if (condaExecutionService) {
8286
return condaExecutionService;
8387
}
@@ -125,13 +129,20 @@ export class PythonExecutionFactory implements IPythonExecutionFactory {
125129
public async createCondaExecutionService(
126130
pythonPath: string,
127131
processService: IProcessService,
132+
executeAsAProcess?: boolean,
128133
): Promise<IPythonExecutionService | undefined> {
129134
const condaLocatorService = this.serviceContainer.get<IComponentAdapter>(IComponentAdapter);
130135
const [condaEnvironment] = await Promise.all([condaLocatorService.getCondaEnvironment(pythonPath)]);
131136
if (!condaEnvironment) {
132137
return undefined;
133138
}
134-
const env = await createCondaEnv(condaEnvironment, pythonPath, processService, this.fileSystem);
139+
const env = await createCondaEnv(
140+
condaEnvironment,
141+
pythonPath,
142+
processService,
143+
this.fileSystem,
144+
executeAsAProcess,
145+
);
135146
if (!env) {
136147
return undefined;
137148
}

src/client/common/process/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ export const IPythonExecutionFactory = Symbol('IPythonExecutionFactory');
6565
export type ExecutionFactoryCreationOptions = {
6666
resource?: Uri;
6767
pythonPath?: string;
68+
/**
69+
* Whether to execute using `NodeJS.child_process` API, considered `true` as default.
70+
*/
71+
executeAsAProcess?: boolean;
6872
};
6973
export type ExecutionFactoryCreateWithEnvironmentOptions = {
7074
resource?: Uri;

src/client/pythonEnvironments/common/environmentManagers/conda.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ export class Conda {
405405
return envList.find((e) => isParentPath(executable, e.prefix));
406406
}
407407

408-
public async getRunPythonArgs(env: CondaEnvInfo): Promise<string[] | undefined> {
408+
public async getRunPythonArgs(env: CondaEnvInfo, executeAsAProcess = true): Promise<string[] | undefined> {
409409
const condaVersion = await this.getCondaVersion();
410410
if (condaVersion && lt(condaVersion, CONDA_RUN_VERSION)) {
411411
return undefined;
@@ -416,7 +416,11 @@ export class Conda {
416416
} else {
417417
args.push('-p', env.prefix);
418418
}
419-
return [this.command, 'run', ...args, '--no-capture-output', '--live-stream', 'python', OUTPUT_MARKER_SCRIPT];
419+
const pythonArgs = [this.command, 'run', ...args, '--no-capture-output', '--live-stream', 'python'];
420+
if (executeAsAProcess) {
421+
pythonArgs.push(OUTPUT_MARKER_SCRIPT);
422+
}
423+
return pythonArgs;
420424
}
421425

422426
/**

src/client/terminals/codeExecution/djangoShellCodeExecution.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Disposable, Uri } from 'vscode';
99
import { ICommandManager, IDocumentManager, IWorkspaceService } from '../../common/application/types';
1010
import '../../common/extensions';
1111
import { IFileSystem, IPlatformService } from '../../common/platform/types';
12+
import { IPythonExecutionFactory } from '../../common/process/types';
1213
import { ITerminalServiceFactory } from '../../common/terminal/types';
1314
import { IConfigurationService, IDisposableRegistry } from '../../common/types';
1415
import { copyPythonExecInfo, PythonExecInfo } from '../../pythonEnvironments/exec';
@@ -26,8 +27,16 @@ export class DjangoShellCodeExecutionProvider extends TerminalCodeExecutionProvi
2627
@inject(ICommandManager) commandManager: ICommandManager,
2728
@inject(IFileSystem) fileSystem: IFileSystem,
2829
@inject(IDisposableRegistry) disposableRegistry: Disposable[],
30+
@inject(IPythonExecutionFactory) pythonExecutionFactory: IPythonExecutionFactory,
2931
) {
30-
super(terminalServiceFactory, configurationService, workspace, disposableRegistry, platformService);
32+
super(
33+
terminalServiceFactory,
34+
configurationService,
35+
workspace,
36+
disposableRegistry,
37+
platformService,
38+
pythonExecutionFactory,
39+
);
3140
this.terminalTitle = 'Django Shell';
3241
disposableRegistry.push(new DjangoContextInitializer(documentManager, workspace, fileSystem, commandManager));
3342
}

src/client/terminals/codeExecution/repl.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { inject, injectable } from 'inversify';
77
import { Disposable } from 'vscode';
88
import { IWorkspaceService } from '../../common/application/types';
99
import { IPlatformService } from '../../common/platform/types';
10+
import { IPythonExecutionFactory } from '../../common/process/types';
1011
import { ITerminalServiceFactory } from '../../common/terminal/types';
1112
import { IConfigurationService, IDisposableRegistry } from '../../common/types';
1213
import { TerminalCodeExecutionProvider } from './terminalCodeExecution';
@@ -19,8 +20,16 @@ export class ReplProvider extends TerminalCodeExecutionProvider {
1920
@inject(IWorkspaceService) workspace: IWorkspaceService,
2021
@inject(IDisposableRegistry) disposableRegistry: Disposable[],
2122
@inject(IPlatformService) platformService: IPlatformService,
23+
@inject(IPythonExecutionFactory) pythonExecutionFactory: IPythonExecutionFactory,
2224
) {
23-
super(terminalServiceFactory, configurationService, workspace, disposableRegistry, platformService);
25+
super(
26+
terminalServiceFactory,
27+
configurationService,
28+
workspace,
29+
disposableRegistry,
30+
platformService,
31+
pythonExecutionFactory,
32+
);
2433
this.terminalTitle = 'REPL';
2534
}
2635
}

src/client/terminals/codeExecution/terminalCodeExecution.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Disposable, Uri } from 'vscode';
99
import { IWorkspaceService } from '../../common/application/types';
1010
import '../../common/extensions';
1111
import { IPlatformService } from '../../common/platform/types';
12+
import { IPythonExecutionFactory } from '../../common/process/types';
1213
import { ITerminalService, ITerminalServiceFactory } from '../../common/terminal/types';
1314
import { IConfigurationService, IDisposableRegistry } from '../../common/types';
1415
import { buildPythonExecInfo, PythonExecInfo } from '../../pythonEnvironments/exec';
@@ -26,6 +27,7 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
2627
@inject(IWorkspaceService) protected readonly workspace: IWorkspaceService,
2728
@inject(IDisposableRegistry) protected readonly disposables: Disposable[],
2829
@inject(IPlatformService) protected readonly platformService: IPlatformService,
30+
@inject(IPythonExecutionFactory) private readonly pythonExecutionFactory: IPythonExecutionFactory,
2931
) {}
3032

3133
public async executeFile(file: Uri) {
@@ -61,11 +63,12 @@ export class TerminalCodeExecutionProvider implements ICodeExecutionService {
6163

6264
public async getExecutableInfo(resource?: Uri, args: string[] = []): Promise<PythonExecInfo> {
6365
const pythonSettings = this.configurationService.getSettings(resource);
64-
const command = this.platformService.isWindows
65-
? pythonSettings.pythonPath.replace(/\\/g, '/')
66-
: pythonSettings.pythonPath;
66+
const executionFactory = await this.pythonExecutionFactory.create({ resource, executeAsAProcess: false });
67+
const execInfo = executionFactory.getExecutionInfo();
68+
const pythonArgs = execInfo.args;
69+
const command = this.platformService.isWindows ? execInfo.command.replace(/\\/g, '/') : execInfo.command;
6770
const launchArgs = pythonSettings.terminal.launchArgs;
68-
return buildPythonExecInfo(command, [...launchArgs, ...args]);
71+
return buildPythonExecInfo(command, [...pythonArgs, ...launchArgs, ...args]);
6972
}
7073

7174
// Overridden in subclasses, see djangoShellCodeExecution.ts

src/test/terminals/codeExecution/djangoShellCodeExect.unit.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ suite('Terminal - Django Shell Code Execution', () => {
5757
commandManager.object,
5858
fileSystem.object,
5959
disposables,
60+
pythonExecutionFactory.object,
6061
);
6162

6263
terminalFactory.setup((f) => f.getTerminalService(TypeMoq.It.isAny())).returns(() => terminalService.object);

src/test/terminals/codeExecution/terminalCodeExec.unit.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ suite('Terminal - Code Execution', () => {
5959
terminalFactory = TypeMoq.Mock.ofType<ITerminalServiceFactory>();
6060
terminalSettings = TypeMoq.Mock.ofType<ITerminalSettings>();
6161
terminalService = TypeMoq.Mock.ofType<ITerminalService>();
62+
pythonExecutionFactory = TypeMoq.Mock.ofType<IPythonExecutionFactory>();
6263
const configService = TypeMoq.Mock.ofType<IConfigurationService>();
6364
workspace = TypeMoq.Mock.ofType<IWorkspaceService>();
6465
platform = TypeMoq.Mock.ofType<IPlatformService>();
6566
workspaceFolder = TypeMoq.Mock.ofType<WorkspaceFolder>();
6667
documentManager = TypeMoq.Mock.ofType<IDocumentManager>();
6768
commandManager = TypeMoq.Mock.ofType<ICommandManager>();
6869
fileSystem = TypeMoq.Mock.ofType<IFileSystem>();
69-
pythonExecutionFactory = TypeMoq.Mock.ofType<IPythonExecutionFactory>();
7070
settings = TypeMoq.Mock.ofType<IPythonSettings>();
7171
settings.setup((s) => s.terminal).returns(() => terminalSettings.object);
7272
configService.setup((c) => c.getSettings(TypeMoq.It.isAny())).returns(() => settings.object);
@@ -79,6 +79,7 @@ suite('Terminal - Code Execution', () => {
7979
workspace.object,
8080
disposables,
8181
platform.object,
82+
pythonExecutionFactory.object,
8283
);
8384
break;
8485
}
@@ -89,6 +90,7 @@ suite('Terminal - Code Execution', () => {
8990
workspace.object,
9091
disposables,
9192
platform.object,
93+
pythonExecutionFactory.object,
9294
);
9395
expectedTerminalTitle = 'REPL';
9496
break;
@@ -111,6 +113,7 @@ suite('Terminal - Code Execution', () => {
111113
commandManager.object,
112114
fileSystem.object,
113115
disposables,
116+
pythonExecutionFactory.object,
114117
);
115118
expectedTerminalTitle = 'Django Shell';
116119
break;

0 commit comments

Comments
 (0)