Skip to content

Commit 157f392

Browse files
authored
Running python code without debugging using the experimental debugger (microsoft#1373)
Fixes microsoft#882 Remove python file used to launch the PTVSD debugger Added ability to run code without debugging using PTVSD Launching PTVSD using -m (run as a python module)
1 parent 62d7b38 commit 157f392

10 files changed

Lines changed: 220 additions & 122 deletions

File tree

pythonFiles/experimental/ptvsd_launcher.py

Lines changed: 0 additions & 96 deletions
This file was deleted.

src/client/debugger/DebugClients/DebugFactory.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
import { DebugSession } from 'vscode-debugadapter';
22
import { AttachRequestArguments, LaunchRequestArguments } from '../Common/Contracts';
3+
import { IDebugLauncherScriptProvider } from '../types';
34
import { DebugClient } from './DebugClient';
4-
import { DebuggerLauncherScriptProvider, DebuggerV2LauncherScriptProvider, NoDebugLauncherScriptProvider } from './launcherProvider';
5+
import { DebuggerLauncherScriptProvider, NoDebugLauncherScriptProvider } from './launcherProvider';
56
import { LocalDebugClient } from './LocalDebugClient';
7+
import { LocalDebugClientV2 } from './localDebugClientV2';
68
import { NonDebugClient } from './NonDebugClient';
9+
import { NonDebugClientV2 } from './nonDebugClientV2';
710
import { RemoteDebugClient } from './RemoteDebugClient';
811

912
export function CreateLaunchDebugClient(launchRequestOptions: LaunchRequestArguments, debugSession: DebugSession, canLaunchTerminal: boolean): DebugClient<{}> {
13+
let launchScriptProvider: IDebugLauncherScriptProvider;
14+
let debugClientClass: typeof LocalDebugClient;
1015
if (launchRequestOptions.noDebug === true) {
11-
return new NonDebugClient(launchRequestOptions, debugSession, canLaunchTerminal, new NoDebugLauncherScriptProvider());
16+
launchScriptProvider = new NoDebugLauncherScriptProvider();
17+
debugClientClass = launchRequestOptions.type === 'pythonExperimental' ? NonDebugClientV2 : NonDebugClient;
18+
} else {
19+
launchScriptProvider = new DebuggerLauncherScriptProvider();
20+
debugClientClass = launchRequestOptions.type === 'pythonExperimental' ? LocalDebugClientV2 : LocalDebugClient;
1221
}
13-
const launchScriptProvider = launchRequestOptions.type === 'pythonExperimental' ? new DebuggerV2LauncherScriptProvider() : new DebuggerLauncherScriptProvider();
14-
return new LocalDebugClient(launchRequestOptions, debugSession, canLaunchTerminal, launchScriptProvider);
22+
return new debugClientClass(launchRequestOptions, debugSession, canLaunchTerminal, launchScriptProvider);
1523
}
1624
export function CreateAttachDebugClient(attachRequestOptions: AttachRequestArguments, debugSession: DebugSession): DebugClient<{}> {
1725
return new RemoteDebugClient(attachRequestOptions, debugSession);

src/client/debugger/DebugClients/LocalDebugClient.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
101101
if (typeof this.args.pythonPath === 'string' && this.args.pythonPath.trim().length > 0) {
102102
pythonPath = this.args.pythonPath;
103103
}
104-
const ptVSToolsFilePath = this.launcherScriptProvider.getLauncherFilePath();
105-
const launcherArgs = this.buildLauncherArguments();
106-
107-
const args = [ptVSToolsFilePath, processCwd, dbgServer.port.toString(), '34806ad9-833a-4524-8cd6-18ca4aa74f14'].concat(launcherArgs);
104+
const args = this.buildLaunchArguments(processCwd, dbgServer.port);
108105
switch (this.args.console) {
109106
case 'externalTerminal':
110107
case 'integratedTerminal': {
@@ -161,8 +158,13 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
161158
let x = 0;
162159
});
163160
}
161+
private buildLaunchArguments(cwd: string, debugPort: number): string[] {
162+
return [...this.buildDebugArguments(cwd, debugPort), ...this.buildStandardArguments()];
163+
}
164+
164165
// tslint:disable-next-line:member-ordering
165-
protected buildLauncherArguments(): string[] {
166+
protected buildDebugArguments(cwd: string, debugPort: number): string[] {
167+
const ptVSToolsFilePath = this.launcherScriptProvider.getLauncherFilePath();
166168
const vsDebugOptions: string[] = [DebugOptions.RedirectOutput];
167169
if (Array.isArray(this.args.debugOptions)) {
168170
this.args.debugOptions.filter(opt => VALID_DEBUG_OPTIONS.indexOf(opt) >= 0)
@@ -173,15 +175,18 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
173175
if (djangoIndex >= 0) {
174176
vsDebugOptions[djangoIndex] = 'DjangoDebugging';
175177
}
178+
return [ptVSToolsFilePath, cwd, debugPort.toString(), '34806ad9-833a-4524-8cd6-18ca4aa74f14', vsDebugOptions.join(',')];
179+
}
180+
// tslint:disable-next-line:member-ordering
181+
protected buildStandardArguments() {
176182
const programArgs = Array.isArray(this.args.args) && this.args.args.length > 0 ? this.args.args : [];
177183
if (typeof this.args.module === 'string' && this.args.module.length > 0) {
178-
return [vsDebugOptions.join(','), '-m', this.args.module].concat(programArgs);
184+
return ['-m', this.args.module, ...programArgs];
179185
}
180-
const args = [vsDebugOptions.join(',')];
181186
if (this.args.program && this.args.program.length > 0) {
182-
args.push(this.args.program);
187+
return [this.args.program, ...programArgs];
183188
}
184-
return args.concat(programArgs);
189+
return programArgs;
185190
}
186191
private launchExternalTerminal(sudo: boolean, cwd: string, pythonPath: string, args: string[], env: {}) {
187192
return new Promise((resolve, reject) => {

src/client/debugger/DebugClients/launcherProvider.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
'use strict';
5+
6+
// tslint:disable:max-classes-per-file
7+
48
import * as path from 'path';
59
import { IDebugLauncherScriptProvider } from '../types';
610

@@ -15,9 +19,3 @@ export class DebuggerLauncherScriptProvider implements IDebugLauncherScriptProvi
1519
return path.join(path.dirname(__dirname), '..', '..', '..', 'pythonFiles', 'PythonTools', 'visualstudio_py_launcher.py');
1620
}
1721
}
18-
19-
export class DebuggerV2LauncherScriptProvider implements IDebugLauncherScriptProvider {
20-
public getLauncherFilePath(): string {
21-
return path.join(path.dirname(__dirname), '..', '..', '..', 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
22-
}
23-
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { DebugSession } from 'vscode-debugadapter';
7+
import { LaunchRequestArguments } from '../Common/Contracts';
8+
import { IDebugLauncherScriptProvider } from '../types';
9+
import { LocalDebugClient } from './LocalDebugClient';
10+
11+
export class LocalDebugClientV2 extends LocalDebugClient {
12+
constructor(args: LaunchRequestArguments, debugSession: DebugSession, canLaunchTerminal: boolean, launcherScriptProvider: IDebugLauncherScriptProvider) {
13+
super(args, debugSession, canLaunchTerminal, launcherScriptProvider);
14+
}
15+
protected buildDebugArguments(cwd: string, debugPort: number): string[] {
16+
const noDebugArg = this.args.noDebug ? ['--nodebug'] : [];
17+
return ['-m', 'ptvsd', ...noDebugArg, '--host', 'localhost', '--port', debugPort.toString()];
18+
}
19+
protected buildStandardArguments() {
20+
const programArgs = Array.isArray(this.args.args) && this.args.args.length > 0 ? this.args.args : [];
21+
if (typeof this.args.module === 'string' && this.args.module.length > 0) {
22+
return ['-m', this.args.module, ...programArgs];
23+
}
24+
if (this.args.program && this.args.program.length > 0) {
25+
return ['--file', this.args.program, ...programArgs];
26+
}
27+
return programArgs;
28+
}
29+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { ChildProcess } from 'child_process';
7+
import { DebugSession } from 'vscode-debugadapter';
8+
import { LaunchRequestArguments } from '../Common/Contracts';
9+
import { IDebugLauncherScriptProvider } from '../types';
10+
import { DebugType } from './DebugClient';
11+
import { LocalDebugClientV2 } from './localDebugClientV2';
12+
13+
export class NonDebugClientV2 extends LocalDebugClientV2 {
14+
constructor(args: LaunchRequestArguments, debugSession: DebugSession, canLaunchTerminal: boolean, launcherScriptProvider: IDebugLauncherScriptProvider) {
15+
super(args, debugSession, canLaunchTerminal, launcherScriptProvider);
16+
}
17+
18+
public get DebugType(): DebugType {
19+
return DebugType.RunLocal;
20+
}
21+
22+
public Stop() {
23+
super.Stop();
24+
if (this.pyProc) {
25+
try {
26+
this.pyProc!.kill();
27+
// tslint:disable-next-line:no-empty
28+
} catch { }
29+
this.pyProc = undefined;
30+
}
31+
}
32+
protected handleProcessOutput(proc: ChildProcess, _failedToLaunch: (error: Error | string | Buffer) => void) {
33+
// Do nothing
34+
}
35+
}

src/client/debugger/mainV2.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { DebugProtocol } from 'vscode-debugprotocol';
2121
import '../../client/common/extensions';
2222
import { noop, sleep } from '../common/core.utils';
2323
import { createDeferred, Deferred, isNotInstalledError } from '../common/helpers';
24+
import { IFileSystem } from '../common/platform/types';
2425
import { ICurrentProcess } from '../common/types';
2526
import { IServiceContainer } from '../ioc/types';
2627
import { AttachRequestArguments, LaunchRequestArguments } from './Common/Contracts';
@@ -98,6 +99,10 @@ export class PythonDebugger extends DebugSession {
9899

99100
}
100101
protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
102+
const fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
103+
if ((typeof args.module !== 'string' || args.module.length === 0) && args.program && !fs.fileExistsSync(args.program)) {
104+
return this.sendErrorResponse(response, { format: `File does not exist. "${args.program}"`, id: 1 }, undefined, undefined, ErrorDestination.User);
105+
}
101106
this.launchPTVSD(args)
102107
.then(() => this.waitForPTVSDToConnect(args))
103108
.then(() => this.emit('debugger_launched'))

src/test/debugger/launcherScriptProvider.test.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { expect } from 'chai';
55
import * as fs from 'fs';
66
import * as path from 'path';
7-
import { DebuggerLauncherScriptProvider, DebuggerV2LauncherScriptProvider, NoDebugLauncherScriptProvider } from '../../client/debugger/DebugClients/launcherProvider';
7+
import { DebuggerLauncherScriptProvider, NoDebugLauncherScriptProvider } from '../../client/debugger/DebugClients/launcherProvider';
88

99
suite('Debugger - Launcher Script Provider', () => {
1010
test('Ensure stable debugger gets the old launcher from PythonTools directory', () => {
@@ -19,10 +19,4 @@ suite('Debugger - Launcher Script Provider', () => {
1919
expect(launcherPath).to.be.equal(expectedPath);
2020
expect(fs.existsSync(launcherPath)).to.be.equal(true, 'file does not exist');
2121
});
22-
test('Ensure experimental debugger gets the new launcher from experimentals directory', () => {
23-
const launcherPath = new DebuggerV2LauncherScriptProvider().getLauncherFilePath();
24-
const expectedPath = path.join(path.dirname(__dirname), '..', '..', 'pythonFiles', 'experimental', 'ptvsd_launcher.py');
25-
expect(launcherPath).to.be.equal(expectedPath);
26-
expect(fs.existsSync(launcherPath)).to.be.equal(true, 'file does not exist');
27-
});
2822
});

0 commit comments

Comments
 (0)