Skip to content

Commit 2a15f4d

Browse files
committed
fix #688
1 parent 415e20c commit 2a15f4d

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/client/debugger/Common/Utils.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import {IPythonProcess, IPythonThread, IPythonModule, IPythonEvaluationResult} from "./Contracts";
44
import * as path from "path";
55
import * as fs from 'fs';
6+
import * as child_process from 'child_process';
7+
8+
export const IS_WINDOWS = /^win/.test(process.platform);
9+
export const PATH_VARIABLE_NAME = IS_WINDOWS ? 'Path' : 'PATH';
610

711
const PathValidity: Map<string, boolean> = new Map<string, boolean>();
812
export function validatePath(filePath: string): Promise<string> {
@@ -66,3 +70,45 @@ export function FixupEscapedUnicodeChars(value: string): string {
6670
return value;
6771
}
6872

73+
export function getPythonExecutable(pythonPath: string): string {
74+
// If only 'python'
75+
if (pythonPath === 'python' ||
76+
pythonPath.indexOf(path.sep) === -1 ||
77+
path.basename(pythonPath) === path.dirname(pythonPath)) {
78+
return pythonPath;
79+
}
80+
81+
if (isValidPythonPath(pythonPath)) {
82+
return pythonPath;
83+
}
84+
85+
// Suffix with 'python' for linux and 'osx', and 'python.exe' for 'windows'
86+
if (IS_WINDOWS) {
87+
if (isValidPythonPath(path.join(pythonPath, 'python.exe'))) {
88+
return path.join(pythonPath, 'python.exe');
89+
}
90+
if (isValidPythonPath(path.join(pythonPath, 'scripts', 'python.exe'))) {
91+
return path.join(pythonPath, 'scripts', 'python.exe');
92+
}
93+
}
94+
else {
95+
if (isValidPythonPath(path.join(pythonPath, 'python'))) {
96+
return path.join(pythonPath, 'python');
97+
}
98+
if (isValidPythonPath(path.join(pythonPath, 'bin', 'python'))) {
99+
return path.join(pythonPath, 'bin', 'python');
100+
}
101+
}
102+
103+
return pythonPath;
104+
}
105+
106+
function isValidPythonPath(pythonPath): boolean {
107+
try {
108+
let output = child_process.execFileSync(pythonPath, ['-c', 'print(1234)'], { encoding: 'utf8' });
109+
return output.startsWith('1234');
110+
}
111+
catch (ex) {
112+
return false;
113+
}
114+
}

src/client/debugger/Main.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { DebugClient, DebugType } from "./DebugClients/DebugClient";
1919
import { CreateAttachDebugClient, CreateLaunchDebugClient } from "./DebugClients/DebugFactory";
2020
import { DjangoApp, LaunchRequestArguments, AttachRequestArguments, DebugFlags, DebugOptions, TelemetryEvent, PythonEvaluationResultFlags } from "./Common/Contracts";
2121
import * as telemetryContracts from "../common/telemetryContracts";
22-
import { validatePath, validatePathSync } from './Common/Utils';
22+
import { validatePath, validatePathSync, getPythonExecutable } from './Common/Utils';
2323
import { isNotInstalledError } from '../common/helpers';
2424

2525
const CHILD_ENUMEARATION_TIMEOUT = 5000;
@@ -200,6 +200,14 @@ export class PythonDebugger extends DebugSession {
200200
Debug_HasEnvVaraibles: args.env && typeof args.env === "object" ? "true" : "false"
201201
}));
202202

203+
// Add support for specifying just the directory where the python executable will be located
204+
// E.g. virtual directory name
205+
try {
206+
args.pythonPath = getPythonExecutable(args.pythonPath);
207+
}
208+
catch (ex) {
209+
}
210+
203211
this.launchArgs = args;
204212
this.debugClient = CreateLaunchDebugClient(args, this);
205213
//this.debugClient.on('exit', () => this.sendEvent(new TerminatedEvent()));

0 commit comments

Comments
 (0)