Skip to content

Commit ffef12f

Browse files
authored
Merge branch 'main' into indigo-cow
2 parents f942dd7 + dbc867f commit ffef12f

14 files changed

Lines changed: 355 additions & 264 deletions

File tree

examples/sample1/src/api.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
// Licensed under the MIT License.
33

44
import {
5-
Uri,
65
Disposable,
7-
MarkdownString,
86
Event,
7+
FileChangeType,
98
LogOutputChannel,
10-
ThemeIcon,
11-
Terminal,
9+
MarkdownString,
1210
TaskExecution,
11+
Terminal,
1312
TerminalOptions,
14-
FileChangeType,
13+
ThemeIcon,
14+
Uri,
1515
} from 'vscode';
1616

1717
/**
@@ -651,10 +651,6 @@ export interface PythonProject {
651651
*/
652652
readonly tooltip?: string | MarkdownString;
653653

654-
/**
655-
* The icon path for the Python project, which can be a string, Uri, or an object with light and dark theme paths.
656-
*/
657-
readonly iconPath?: IconPath;
658654
}
659655

660656
/**
@@ -696,10 +692,6 @@ export interface PythonProjectCreator {
696692
*/
697693
readonly tooltip?: string | MarkdownString;
698694

699-
/**
700-
* The icon path for the Python project creator, which can be a string, Uri, or an object with light and dark theme paths.
701-
*/
702-
readonly iconPath?: IconPath;
703695

704696
/**
705697
* Creates a new Python project or projects.

package.json

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,6 @@
160160
"category": "Python",
161161
"icon": "$(check)"
162162
},
163-
{
164-
"command": "python-envs.reset",
165-
"title": "%python-envs.reset.title%",
166-
"category": "Python",
167-
"icon": "$(sync)"
168-
},
169163
{
170164
"command": "python-envs.remove",
171165
"title": "%python-envs.remove.title%",
@@ -256,6 +250,11 @@
256250
"title": "%python-envs.terminal.revertStartupScriptChanges.title%",
257251
"category": "Python Envs",
258252
"icon": "$(discard)"
253+
},
254+
{
255+
"command": "python-envs.reportIssue",
256+
"title": "%python-envs.reportIssue.title%",
257+
"category": "Python Environments"
259258
}
260259
],
261260
"menus": {
@@ -276,10 +275,6 @@
276275
"command": "python-envs.setEnv",
277276
"when": "false"
278277
},
279-
{
280-
"command": "python-envs.reset",
281-
"when": "false"
282-
},
283278
{
284279
"command": "python-envs.remove",
285280
"when": "false"
@@ -401,10 +396,6 @@
401396
"group": "inline",
402397
"when": "view == python-projects && viewItem =~ /.*python-workspace.*/"
403398
},
404-
{
405-
"command": "python-envs.reset",
406-
"when": "view == python-projects && viewItem =~ /.*python-workspace.*/"
407-
},
408399
{
409400
"command": "python-envs.createTerminal",
410401
"group": "inline",

package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"python-envs.terminal.autoActivationType.shellStartup": "Activation by modifying the terminal shell startup script. To use this feature we will need to modify your shell startup scripts.",
1212
"python-envs.terminal.autoActivationType.off": "No automatic activation of environments.",
1313
"python-envs.terminal.revertStartupScriptChanges.title": "Revert Shell Startup Script Changes",
14+
"python-envs.reportIssue.title": "Report Issue",
1415
"python-envs.setEnvManager.title": "Set Environment Manager",
1516
"python-envs.setPkgManager.title": "Set Package Manager",
1617
"python-envs.addPythonProject.title": "Add Python Project",
@@ -22,7 +23,6 @@
2223
"python-envs.createAny.title": "Create Environment",
2324
"python-envs.set.title": "Set Project Environment",
2425
"python-envs.setEnv.title": "Set As Project Environment",
25-
"python-envs.reset.title": "Reset to Default",
2626
"python-envs.remove.title": "Delete Environment",
2727
"python-envs.refreshAllManagers.title": "Refresh All Environment Managers",
2828
"python-envs.refreshPackages.title": "Refresh Packages List",

src/api.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -650,11 +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-
654-
/**
655-
* The icon path for the Python project, which can be a string, Uri, or an object with light and dark theme paths.
656-
*/
657-
readonly iconPath?: IconPath;
658653
}
659654

660655
/**
@@ -701,11 +696,6 @@ export interface PythonProjectCreator {
701696
*/
702697
readonly tooltip?: string | MarkdownString;
703698

704-
/**
705-
* The icon path for the Python project creator, which can be a string, Uri, or an object with light and dark theme paths.
706-
*/
707-
readonly iconPath?: IconPath;
708-
709699
/**
710700
* Creates a new Python project(s) or, if files are not a project, returns Uri(s) to the created files.
711701
* Anything that needs its own python environment constitutes a project.

src/extension.ts

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { commands, ExtensionContext, LogOutputChannel, Terminal, Uri, window } from 'vscode';
1+
import { commands, extensions, ExtensionContext, LogOutputChannel, Terminal, Uri, window, workspace } from 'vscode';
22
import { PythonEnvironment, PythonEnvironmentApi, PythonProjectCreator } from './api';
33
import { ensureCorrectVersion } from './common/extVersion';
44
import { registerLogger, traceError, traceInfo } from './common/logging';
@@ -32,7 +32,6 @@ import {
3232
refreshPackagesCommand,
3333
removeEnvironmentCommand,
3434
removePythonProject,
35-
resetEnvironmentCommand,
3635
runAsTaskCommand,
3736
runInDedicatedTerminalCommand,
3837
runInTerminalCommand,
@@ -61,6 +60,7 @@ import { EnvManagerView } from './features/views/envManagersView';
6160
import { ProjectView } from './features/views/projectView';
6261
import { PythonStatusBarImpl } from './features/views/pythonStatusBar';
6362
import { updateViewsAndStatus } from './features/views/revealHandler';
63+
import { ProjectItem } from './features/views/treeViewItems';
6464
import { EnvironmentManagers, ProjectCreators, PythonProjectManager } from './internal.api';
6565
import { registerSystemPythonFeatures } from './managers/builtin/main';
6666
import { SysPythonManager } from './managers/builtin/sysPythonManager';
@@ -69,6 +69,85 @@ import { registerCondaFeatures } from './managers/conda/main';
6969
import { registerPoetryFeatures } from './managers/poetry/main';
7070
import { registerPyenvFeatures } from './managers/pyenv/main';
7171

72+
/**
73+
* Collects relevant Python environment information for issue reporting
74+
*/
75+
async function collectEnvironmentInfo(
76+
context: ExtensionContext,
77+
envManagers: EnvironmentManagers,
78+
projectManager: PythonProjectManager
79+
): Promise<string> {
80+
const info: string[] = [];
81+
82+
try {
83+
// Extension version
84+
const extensionVersion = context.extension?.packageJSON?.version || 'unknown';
85+
info.push(`Extension Version: ${extensionVersion}`);
86+
87+
// Python extension version
88+
const pythonExtension = extensions.getExtension('ms-python.python');
89+
const pythonVersion = pythonExtension?.packageJSON?.version || 'not installed';
90+
info.push(`Python Extension Version: ${pythonVersion}`);
91+
92+
// Environment managers
93+
const managers = envManagers.managers;
94+
info.push(`\nRegistered Environment Managers (${managers.length}):`);
95+
managers.forEach(manager => {
96+
info.push(` - ${manager.id} (${manager.displayName})`);
97+
});
98+
99+
// Available environments
100+
const allEnvironments: PythonEnvironment[] = [];
101+
for (const manager of managers) {
102+
try {
103+
const envs = await manager.getEnvironments('all');
104+
allEnvironments.push(...envs);
105+
} catch (err) {
106+
info.push(` Error getting environments from ${manager.id}: ${err}`);
107+
}
108+
}
109+
110+
info.push(`\nTotal Available Environments: ${allEnvironments.length}`);
111+
if (allEnvironments.length > 0) {
112+
info.push('Environment Details:');
113+
allEnvironments.slice(0, 10).forEach((env, index) => {
114+
info.push(` ${index + 1}. ${env.displayName} (${env.version}) - ${env.displayPath}`);
115+
});
116+
if (allEnvironments.length > 10) {
117+
info.push(` ... and ${allEnvironments.length - 10} more environments`);
118+
}
119+
}
120+
121+
// Python projects
122+
const projects = projectManager.getProjects();
123+
info.push(`\nPython Projects (${projects.length}):`);
124+
for (let index = 0; index < projects.length; index++) {
125+
const project = projects[index];
126+
info.push(` ${index + 1}. ${project.uri.fsPath}`);
127+
try {
128+
const env = await envManagers.getEnvironment(project.uri);
129+
if (env) {
130+
info.push(` Environment: ${env.displayName}`);
131+
}
132+
} catch (err) {
133+
info.push(` Error getting environment: ${err}`);
134+
}
135+
}
136+
137+
// Current settings (non-sensitive)
138+
const config = workspace.getConfiguration('python-envs');
139+
info.push('\nExtension Settings:');
140+
info.push(` Default Environment Manager: ${config.get('defaultEnvManager')}`);
141+
info.push(` Default Package Manager: ${config.get('defaultPackageManager')}`);
142+
info.push(` Terminal Auto Activation: ${config.get('terminal.autoActivationType')}`);
143+
144+
} catch (err) {
145+
info.push(`\nError collecting environment information: ${err}`);
146+
}
147+
148+
return info.join('\n');
149+
}
150+
72151
export async function activate(context: ExtensionContext): Promise<PythonEnvironmentApi> {
73152
const start = new StopWatch();
74153

@@ -119,7 +198,7 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
119198
projectCreators.registerPythonProjectCreator(new ExistingProjects(projectManager)),
120199
projectCreators.registerPythonProjectCreator(new AutoFindProjects(projectManager)),
121200
projectCreators.registerPythonProjectCreator(new NewPackageProject(envManagers, projectManager)),
122-
projectCreators.registerPythonProjectCreator(new NewScriptProject()),
201+
projectCreators.registerPythonProjectCreator(new NewScriptProject(projectManager)),
123202
);
124203

125204
setPythonApi(envManagers, projectManager, projectCreators, terminalManager, envVarManager);
@@ -186,9 +265,6 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
186265
commands.registerCommand('python-envs.setEnv', async (item) => {
187266
await setEnvironmentCommand(item, envManagers, projectManager);
188267
}),
189-
commands.registerCommand('python-envs.reset', async (item) => {
190-
await resetEnvironmentCommand(item, envManagers, projectManager);
191-
}),
192268
commands.registerCommand('python-envs.setEnvManager', async () => {
193269
await setEnvManagerCommand(envManagers, projectManager);
194270
}),
@@ -206,7 +282,16 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
206282
await addPythonProjectCommand(resource, projectManager, envManagers, projectCreators);
207283
}),
208284
commands.registerCommand('python-envs.removePythonProject', async (item) => {
209-
await resetEnvironmentCommand(item, envManagers, projectManager);
285+
// Clear environment association before removing project
286+
if (item instanceof ProjectItem) {
287+
const uri = item.project.uri;
288+
const manager = envManagers.getEnvironmentManager(uri);
289+
if (manager) {
290+
manager.set(uri, undefined);
291+
} else {
292+
traceError(`No environment manager found for ${uri.fsPath}`);
293+
}
294+
}
210295
await removePythonProject(item, projectManager);
211296
}),
212297
commands.registerCommand('python-envs.clearCache', async () => {
@@ -278,6 +363,19 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
278363
}
279364
},
280365
),
366+
commands.registerCommand('python-envs.reportIssue', async () => {
367+
try {
368+
const issueData = await collectEnvironmentInfo(context, envManagers, projectManager);
369+
370+
await commands.executeCommand('workbench.action.openIssueReporter', {
371+
extensionId: 'ms-python.vscode-python-envs',
372+
issueTitle: '[Python Environments] ',
373+
issueBody: `<!-- Please describe the issue you're experiencing -->\n\n<!-- The following information was automatically generated -->\n\n<details>\n<summary>Environment Information</summary>\n\n\`\`\`\n${issueData}\n\`\`\`\n\n</details>`
374+
});
375+
} catch (error) {
376+
window.showErrorMessage(`Failed to open issue reporter: ${error}`);
377+
}
378+
}),
281379
terminalActivation.onDidChangeTerminalActivationState(async (e) => {
282380
await setActivateMenuButtonContext(e.terminal, e.environment, e.activated);
283381
}),

src/features/creators/newPackageProject.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,6 @@ export class NewPackageProject implements PythonProjectCreator {
116116
let createdPackage: PythonProject | undefined;
117117
let createdEnv: PythonEnvironment | undefined;
118118
if (createVenv) {
119-
createdPackage = {
120-
name: packageName,
121-
uri: Uri.file(projectDestinationFolder),
122-
};
123-
124119
// add package to list of packages before creating the venv
125120
this.projectManager.add(createdPackage);
126121
// gets default environment manager
@@ -178,13 +173,12 @@ export class NewPackageProject implements PythonProjectCreator {
178173
};
179174
await manageLaunchJsonFile(destRoot, JSON.stringify(launchJsonConfig));
180175

181-
if (createdPackage) {
182-
// return package if created (ie when venv is created)
183-
return createdPackage;
184-
} else {
185-
// otherwise its not a package and just a folder
186-
return Uri.file(projectDestinationFolder);
187-
}
176+
const createdPackage: PythonProject | undefined = {
177+
name: packageName,
178+
uri: Uri.file(projectDestinationFolder),
179+
};
180+
this.projectManager.add(createdPackage);
181+
return createdPackage;
188182
}
189183
return undefined;
190184
}

src/features/creators/newScriptProject.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { PythonProject, PythonProjectCreator, PythonProjectCreatorOptions } from
55
import { NEW_PROJECT_TEMPLATES_FOLDER } from '../../common/constants';
66
import { traceError } from '../../common/logging';
77
import { showInputBoxWithButtons } from '../../common/window.apis';
8+
import { PythonProjectManager } from '../../internal.api';
89
import { isCopilotInstalled, manageCopilotInstructionsFile, replaceInFilesAndNames } from './creationHelpers';
910

1011
export class NewScriptProject implements PythonProjectCreator {
@@ -13,7 +14,7 @@ export class NewScriptProject implements PythonProjectCreator {
1314
public readonly description = l10n.t('Creates a new script folder in your current workspace with PEP 723 support');
1415
public readonly tooltip = new MarkdownString(l10n.t('Create a new Python script'));
1516

16-
constructor() {}
17+
constructor(private readonly projectManager: PythonProjectManager) {}
1718

1819
async create(options?: PythonProjectCreatorOptions): Promise<PythonProject | Uri | undefined> {
1920
// quick create (needs name, will always create venv and copilot instructions)
@@ -113,7 +114,13 @@ export class NewScriptProject implements PythonProjectCreator {
113114
]);
114115
}
115116

116-
return Uri.file(scriptDestination);
117+
// Add the created script to the project manager
118+
const createdScript: PythonProject | undefined = {
119+
name: scriptFileName,
120+
uri: Uri.file(scriptDestination),
121+
};
122+
this.projectManager.add(createdScript);
123+
return createdScript;
117124
}
118125
return undefined;
119126
}

src/features/envCommands.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -329,35 +329,6 @@ async function setEnvironmentForProjects(
329329
await em.setEnvironments(uris, environment);
330330
}
331331

332-
export async function resetEnvironmentCommand(
333-
context: unknown,
334-
em: EnvironmentManagers,
335-
wm: PythonProjectManager,
336-
): Promise<void> {
337-
if (context instanceof ProjectItem) {
338-
const view = context as ProjectItem;
339-
return resetEnvironmentCommand(view.project.uri, em, wm);
340-
} else if (context instanceof Uri) {
341-
const uri = context as Uri;
342-
const manager = em.getEnvironmentManager(uri);
343-
if (manager) {
344-
manager.set(uri, undefined);
345-
} else {
346-
showErrorMessage(`No environment manager found for: ${uri.fsPath}`);
347-
traceError(`No environment manager found for ${uri.fsPath}`);
348-
}
349-
return;
350-
} else if (context === undefined) {
351-
const pw = await pickProject(wm.getProjects());
352-
if (pw) {
353-
return resetEnvironmentCommand(pw.uri, em, wm);
354-
}
355-
return;
356-
}
357-
traceError(`Invalid context for unset environment command: ${context}`);
358-
showErrorMessage('Invalid context for unset environment');
359-
}
360-
361332
export async function setEnvManagerCommand(em: EnvironmentManagers, wm: PythonProjectManager): Promise<void> {
362333
const projects = await pickProjectMany(wm.getProjects());
363334
if (projects && projects.length > 0) {

0 commit comments

Comments
 (0)