Skip to content

Commit e514be3

Browse files
committed
refactor: update logging for default environment manager warnings and add localization support
1 parent b2e03ae commit e514be3

File tree

3 files changed

+121
-20
lines changed

3 files changed

+121
-20
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
applyTo: '**'
3+
---
4+
5+
Provide project context and coding guidelines that AI should follow when generating code, answering questions, or reviewing changes.# Coding Instructions for vscode-python-environments
6+
7+
## Localization
8+
9+
- Localize all user-facing messages using VS Code’s `l10n` API.
10+
- Internal log messages do not require localization.
11+
12+
## Logging
13+
14+
- Use the extension’s logging utilities (`traceLog`, `traceVerbose`) for internal logs.
15+
- Do not use `console.log` or `console.warn` for logging.
16+
17+
## Settings Precedence
18+
19+
- Always consider VS Code settings precedence:
20+
1. Workspace folder
21+
2. Workspace
22+
3. User/global
23+
- Remove or update settings from the highest precedence scope first.
24+
25+
## Error Handling & User Notifications
26+
27+
- Avoid showing the same error message multiple times in a session; track state with a module-level variable.
28+
- Use clear, actionable error messages and offer relevant buttons (e.g., "Open settings", "Close").
29+
30+
## Documentation
31+
32+
- Add clear docstrings to public functions, describing their purpose, parameters, and behavior.

src/features/settings/settingHelpers.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from 'vscode';
1010
import { PythonProject } from '../../api';
1111
import { DEFAULT_ENV_MANAGER_ID, DEFAULT_PACKAGE_MANAGER_ID } from '../../common/constants';
12-
import { traceError, traceInfo } from '../../common/logging';
12+
import { traceError, traceWarn } from '../../common/logging';
1313
import { getWorkspaceFile, getWorkspaceFolders } from '../../common/workspace.apis';
1414
import { PythonProjectManager, PythonProjectSettings } from '../../internal.api';
1515

@@ -32,6 +32,7 @@ function getSettings(
3232
}
3333

3434
let DEFAULT_ENV_MANAGER_BROKEN = false;
35+
let hasShownDefaultEnvManagerBrokenWarn = false;
3536

3637
export function setDefaultEnvManagerBroken(broken: boolean) {
3738
DEFAULT_ENV_MANAGER_BROKEN = broken;
@@ -46,14 +47,18 @@ export function getDefaultEnvManagerSetting(wm: PythonProjectManager, scope?: Ur
4647
if (settings && settings.envManager.length > 0) {
4748
return settings.envManager;
4849
}
50+
// Only show the warning once per session
4951
if (isDefaultEnvManagerBroken()) {
50-
traceInfo(`Default environment manager is broken, using system default: ${DEFAULT_ENV_MANAGER_ID}`);
52+
if (!hasShownDefaultEnvManagerBrokenWarn) {
53+
traceWarn(`Default environment manager is broken, using system default: ${DEFAULT_ENV_MANAGER_ID}`);
54+
hasShownDefaultEnvManagerBrokenWarn = true;
55+
}
5156
return DEFAULT_ENV_MANAGER_ID;
5257
}
5358
const defaultManager = config.get<string>('defaultEnvManager');
5459
if (defaultManager === undefined || defaultManager === null || defaultManager === '') {
5560
traceError('No default environment manager set. Check setting python-envs.defaultEnvManager');
56-
traceInfo(`Using system default package manager: ${DEFAULT_ENV_MANAGER_ID}`);
61+
traceWarn(`Using system default package manager: ${DEFAULT_ENV_MANAGER_ID}`);
5762
return DEFAULT_ENV_MANAGER_ID;
5863
}
5964
return defaultManager;

src/managers/common/utils.ts

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as fs from 'fs-extra';
22
import path from 'path';
3-
import { commands, ConfigurationTarget, window, workspace } from 'vscode';
3+
import { commands, ConfigurationTarget, l10n, window, workspace } from 'vscode';
44
import { PythonCommandRunConfiguration, PythonEnvironment, PythonEnvironmentApi } from '../../api';
5+
import { traceLog, traceVerbose } from '../../common/logging';
56
import { isWindows } from '../../common/utils/platformUtils';
67
import { ShellConstants } from '../../features/common/shellConstants';
78
import { getDefaultEnvManagerSetting, setDefaultEnvManagerBroken } from '../../features/settings/settingHelpers';
@@ -198,35 +199,64 @@ export async function getShellActivationCommands(binDir: string): Promise<{
198199
};
199200
}
200201

202+
// Tracks if the broken defaultEnvManager error message has been shown this session
203+
let hasShownBrokenDefaultEnvManagerError = false;
204+
205+
/**
206+
* Checks if the given managerId is set as the default environment manager for the project.
207+
* If so, marks the default manager as broken, refreshes environments, and shows an error message to the user.
208+
* The error message offers to reset the setting, view the setting, or close.
209+
* The error message is only shown once per session.
210+
*
211+
* @param managerId The environment manager id to check.
212+
* @param projectManager The Python project manager instance.
213+
* @param api The Python environment API instance.
214+
*/
201215
export async function notifyMissingManagerIfDefault(
202216
managerId: string,
203217
projectManager: PythonProjectManager,
204218
api: PythonEnvironmentApi,
205219
) {
206220
const defaultEnvManager = getDefaultEnvManagerSetting(projectManager);
207221
if (defaultEnvManager === managerId) {
222+
if (hasShownBrokenDefaultEnvManagerError) {
223+
return;
224+
}
225+
hasShownBrokenDefaultEnvManagerError = true;
208226
setDefaultEnvManagerBroken(true);
209227
await api.refreshEnvironments(undefined);
210228
window
211229
.showErrorMessage(
212-
`The default environment manager is set to '${defaultEnvManager}', but the ${
213-
managerId.split(':')[1]
214-
} executable could not be found.`,
215-
'Reset setting',
216-
'View setting',
217-
'Close',
230+
l10n.t(
231+
"The default environment manager is set to '{0}', but the {1} executable could not be found.",
232+
defaultEnvManager,
233+
managerId.split(':')[1],
234+
),
235+
l10n.t('Reset setting'),
236+
l10n.t('View setting'),
237+
l10n.t('Close'),
218238
)
219-
.then((selection) => {
239+
.then(async (selection) => {
220240
if (selection === 'Reset setting') {
221-
// Remove the setting from all scopes
222-
const config = workspace.getConfiguration('python-envs');
223-
const inspect = config.inspect('defaultEnvManager');
224-
if (inspect?.workspaceValue !== undefined) {
225-
// Remove from workspace settings
226-
config.update('defaultEnvManager', undefined, ConfigurationTarget.Workspace);
227-
} else if (inspect?.globalValue !== undefined) {
228-
// Remove from user settings
229-
config.update('defaultEnvManager', undefined, ConfigurationTarget.Global);
241+
const result = await removeFirstDefaultEnvManagerSettingDetailed(managerId);
242+
if (!result.found) {
243+
window
244+
.showErrorMessage(
245+
l10n.t(
246+
"Could not find a setting for 'defaultEnvManager' set to '{0}' to reset.",
247+
managerId,
248+
),
249+
l10n.t('Open settings'),
250+
l10n.t('Close'),
251+
)
252+
.then((sel) => {
253+
if (sel === 'Open settings') {
254+
commands.executeCommand(
255+
'workbench.action.openSettings',
256+
'python-envs.defaultEnvManager',
257+
);
258+
}
259+
});
230260
}
231261
}
232262
if (selection === 'View setting') {
@@ -235,3 +265,37 @@ export async function notifyMissingManagerIfDefault(
235265
});
236266
}
237267
}
268+
269+
/**
270+
* Removes the first occurrence of 'defaultEnvManager' set to managerId, returns where it was removed, and logs the action.
271+
* @param managerId The manager id to match and remove.
272+
* @returns { found: boolean, scope?: string }
273+
*/
274+
export async function removeFirstDefaultEnvManagerSettingDetailed(
275+
managerId: string,
276+
): Promise<{ found: boolean; scope?: string }> {
277+
const config = workspace.getConfiguration('python-envs');
278+
const inspect = config.inspect('defaultEnvManager');
279+
280+
// Workspace folder settings (multi-root)
281+
if (inspect?.workspaceFolderValue !== undefined && inspect.workspaceFolderValue === managerId) {
282+
await config.update('defaultEnvManager', undefined, ConfigurationTarget.WorkspaceFolder);
283+
traceLog("[python-envs] Removed 'defaultEnvManager' from Workspace Folder settings.");
284+
return { found: true, scope: 'Workspace Folder' };
285+
}
286+
// Workspace settings
287+
if (inspect?.workspaceValue !== undefined && inspect.workspaceValue === managerId) {
288+
await config.update('defaultEnvManager', undefined, ConfigurationTarget.Workspace);
289+
traceLog("[python-envs] Removed 'defaultEnvManager' from Workspace settings.");
290+
return { found: true, scope: 'Workspace' };
291+
}
292+
// User/global settings
293+
if (inspect?.globalValue !== undefined && inspect.globalValue === managerId) {
294+
await config.update('defaultEnvManager', undefined, ConfigurationTarget.Global);
295+
traceLog("[python-envs] Removed 'defaultEnvManager' from User/Global settings.");
296+
return { found: true, scope: 'User/Global' };
297+
}
298+
// No matching setting found
299+
traceVerbose(`[python-envs] Could not find 'defaultEnvManager' set to '${managerId}' in any scope.`);
300+
return { found: false };
301+
}

0 commit comments

Comments
 (0)