Skip to content

Commit 19fc3df

Browse files
authored
Merge branch 'main' into copilot/fix-python-environment-creation
2 parents 7f86804 + 7d52871 commit 19fc3df

File tree

17 files changed

+384
-47
lines changed

17 files changed

+384
-47
lines changed

.github/instructions/testing-workflow.instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,5 +548,6 @@ envConfig.inspect
548548
- When fixing mock environment creation, use `null` to truly omit properties rather than `undefined` (1)
549549
- Always recompile TypeScript after making import/export changes before running tests, as stubs won't work if they're applied to old compiled JavaScript that doesn't have the updated imports (2)
550550
- Create proxy abstraction functions for Node.js APIs like `cp.spawn` to enable clean testing - use function overloads to preserve Node.js's intelligent typing while making the functions mockable (1)
551+
- When a targeted test run yields 0 tests, first verify the compiled JS exists under `out/test` (rootDir is `src`); absence almost always means the test file sits outside `src` or compilation hasn't run yet (1)
551552
- When unit tests fail with VS Code API errors like `TypeError: X is not a constructor` or `Cannot read properties of undefined (reading 'Y')`, check if VS Code APIs are properly mocked in `/src/test/unittests.ts` - add missing Task-related APIs (`Task`, `TaskScope`, `ShellExecution`, `TaskRevealKind`, `TaskPanelKind`) and namespace mocks (`tasks`) following the existing pattern of `mockedVSCode.X = vscodeMocks.vscMockExtHostedTypes.X` (1)
552553
- Create minimal mock objects with only required methods and use TypeScript type assertions (e.g., mockApi as PythonEnvironmentApi) to satisfy interface requirements instead of implementing all interface methods when only specific methods are needed for the test (1)

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ export default [{
3535
eqeqeq: "warn",
3636
"no-throw-literal": "warn",
3737
semi: "warn",
38-
"@typescript-eslint/no-explicit-any": "warn",
38+
"@typescript-eslint/no-explicit-any": "error",
3939
},
4040
}];

examples/sample1/src/api.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,6 @@ export interface PythonProject {
650650
* The tooltip for the Python project, which can be a string or a Markdown string.
651651
*/
652652
readonly tooltip?: string | MarkdownString;
653-
654653
}
655654

656655
/**
@@ -692,7 +691,6 @@ export interface PythonProjectCreator {
692691
*/
693692
readonly tooltip?: string | MarkdownString;
694693

695-
696694
/**
697695
* Creates a new Python project or projects.
698696
* @param options - Optional parameters for creating the Python project.
@@ -1228,12 +1226,13 @@ export interface PythonEnvironmentVariablesApi {
12281226
* 3. `.env` file at the root of the python project.
12291227
* 4. `overrides` in the order provided.
12301228
*
1231-
* @param uri The URI of the project, workspace or a file in a for which environment variables are required.
1229+
* @param uri The URI of the project, workspace or a file in a for which environment variables are required. If not provided,
1230+
* it fetches the environment variables for the global scope.
12321231
* @param overrides Additional environment variables to override the defaults.
12331232
* @param baseEnvVar The base environment variables that should be used as a starting point.
12341233
*/
12351234
getEnvironmentVariables(
1236-
uri: Uri,
1235+
uri: Uri | undefined,
12371236
overrides?: ({ [key: string]: string | undefined } | Uri)[],
12381237
baseEnvVar?: { [key: string]: string | undefined },
12391238
): Promise<{ [key: string]: string | undefined }>;

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"Other"
1313
],
1414
"enabledApiProposals": [
15-
"terminalShellEnv"
15+
"terminalShellEnv",
16+
"terminalDataWriteEvent"
1617
],
1718
"capabilities": {
1819
"untrustedWorkspaces": {

src/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,12 +1237,13 @@ export interface PythonEnvironmentVariablesApi {
12371237
* 3. `.env` file at the root of the python project.
12381238
* 4. `overrides` in the order provided.
12391239
*
1240-
* @param uri The URI of the project, workspace or a file in a for which environment variables are required.
1240+
* @param uri The URI of the project, workspace or a file in a for which environment variables are required.If not provided,
1241+
* it fetches the environment variables for the global scope.
12411242
* @param overrides Additional environment variables to override the defaults.
12421243
* @param baseEnvVar The base environment variables that should be used as a starting point.
12431244
*/
12441245
getEnvironmentVariables(
1245-
uri: Uri,
1246+
uri: Uri | undefined,
12461247
overrides?: ({ [key: string]: string | undefined } | Uri)[],
12471248
baseEnvVar?: { [key: string]: string | undefined },
12481249
): Promise<{ [key: string]: string | undefined }>;

src/common/utils/asyncUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export async function sleep(milliseconds: number) {
1+
export async function timeout(milliseconds: number): Promise<void> {
22
return new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
33
}

src/common/utils/debounce.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1-
export interface SimpleDebounce {
1+
import { Disposable } from 'vscode';
2+
export interface SimpleDebounce extends Disposable {
23
trigger(): void;
34
}
45

5-
class SimpleDebounceImpl {
6+
class SimpleDebounceImpl implements SimpleDebounce {
67
private timeout: NodeJS.Timeout | undefined;
78

89
constructor(private readonly ms: number, private readonly callback: () => void) {}
910

10-
public trigger() {
11+
public trigger(): void {
1112
if (this.timeout) {
1213
clearTimeout(this.timeout);
1314
}
1415
this.timeout = setTimeout(() => {
1516
this.callback();
1617
}, this.ms);
1718
}
19+
20+
public dispose(): void {
21+
if (this.timeout) {
22+
clearTimeout(this.timeout);
23+
}
24+
}
1825
}
1926

2027
export function createSimpleDebounce(ms: number, callback: () => void): SimpleDebounce {

src/common/window.apis.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ export function onDidChangeTerminalShellIntegration(
4949
return window.onDidChangeTerminalShellIntegration(listener, thisArgs, disposables);
5050
}
5151

52+
export function onDidWriteTerminalData(
53+
listener: (e: { readonly terminal: Terminal; readonly data: string }) => any,
54+
thisArgs?: any,
55+
disposables?: Disposable[],
56+
): Disposable {
57+
return window.onDidWriteTerminalData(listener, thisArgs, disposables);
58+
}
59+
5260
export function showOpenDialog(options?: OpenDialogOptions): Thenable<Uri[] | undefined> {
5361
return window.showOpenDialog(options);
5462
}

src/features/execution/envVariableManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ export class PythonEnvVariableManager implements EnvVarManager {
3737
}
3838

3939
async getEnvironmentVariables(
40-
uri: Uri,
40+
uri: Uri | undefined,
4141
overrides?: ({ [key: string]: string | undefined } | Uri)[],
4242
baseEnvVar?: { [key: string]: string | undefined },
4343
): Promise<{ [key: string]: string | undefined }> {
44-
const project = this.pm.get(uri);
44+
const project = uri ? this.pm.get(uri) : undefined;
4545

4646
const base = baseEnvVar || { ...process.env };
4747
let env = base;

src/features/terminal/shells/common/shellUtils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { PythonCommandRunConfiguration, PythonEnvironment } from '../../../../api';
22
import { traceInfo } from '../../../../common/logging';
33
import { getGlobalPersistentState } from '../../../../common/persistentState';
4-
import { sleep } from '../../../../common/utils/asyncUtils';
4+
import { timeout } from '../../../../common/utils/asyncUtils';
55
import { isWindows } from '../../../../common/utils/platformUtils';
66
import { activeTerminalShellIntegration } from '../../../../common/window.apis';
77
import { getConfiguration } from '../../../../common/workspace.apis';
@@ -106,11 +106,11 @@ export function extractProfilePath(content: string): string | undefined {
106106

107107
export async function shellIntegrationForActiveTerminal(name: string, profile?: string): Promise<boolean> {
108108
let hasShellIntegration = activeTerminalShellIntegration();
109-
let timeout = 0;
109+
let timeOutstamp = 0;
110110

111-
while (!hasShellIntegration && timeout < SHELL_INTEGRATION_TIMEOUT) {
112-
await sleep(SHELL_INTEGRATION_POLL_INTERVAL);
113-
timeout += SHELL_INTEGRATION_POLL_INTERVAL;
111+
while (!hasShellIntegration && timeOutstamp < SHELL_INTEGRATION_TIMEOUT) {
112+
await timeout(SHELL_INTEGRATION_POLL_INTERVAL);
113+
timeOutstamp += SHELL_INTEGRATION_POLL_INTERVAL;
114114
hasShellIntegration = activeTerminalShellIntegration();
115115
}
116116

0 commit comments

Comments
 (0)