Skip to content

Commit a464d9c

Browse files
authored
Use a python script to launch the debugger (#2554)
* Use a python script to launch the debugger
1 parent 80af3fa commit a464d9c

File tree

7 files changed

+145
-30
lines changed

7 files changed

+145
-30
lines changed

news/2 Fixes/2509.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use a python script to launch the debugger, instead of using `-m` which requires changes to the `PYTHONPATH` variable.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Python Tools for Visual Studio
2+
# Copyright(c) Microsoft Corporation
3+
# All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the License); you may not use
6+
# this file except in compliance with the License. You may obtain a copy of the
7+
# License at http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
10+
# OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
11+
# IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
12+
# MERCHANTABLITY OR NON-INFRINGEMENT.
13+
#
14+
# See the Apache Version 2.0 License for specific language governing
15+
# permissions and limitations under the License.
16+
17+
# Source Copied from https://github.com/Microsoft/PTVS/blob/master/Python/Product/PythonTools/ptvsd_launcher.py
18+
"""
19+
Starts Debugging, expected to start with normal program
20+
to start as first argument and directory to run from as
21+
the second argument.
22+
"""
23+
24+
__author__ = "Microsoft Corporation <[email protected]>"
25+
__version__ = "3.2.0.0"
26+
27+
import os
28+
import os.path
29+
import sys
30+
import traceback
31+
32+
# Arguments are:
33+
# 1. VS debugger port to connect to.
34+
# 2. '-g' to use the installed ptvsd package, rather than bundled one.
35+
# 3. '--nodebug' to launch without debugging.
36+
# 4. '-m' or '-c' to override the default run-as mode. [optional]
37+
# 5. Startup script name.
38+
# 6. Script arguments.
39+
40+
port_num = int(sys.argv[1])
41+
del sys.argv[0:2]
42+
43+
# Use bundled ptvsd or not?
44+
bundled_ptvsd = True
45+
if sys.argv and sys.argv[0] == '-g':
46+
bundled_ptvsd = False
47+
del sys.argv[0]
48+
49+
# Use bundled ptvsd or not?
50+
no_debug = False
51+
if sys.argv and sys.argv[0] == '--nodebug':
52+
no_debug = True
53+
del sys.argv[0]
54+
55+
# set run_as mode appropriately
56+
run_as = 'script'
57+
if sys.argv and sys.argv[0] == '-m':
58+
run_as = 'module'
59+
del sys.argv[0]
60+
if sys.argv and sys.argv[0] == '-c':
61+
run_as = 'code'
62+
del sys.argv[0]
63+
64+
# preserve filename before we del sys
65+
filename = sys.argv[0]
66+
67+
# fix sys.path to be the script file dir
68+
sys.path[0] = ''
69+
70+
if not bundled_ptvsd and (sys.platform == 'cli' or sys.version_info < (2, 7) or
71+
(sys.version_info >= (3, 0) and sys.version_info < (3, 4))):
72+
# This is experimental debugger incompatibility. Exit immediately.
73+
# This process will be killed by VS since it does not see a debugger
74+
# connect to it. The exit code we will get there will be wrong.
75+
# 687: ERROR_DLL_MIGHT_BE_INCOMPATIBLE
76+
sys.exit(687)
77+
78+
# Load the debugger package
79+
try:
80+
ptvs_lib_path = None
81+
if bundled_ptvsd:
82+
ptvs_lib_path = os.path.join(os.path.dirname(__file__), 'ptvsd')
83+
sys.path.insert(0, ptvs_lib_path)
84+
try:
85+
import ptvsd
86+
import ptvsd.debugger as vspd
87+
ptvsd_loaded = True
88+
except ImportError:
89+
ptvsd_loaded = False
90+
raise
91+
vspd.DONT_DEBUG.append(os.path.normcase(__file__))
92+
except:
93+
traceback.print_exc()
94+
if not bundled_ptvsd and not ptvsd_loaded:
95+
# This is experimental debugger import error. Exit immediately.
96+
# This process will be killed by VS since it does not see a debugger
97+
# connect to it. The exit code we will get there will be wrong.
98+
# 126 : ERROR_MOD_NOT_FOUND
99+
sys.exit(126)
100+
print('''
101+
Internal error detected. Please copy the above traceback and report at
102+
https://github.com/Microsoft/vscode-python/issues/new
103+
104+
Press Enter to close. . .''')
105+
try:
106+
raw_input()
107+
except NameError:
108+
input()
109+
sys.exit(1)
110+
finally:
111+
if ptvs_lib_path:
112+
sys.path.remove(ptvs_lib_path)
113+
114+
if no_debug:
115+
vspd.run(filename, port_num, run_as, *sys.argv[1:])
116+
else:
117+
# and start debugging
118+
vspd.debug(filename, port_num, '', '', run_as)

src/client/debugger/DebugClients/LocalDebugClient.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { PathUtils } from '../../common/platform/pathUtils';
88
import { CurrentProcess } from '../../common/process/currentProcess';
99
import { EnvironmentVariablesService } from '../../common/variables/environment';
1010
import { IServiceContainer } from '../../ioc/types';
11-
import { PTVSD_PATH } from '../Common/constants';
1211
import { DebugOptions, IDebugServer, IPythonProcess, LaunchRequestArguments } from '../Common/Contracts';
1312
import { IS_WINDOWS } from '../Common/Utils';
1413
import { BaseDebugServer } from '../DebugServers/BaseDebugServer';
@@ -44,8 +43,7 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
4443
}
4544
return DebugServerStatus.Unknown;
4645
}
47-
// tslint:disable-next-line:no-any
48-
constructor(args: LaunchRequestArguments, debugSession: DebugSession, private canLaunchTerminal: boolean, private launcherScriptProvider: IDebugLauncherScriptProvider) {
46+
constructor(args: LaunchRequestArguments, debugSession: DebugSession, private canLaunchTerminal: boolean, protected launcherScriptProvider: IDebugLauncherScriptProvider) {
4947
super(args, debugSession);
5048
}
5149

@@ -82,8 +80,6 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
8280
const environmentVariablesService = new EnvironmentVariablesService(pathUtils);
8381
const helper = new DebugClientHelper(environmentVariablesService, pathUtils, currentProcess);
8482
const environmentVariables = await helper.getEnvironmentVariables(this.args);
85-
// Import the PTVSD debugger, allowing users to use their own latest copies.
86-
environmentVariablesService.appendPythonPath(environmentVariables, PTVSD_PATH);
8783
// tslint:disable-next-line:max-func-body-length cyclomatic-complexity no-any
8884
return new Promise<any>((resolve, reject) => {
8985
const fileDir = this.args && this.args.program ? path.dirname(this.args.program) : '';

src/client/debugger/DebugClients/launcherProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
// tslint:disable:max-classes-per-file
77

88
import * as path from 'path';
9+
import { EXTENSION_ROOT_DIR } from '../../common/constants';
910
import { IDebugLauncherScriptProvider } from '../types';
1011

1112
export class NoDebugLauncherScriptProvider implements IDebugLauncherScriptProvider {
1213
public getLauncherFilePath(): string {
13-
return path.join(path.dirname(__dirname), '..', '..', '..', 'pythonFiles', 'PythonTools', 'visualstudio_py_launcher_nodebug.py');
14+
return path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
1415
}
1516
}
1617

1718
export class DebuggerLauncherScriptProvider implements IDebugLauncherScriptProvider {
1819
public getLauncherFilePath(): string {
19-
return path.join(path.dirname(__dirname), '..', '..', '..', 'pythonFiles', 'PythonTools', 'visualstudio_py_launcher.py');
20+
return path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
2021
}
2122
}

src/client/debugger/DebugClients/localDebugClientV2.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ export class LocalDebugClientV2 extends LocalDebugClient {
1313
super(args, debugSession, canLaunchTerminal, launcherScriptProvider);
1414
}
1515
protected buildDebugArguments(cwd: string, debugPort: number): string[] {
16+
const launcher = this.launcherScriptProvider.getLauncherFilePath();
1617
const noDebugArg = this.args.noDebug ? ['--nodebug'] : [];
17-
return ['-m', 'ptvsd', ...noDebugArg, '--host', 'localhost', '--port', debugPort.toString()];
18+
return [launcher, debugPort.toString(), ...noDebugArg];
1819
}
1920
protected buildStandardArguments() {
2021
const programArgs = Array.isArray(this.args.args) && this.args.args.length > 0 ? this.args.args : [];

src/test/debugger/launcherScriptProvider.test.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { expect } from 'chai';
5+
import * as path from 'path';
6+
import { EXTENSION_ROOT_DIR } from '../../client/common/constants';
7+
import { DebuggerLauncherScriptProvider, NoDebugLauncherScriptProvider } from '../../client/debugger/DebugClients/launcherProvider';
8+
9+
suite('Debugger - Launcher Script Provider', () => {
10+
test('Ensure debugger gets the launcher from PythonTools directory', () => {
11+
const launcherPath = new DebuggerLauncherScriptProvider().getLauncherFilePath();
12+
const expectedPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
13+
expect(launcherPath).to.be.equal(expectedPath);
14+
});
15+
test('Ensure debugger gets the non debug launcher from PythonTools directory', () => {
16+
const launcherPath = new NoDebugLauncherScriptProvider().getLauncherFilePath();
17+
const expectedPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
18+
expect(launcherPath).to.be.equal(expectedPath);
19+
});
20+
});

0 commit comments

Comments
 (0)