Skip to content

Commit 2d74b6c

Browse files
author
Kartik Raj
committed
Refactor
1 parent bfe68ea commit 2d74b6c

File tree

6 files changed

+42
-29
lines changed

6 files changed

+42
-29
lines changed

src/client/application/diagnostics/checks/pythonInterpreter.ts

+35-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { inject, injectable } from 'inversify';
66
import { DiagnosticSeverity, l10n } from 'vscode';
77
import '../../../common/extensions';
88
import * as path from 'path';
9-
import { IDisposableRegistry, IInterpreterPathService, Resource } from '../../../common/types';
9+
import { IConfigurationService, IDisposableRegistry, IInterpreterPathService, Resource } from '../../../common/types';
1010
import { IInterpreterService } from '../../../interpreter/contracts';
1111
import { IServiceContainer } from '../../../ioc/types';
1212
import { BaseDiagnostic, BaseDiagnosticsService } from '../base';
@@ -28,10 +28,11 @@ import { EventName } from '../../../telemetry/constants';
2828
import { IExtensionSingleActivationService } from '../../../activation/types';
2929
import { cache } from '../../../common/utils/decorators';
3030
import { noop } from '../../../common/utils/misc';
31-
import { IPythonExecutionFactory } from '../../../common/process/types';
3231
import { getOSType, OSType } from '../../../common/utils/platform';
3332
import { IFileSystem } from '../../../common/platform/types';
3433
import { traceError } from '../../../logging';
34+
import { getExecutable } from '../../../common/process/internal/python';
35+
import { shellExec } from '../../../common/process/rawProcessApis';
3536

3637
const messages = {
3738
[DiagnosticCodes.NoPythonInterpretersDiagnostic]: l10n.t(
@@ -41,7 +42,7 @@ const messages = {
4142
'An Invalid Python interpreter is selected{0}, please try changing it to enable features such as IntelliSense, linting, and debugging. See output for more details regarding why the interpreter is invalid.',
4243
),
4344
[DiagnosticCodes.InvalidComspecDiagnostic]: l10n.t(
44-
"The environment variable 'Comspec' seems to be set to an invalid value. Please correct it to carry valid path to Command Prompt to enable features such as IntelliSense, linting, and debugging. See instructions which might help.",
45+
'We detected an issue with one of your environment variables that breaks features such as IntelliSense, linting and debugging. Try setting the "ComSpec" to a valid Command Prompt path in your system to fix it.',
4546
),
4647
};
4748

@@ -112,20 +113,16 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
112113
);
113114
}
114115

115-
// eslint-disable-next-line class-methods-use-this
116-
public async diagnose(_resource: Resource): Promise<IDiagnostic[]> {
117-
return [];
116+
public async diagnose(resource: Resource): Promise<IDiagnostic[]> {
117+
return this.diagnoseDefaultShell(resource);
118118
}
119119

120120
public async _manualDiagnose(resource: Resource): Promise<IDiagnostic[]> {
121121
const workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
122122
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
123-
const currentInterpreter = await interpreterService.getActiveInterpreter(resource);
124-
if (!currentInterpreter) {
125-
const diagnostics = await this.diagnoseDefaultShell(resource);
126-
if (diagnostics.length) {
127-
return diagnostics;
128-
}
123+
const diagnostics = await this.diagnoseDefaultShell(resource);
124+
if (diagnostics.length) {
125+
return diagnostics;
129126
}
130127
const hasInterpreters = await interpreterService.hasInterpreters();
131128
const interpreterPathService = this.serviceContainer.get<IInterpreterPathService>(IInterpreterPathService);
@@ -142,6 +139,7 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
142139
];
143140
}
144141

142+
const currentInterpreter = await interpreterService.getActiveInterpreter(resource);
145143
if (!currentInterpreter) {
146144
return [
147145
new InvalidPythonInterpreterDiagnostic(
@@ -189,7 +187,7 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
189187
if (diagnostic.code === DiagnosticCodes.InvalidComspecDiagnostic) {
190188
return [
191189
{
192-
prompt: Common.instructions,
190+
prompt: Common.seeInstructions,
193191
command: commandFactory.createCommand(diagnostic, {
194192
type: 'launch',
195193
options: 'https://aka.ms/AAk3djo',
@@ -222,12 +220,16 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
222220
if (getOSType() !== OSType.Windows) {
223221
return [];
224222
}
225-
const executionFactory = this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory);
226-
const executionService = await executionFactory.create({ resource });
223+
const interpreterService = this.serviceContainer.get<IInterpreterService>(IInterpreterService);
224+
const currentInterpreter = await interpreterService.getActiveInterpreter(resource);
225+
if (currentInterpreter) {
226+
return [];
227+
}
227228
try {
228-
await executionService.getExecutablePath({ throwOnError: true });
229+
await this.shellExecPython();
229230
} catch (ex) {
230-
if ((ex as Error).message?.includes('4058')) {
231+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
232+
if ((ex as any).errno === -4058) {
231233
// ENOENT (-4058) error is thrown by Node when the default shell is invalid.
232234
if (await this.isComspecInvalid()) {
233235
traceError('ComSpec is set to an invalid value', process.env.ComSpec);
@@ -241,7 +243,22 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
241243
private async isComspecInvalid() {
242244
const comSpec = process.env.ComSpec ?? '';
243245
const fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
244-
return fs.fileExists(comSpec);
246+
return fs.fileExists(comSpec).then((exists) => !exists);
247+
}
248+
249+
@cache(-1, true)
250+
// eslint-disable-next-line class-methods-use-this
251+
private async shellExecPython() {
252+
const configurationService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
253+
const { pythonPath } = configurationService.getSettings();
254+
const [args] = getExecutable();
255+
const argv = [pythonPath, ...args];
256+
// Concat these together to make a set of quoted strings
257+
const quoted = argv.reduce(
258+
(p, c) => (p ? `${p} ${c.toCommandArgumentForPythonExt()}` : `${c.toCommandArgumentForPythonExt()}`),
259+
'',
260+
);
261+
return shellExec(quoted, { timeout: 15000 });
245262
}
246263
}
247264

src/client/common/process/pythonEnvironment.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class PythonEnvironment implements IPythonEnvironment {
4747
return this.cachedInterpreterInformation;
4848
}
4949

50-
public async getExecutablePath(options?: { throwOnError?: boolean }): Promise<string | undefined> {
50+
public async getExecutablePath(): Promise<string | undefined> {
5151
// If we've passed the python file, then return the file.
5252
// This is because on mac if using the interpreter /usr/bin/python2.7 we can get a different value for the path
5353
if (await this.deps.isValidExecutable(this.pythonPath)) {
@@ -59,7 +59,7 @@ class PythonEnvironment implements IPythonEnvironment {
5959
return result;
6060
}
6161
const python = this.getExecutionInfo();
62-
const promise = getExecutablePath(python, this.deps.shellExec, options);
62+
const promise = getExecutablePath(python, this.deps.shellExec);
6363
cachedExecutablePath.set(this.pythonPath, promise);
6464
return promise;
6565
}

src/client/common/process/pythonExecutionFactory.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ function createPythonService(procService: IProcessService, env: IPythonEnvironme
145145
const procs = createPythonProcessService(procService, env);
146146
return {
147147
getInterpreterInformation: () => env.getInterpreterInformation(),
148-
getExecutablePath: (options?: { throwOnError?: boolean }) => env.getExecutablePath(options),
148+
getExecutablePath: () => env.getExecutablePath(),
149149
isModuleInstalled: (m) => env.isModuleInstalled(m),
150150
getModuleVersion: (m) => env.getModuleVersion(m),
151151
getExecutionInfo: (a) => env.getExecutionInfo(a),

src/client/common/process/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const IPythonExecutionService = Symbol('IPythonExecutionService');
8484

8585
export interface IPythonExecutionService {
8686
getInterpreterInformation(): Promise<InterpreterInformation | undefined>;
87-
getExecutablePath(options?: { throwOnError?: boolean }): Promise<string | undefined>;
87+
getExecutablePath(): Promise<string | undefined>;
8888
isModuleInstalled(moduleName: string): Promise<boolean>;
8989
getModuleVersion(moduleName: string): Promise<string | undefined>;
9090
getExecutionInfo(pythonArgs?: string[]): PythonExecInfo;
@@ -100,7 +100,7 @@ export interface IPythonExecutionService {
100100
export interface IPythonEnvironment {
101101
getInterpreterInformation(): Promise<InterpreterInformation | undefined>;
102102
getExecutionObservableInfo(pythonArgs?: string[], pythonExecutable?: string): PythonExecInfo;
103-
getExecutablePath(options?: { throwOnError?: boolean }): Promise<string | undefined>;
103+
getExecutablePath(): Promise<string | undefined>;
104104
isModuleInstalled(moduleName: string): Promise<boolean>;
105105
getModuleVersion(moduleName: string): Promise<string | undefined>;
106106
getExecutionInfo(pythonArgs?: string[], pythonExecutable?: string): PythonExecInfo;

src/client/common/utils/localize.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export namespace Diagnostics {
4949

5050
export namespace Common {
5151
export const allow = l10n.t('Allow');
52-
export const instructions = l10n.t('Instructions');
52+
export const seeInstructions = l10n.t('See Instructions');
5353
export const close = l10n.t('Close');
5454
export const bannerLabelYes = l10n.t('Yes');
5555
export const bannerLabelNo = l10n.t('No');

src/client/pythonEnvironments/info/executable.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ import { copyPythonExecInfo, PythonExecInfo } from '../exec';
1414
* @param python - the information to use when running Python
1515
* @param shellExec - the function to use to run Python
1616
*/
17-
export async function getExecutablePath(
18-
python: PythonExecInfo,
19-
shellExec: ShellExecFunc,
20-
options?: { throwOnError?: boolean },
21-
): Promise<string | undefined> {
17+
export async function getExecutablePath(python: PythonExecInfo, shellExec: ShellExecFunc): Promise<string | undefined> {
2218
try {
2319
const [args, parse] = getExecutable();
2420
const info = copyPythonExecInfo(python, args);

0 commit comments

Comments
 (0)