Skip to content

Commit d3afab4

Browse files
Merge branch 'main' into update-readme
2 parents 02b6a5d + e1be8cc commit d3afab4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+6548
-8
lines changed

.vscode/tasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{
77
"type": "npm",
88
"script": "watch",
9-
"problemMatcher": "$ts-webpack-watch",
9+
"problemMatcher": "$tsc-watch",
1010
"isBackground": true,
1111
"presentation": {
1212
"reveal": "never",

icon.png

47.5 KB
Loading

package-lock.json

Lines changed: 24 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "debugpy",
33
"displayName": "Debugpy",
44
"description": "Python Debugger extension using `debugpy`.",
5-
"version": "0.0.1",
5+
"version": "2023.1.0-dev",
66
"publisher": "ms-python",
77
"license": "MIT",
88
"homepage": "https://github.com/Microsoft/vscode-python-debugger",
@@ -13,6 +13,7 @@
1313
"bugs": {
1414
"url": "https://github.com/Microsoft/vscode-python-debugger/issues"
1515
},
16+
"icon": "icon.png",
1617
"keywords": [
1718
"python",
1819
"debugger",
@@ -468,6 +469,7 @@
468469
"dependencies": {
469470
"@vscode/extension-telemetry": "^0.7.4-preview",
470471
"fs-extra": "^11.1.0",
472+
"iconv-lite": "^0.6.3",
471473
"inversify": "^6.0.1",
472474
"jsonc-parser": "^3.2.0",
473475
"lodash": "^4.17.21",

src/test/ciConstants.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
//
7+
// Constants that pertain to CI processes/tests only. No dependencies on vscode!
8+
//
9+
export const PYTHON_VIRTUAL_ENVS_LOCATION = process.env.PYTHON_VIRTUAL_ENVS_LOCATION;
10+
export const IS_APPVEYOR = process.env.APPVEYOR === 'true';
11+
export const IS_TRAVIS = process.env.TRAVIS === 'true';
12+
export const IS_VSTS = process.env.TF_BUILD !== undefined;
13+
export const IS_GITHUB_ACTIONS = process.env.GITHUB_ACTIONS === 'true';
14+
export const IS_CI_SERVER = IS_TRAVIS || IS_APPVEYOR || IS_VSTS || IS_GITHUB_ACTIONS;
15+
16+
// Control JUnit-style output logging for reporting purposes.
17+
let reportJunit: boolean = false;
18+
if (IS_CI_SERVER && process.env.MOCHA_REPORTER_JUNIT !== undefined) {
19+
reportJunit = process.env.MOCHA_REPORTER_JUNIT.toLowerCase() === 'true';
20+
}
21+
export const MOCHA_REPORTER_JUNIT: boolean = reportJunit;
22+
export const IS_CI_SERVER_TEST_DEBUGGER = process.env.IS_CI_SERVER_TEST_DEBUGGER === '1';

src/test/common.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
'use strict';
4+
5+
// IMPORTANT: Do not import anything from the 'client' folder in this file as that folder is not available during smoke tests.
6+
7+
import * as fs from 'fs-extra';
8+
import { ConfigurationTarget, TextDocument, Uri } from 'vscode';
9+
import { IS_MULTI_ROOT_TEST } from './constants';
10+
import { IExtensionApi } from '../extension/apiTypes';
11+
import { assert } from 'chai';
12+
13+
export const PYTHON_PATH = getPythonPath();
14+
15+
export async function clearPythonPathInWorkspaceFolder(resource: string | Uri) {
16+
const vscode = require('vscode') as typeof import('vscode');
17+
return retryAsync(setPythonPathInWorkspace)(resource, vscode.ConfigurationTarget.WorkspaceFolder);
18+
}
19+
20+
export async function setPythonPathInWorkspaceRoot(pythonPath: string) {
21+
const vscode = require('vscode') as typeof import('vscode');
22+
return retryAsync(setPythonPathInWorkspace)(undefined, vscode.ConfigurationTarget.Workspace, pythonPath);
23+
}
24+
25+
export const resetGlobalPythonPathSetting = async () => retryAsync(restoreGlobalPythonPathSetting)();
26+
27+
export async function openFile(file: string): Promise<TextDocument> {
28+
const vscode = require('vscode') as typeof import('vscode');
29+
const textDocument = await vscode.workspace.openTextDocument(file);
30+
await vscode.window.showTextDocument(textDocument);
31+
assert(vscode.window.activeTextEditor, 'No active editor');
32+
return textDocument;
33+
}
34+
35+
export function retryAsync(this: any, wrapped: Function, retryCount: number = 2) {
36+
return async (...args: any[]) => {
37+
return new Promise((resolve, reject) => {
38+
const reasons: any[] = [];
39+
40+
const makeCall = () => {
41+
wrapped.call(this as Function, ...args).then(resolve, (reason: any) => {
42+
reasons.push(reason);
43+
if (reasons.length >= retryCount) {
44+
reject(reasons);
45+
} else {
46+
// If failed once, lets wait for some time before trying again.
47+
setTimeout(makeCall, 500);
48+
}
49+
});
50+
};
51+
52+
makeCall();
53+
});
54+
};
55+
}
56+
57+
async function setPythonPathInWorkspace(
58+
resource: string | Uri | undefined,
59+
config: ConfigurationTarget,
60+
pythonPath?: string,
61+
) {
62+
const vscode = require('vscode') as typeof import('vscode');
63+
if (config === vscode.ConfigurationTarget.WorkspaceFolder && !IS_MULTI_ROOT_TEST) {
64+
return;
65+
}
66+
const resourceUri = typeof resource === 'string' ? vscode.Uri.file(resource) : resource;
67+
const settings = vscode.workspace.getConfiguration('python', resourceUri || null);
68+
const value = settings.inspect<string>('defaultInterpreterPath');
69+
const prop: 'workspaceFolderValue' | 'workspaceValue' =
70+
config === vscode.ConfigurationTarget.Workspace ? 'workspaceValue' : 'workspaceFolderValue';
71+
if (value && value[prop] !== pythonPath) {
72+
await settings.update('defaultInterpreterPath', pythonPath, config);
73+
// await disposePythonSettings();
74+
}
75+
}
76+
async function restoreGlobalPythonPathSetting(): Promise<void> {
77+
const vscode = require('vscode') as typeof import('vscode');
78+
const pythonConfig = vscode.workspace.getConfiguration('python', null as any as Uri);
79+
await Promise.all([
80+
pythonConfig.update('defaultInterpreterPath', undefined, true),
81+
pythonConfig.update('defaultInterpreterPath', undefined, true),
82+
]);
83+
// await disposePythonSettings();
84+
}
85+
86+
function getPythonPath(): string {
87+
if (process.env.CI_PYTHON_PATH && fs.existsSync(process.env.CI_PYTHON_PATH)) {
88+
return process.env.CI_PYTHON_PATH;
89+
}
90+
91+
// TODO: Change this to python3.
92+
// See https://github.com/microsoft/vscode-python/issues/10910.
93+
return 'python';
94+
}
95+
96+
export interface IExtensionTestApi extends IExtensionApi {}

src/test/constants.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as path from 'path';
5+
import { IS_CI_SERVER, IS_CI_SERVER_TEST_DEBUGGER } from './ciConstants';
6+
7+
// Activating extension for Multiroot and Debugger CI tests for Windows takes just over 2 minutes sometimes, so 3 minutes seems like a safe margin
8+
export const MAX_EXTENSION_ACTIVATION_TIME = 180_000;
9+
export const TEST_TIMEOUT = 60_000;
10+
export const TEST_RETRYCOUNT = 3;
11+
export const IS_SMOKE_TEST = process.env.VSC_PYTHON_SMOKE_TEST === '1';
12+
export const IS_PERF_TEST = process.env.VSC_PYTHON_PERF_TEST === '1';
13+
export const IS_MULTI_ROOT_TEST = isMultitrootTest();
14+
15+
// If running on CI server, then run debugger tests ONLY if the corresponding flag is enabled.
16+
export const TEST_DEBUGGER = IS_CI_SERVER ? IS_CI_SERVER_TEST_DEBUGGER : true;
17+
18+
function isMultitrootTest() {
19+
// No need to run smoke nor perf tests in a multi-root environment.
20+
if (IS_SMOKE_TEST || IS_PERF_TEST) {
21+
return false;
22+
}
23+
try {
24+
const vscode = require('vscode');
25+
const workspace = vscode.workspace;
26+
return Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 1;
27+
} catch {
28+
// being accessed, when VS Code hasn't been launched.
29+
return false;
30+
}
31+
}
32+
33+
export const EXTENSION_ROOT_DIR_FOR_TESTS = path.join(__dirname, '..', '..');
34+
export const PVSC_EXTENSION_ID_FOR_TESTS = 'ms-python.python';
35+
36+
export const SMOKE_TEST_EXTENSIONS_DIR = path.join(
37+
EXTENSION_ROOT_DIR_FOR_TESTS,
38+
'tmp',
39+
'ext',
40+
'smokeTestExtensionsFolder',
41+
);

src/test/core.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
// File without any dependencies on VS Code.
7+
8+
export async function sleep(milliseconds: number) {
9+
return new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
10+
}
11+
12+
export function noop() {}
13+
14+
export const isWindows = /^win/.test(process.platform);

src/test/fixtures.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as fs from 'fs-extra';
5+
import { PYTHON_PATH } from './common';
6+
import { sleep } from './core';
7+
import { Proc, spawn } from './proc';
8+
9+
export type CleanupFunc = (() => void) | (() => Promise<void>);
10+
11+
export class CleanupFixture {
12+
private cleanups: CleanupFunc[];
13+
constructor() {
14+
this.cleanups = [];
15+
}
16+
17+
public addCleanup(cleanup: CleanupFunc) {
18+
this.cleanups.push(cleanup);
19+
}
20+
public addFSCleanup(filename: string) {
21+
this.addCleanup(async () => {
22+
try {
23+
await fs.unlink(filename);
24+
} catch {
25+
// The file is already gone.
26+
}
27+
});
28+
}
29+
30+
public async cleanUp() {
31+
const cleanups = this.cleanups;
32+
this.cleanups = [];
33+
34+
return Promise.all(
35+
cleanups.map(async (cleanup, i) => {
36+
try {
37+
const res = cleanup();
38+
if (res) {
39+
await res;
40+
}
41+
} catch (err) {
42+
console.error(`cleanup ${i + 1} failed: ${err}`);
43+
44+
console.error('moving on...');
45+
}
46+
}),
47+
);
48+
}
49+
}
50+
51+
export class PythonFixture extends CleanupFixture {
52+
public readonly python: string;
53+
constructor(
54+
// If not provided, we will use the global default.
55+
python?: string,
56+
) {
57+
super();
58+
if (python) {
59+
this.python = python;
60+
} else {
61+
this.python = PYTHON_PATH;
62+
}
63+
}
64+
65+
public runScript(filename: string, ...args: string[]): Proc {
66+
return this.spawn(filename, ...args);
67+
}
68+
69+
public runModule(name: string, ...args: string[]): Proc {
70+
return this.spawn('-m', name, ...args);
71+
}
72+
73+
private spawn(...args: string[]) {
74+
const proc = spawn(this.python, ...args);
75+
this.addCleanup(async () => {
76+
if (!proc.exited) {
77+
await sleep(1000); // Wait a sec before the hammer falls.
78+
try {
79+
proc.raw.kill();
80+
} catch {
81+
// It already finished.
82+
}
83+
}
84+
});
85+
return proc;
86+
}
87+
}

0 commit comments

Comments
 (0)