Skip to content

Commit b893232

Browse files
atomiechenedvilme
andauthored
Fix path-only Python project manager defaults (#1667)
## Summary Fixes #1666. Path-only entries are valid according to the `python-envs.pythonProjects` setting schema: ```json { "python-envs.pythonProjects": [ { "path": "backend" } ] } ``` However, the manager-setting helpers called `.length` on the omitted `envManager` and `packageManager` properties. This caused repeated `TypeError` failures during post-initialization telemetry and environment lookup. ## Fix - Treat omitted or empty project-level manager values as requests to use the corresponding default setting. - Mark `PythonProjectSettings.envManager` and `.packageManager` optional so the internal type matches the contributed JSON schema. - Add a unit test covering a path-only nested project entry and both default-manager fallbacks. ## Validation - Reproduced with VS Code 1.130.0 and the latest stable extensions in an empty `--user-data-dir` / `--extensions-dir` profile. - Installed the patched 1.37.0 VSIX in a second empty profile and verified that the same workspace starts without `TypeError` or post-initialization failure. - `npm run compile-tests` - `npm run lint` - `npm run unittest` — 1,429 passing, 6 pending AI disclosure: Prepared with assistance from OpenAI Codex. Co-authored-by: Eduardo Villalpando Mello <eduardovil@microsoft.com>
1 parent ab7e086 commit b893232

3 files changed

Lines changed: 65 additions & 4 deletions

File tree

‎src/features/projectManager.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export interface PythonProjectManager extends Disposable {
3737

3838
export interface PythonProjectSettings {
3939
path: string;
40-
envManager: string;
41-
packageManager: string;
40+
envManager?: string;
41+
packageManager?: string;
4242
workspace?: string;
4343
_inlineScriptRegistration?: InlineScriptProjectRegistrationMarker;
4444
}

‎src/features/settings/settingHelpers.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export function isDefaultEnvManagerBroken(): boolean {
9999
export function getDefaultEnvManagerSetting(wm: PythonProjectManager, scope?: Uri): string {
100100
const config = workspaceApis.getConfiguration('python-envs', scope);
101101
const settings = getSettings(wm, config, scope);
102-
if (settings && settings.envManager.length > 0) {
102+
if (settings?.envManager) {
103103
return settings.envManager;
104104
}
105105
// Only show the warning once per session
@@ -127,7 +127,7 @@ export function getDefaultPkgManagerSetting(
127127
const config = workspaceApis.getConfiguration('python-envs', scope);
128128

129129
const settings = getSettings(wm, config, scope);
130-
if (settings && settings.packageManager.length > 0) {
130+
if (settings?.packageManager) {
131131
return settings.packageManager;
132132
}
133133

‎src/test/features/settings/settingHelpers.unit.test.ts‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import * as sender from '../../../common/telemetry/sender';
99
import * as workspaceApis from '../../../common/workspace.apis';
1010
import {
1111
addPythonProjectSetting,
12+
getDefaultEnvManagerSetting,
13+
getDefaultPkgManagerSetting,
1214
getExactPythonProjectSetting,
1315
migrateGlobalDefaultEnvManagerSetting,
1416
registerInlineScriptPythonProjectSetting,
@@ -35,6 +37,65 @@ function getTestWorkspacePath(): string {
3537
return process.platform === 'win32' ? 'C:\\workspace' : '/workspace';
3638
}
3739

40+
suite('Setting Helpers - Optional Project Managers', () => {
41+
const VENV_MANAGER_ID = 'ms-python.python:venv';
42+
const PIP_MANAGER_ID = 'ms-python.python:pip';
43+
const workspacePath = getTestWorkspacePath();
44+
const workspaceUri = Uri.file(workspacePath);
45+
const projectUri = Uri.joinPath(workspaceUri, 'backend');
46+
const workspaceFolder: WorkspaceFolder = {
47+
uri: workspaceUri,
48+
name: 'workspace',
49+
index: 0,
50+
};
51+
const project = {
52+
name: 'backend',
53+
uri: projectUri,
54+
};
55+
const projectManager = {
56+
get: (uri: Uri) => (uri.fsPath === projectUri.fsPath ? project : undefined),
57+
} as unknown as PythonProjectManager;
58+
59+
teardown(() => {
60+
sinon.restore();
61+
});
62+
63+
function createProjectConfig(projectSettings: PythonProjectSettings): MockWorkspaceConfiguration {
64+
const mockConfig = new MockWorkspaceConfiguration();
65+
(mockConfig as any).get = <T>(key: string, defaultValue?: T): T | undefined => {
66+
if (key === 'pythonProjects') {
67+
return [projectSettings] as T;
68+
}
69+
if (key === 'defaultEnvManager') {
70+
return VENV_MANAGER_ID as T;
71+
}
72+
if (key === 'defaultPackageManager') {
73+
return PIP_MANAGER_ID as T;
74+
}
75+
return defaultValue;
76+
};
77+
return mockConfig;
78+
}
79+
80+
test('uses default managers when a pythonProjects entry only specifies path', () => {
81+
sinon.stub(workspaceApis, 'getConfiguration').returns(createProjectConfig({ path: 'backend' }));
82+
sinon.stub(workspaceApis, 'getWorkspaceFolder').returns(workspaceFolder);
83+
84+
assert.strictEqual(getDefaultEnvManagerSetting(projectManager, projectUri), VENV_MANAGER_ID);
85+
assert.strictEqual(getDefaultPkgManagerSetting(projectManager, projectUri), PIP_MANAGER_ID);
86+
});
87+
88+
test('uses default managers when a pythonProjects entry has empty manager values', () => {
89+
sinon.stub(workspaceApis, 'getConfiguration').returns(
90+
createProjectConfig({ path: 'backend', envManager: '', packageManager: '' }),
91+
);
92+
sinon.stub(workspaceApis, 'getWorkspaceFolder').returns(workspaceFolder);
93+
94+
assert.strictEqual(getDefaultEnvManagerSetting(projectManager, projectUri), VENV_MANAGER_ID);
95+
assert.strictEqual(getDefaultPkgManagerSetting(projectManager, projectUri), PIP_MANAGER_ID);
96+
});
97+
});
98+
3899
/**
39100
* These tests verify that manager edits without a project do not write settings
40101
* and are logged explicitly as ignored global edits.

0 commit comments

Comments
 (0)