Skip to content

Hide progress messages when creating env or installing packages #25174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/client/chat/createVirtualEnvTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { traceError, traceVerbose, traceWarn } from '../logging';
import { StopWatch } from '../common/utils/stopWatch';
import { useEnvExtension } from '../envExt/api.internal';
import { PythonEnvironment } from '../envExt/types';
import { hideEnvCreation } from '../pythonEnvironments/creation/provider/hideEnvCreation';

interface ICreateVirtualEnvToolParams extends IResourceReference {
packageList?: string[]; // Added only becausewe have ability to create a virtual env with list of packages same tool within the in Python Env extension.
Expand Down Expand Up @@ -86,6 +87,7 @@ export class CreateVirtualEnvTool implements LanguageModelTool<ICreateVirtualEnv
const interpreterPathService = this.serviceContainer.get<IInterpreterPathService>(IInterpreterPathService);
const disposables = new DisposableStore();
try {
disposables.add(hideEnvCreation());
const interpreterChanged = new Promise<void>((resolve) => {
disposables.add(interpreterPathService.onDidChange(() => resolve()));
});
Expand Down
5 changes: 4 additions & 1 deletion src/client/chat/installPackagesTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ export class InstallPackagesTool implements LanguageModelTool<IInstallPackageArg
throw new Error(`Installer ${installerType} not supported for the environment type: ${installerType}`);
}
for (const packageName of options.input.packageList) {
await installer.installModule(packageName, resourcePath, token, undefined, { installAsProcess: true });
await installer.installModule(packageName, resourcePath, token, undefined, {
installAsProcess: true,
hideProgress: true,
});
}
// format and return
const resultMessage = `Successfully installed ${packagePlurality}: ${options.input.packageList.join(', ')}`;
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/installer/moduleInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
// Display progress indicator if we have ability to cancel this operation from calling code.
// This is required as its possible the installation can take a long time.
// (i.e. if installation takes a long time in terminal or like, a progress indicator is necessary to let user know what is being waited on).
if (cancel) {
if (cancel && !options?.hideProgress) {
const shell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
const options: ProgressOptions = {
location: ProgressLocation.Notification,
Expand Down
1 change: 1 addition & 0 deletions src/client/common/installer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ export enum ModuleInstallFlags {

export type InstallOptions = {
installAsProcess?: boolean;
hideProgress?: boolean;
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { CancellationToken, ProgressLocation, WorkspaceFolder } from 'vscode';
import { CancellationToken, CancellationTokenSource, ProgressLocation, WorkspaceFolder } from 'vscode';
import * as path from 'path';
import { Commands, PVSC_EXTENSION_ID } from '../../../common/constants';
import { traceError, traceInfo, traceLog } from '../../../logging';
Expand Down Expand Up @@ -35,6 +35,8 @@ import {
CreateEnvironmentResult,
CreateEnvironmentProvider,
} from '../proposed.createEnvApis';
import { shouldDisplayEnvCreationProgress } from './hideEnvCreation';
import { noop } from '../../../common/utils/misc';

function generateCommandArgs(version?: string, options?: CreateEnvironmentOptions): string[] {
let addGitIgnore = true;
Expand Down Expand Up @@ -261,6 +263,50 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
}
}

const createEnvInternal = async (progress: CreateEnvironmentProgress, token: CancellationToken) => {
progress.report({
message: CreateEnv.statusStarting,
});

let envPath: string | undefined;
try {
sendTelemetryEvent(EventName.ENVIRONMENT_CREATING, undefined, {
environmentType: 'conda',
pythonVersion: version,
});
if (workspace) {
envPath = await createCondaEnv(
workspace,
getExecutableCommand(conda),
generateCommandArgs(version, options),
progress,
token,
);

if (envPath) {
return { path: envPath, workspaceFolder: workspace };
}

throw new Error('Failed to create conda environment. See Output > Python for more info.');
} else {
throw new Error('A workspace is needed to create conda environment');
}
} catch (ex) {
traceError(ex);
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
return { error: ex as Error };
}
};

if (!shouldDisplayEnvCreationProgress()) {
const token = new CancellationTokenSource();
try {
return await createEnvInternal({ report: noop }, token.token);
} finally {
token.dispose();
}
}

return withProgress(
{
location: ProgressLocation.Notification,
Expand All @@ -270,40 +316,7 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
async (
progress: CreateEnvironmentProgress,
token: CancellationToken,
): Promise<CreateEnvironmentResult | undefined> => {
progress.report({
message: CreateEnv.statusStarting,
});

let envPath: string | undefined;
try {
sendTelemetryEvent(EventName.ENVIRONMENT_CREATING, undefined, {
environmentType: 'conda',
pythonVersion: version,
});
if (workspace) {
envPath = await createCondaEnv(
workspace,
getExecutableCommand(conda),
generateCommandArgs(version, options),
progress,
token,
);

if (envPath) {
return { path: envPath, workspaceFolder: workspace };
}

throw new Error('Failed to create conda environment. See Output > Python for more info.');
} else {
throw new Error('A workspace is needed to create conda environment');
}
} catch (ex) {
traceError(ex);
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
return { error: ex as Error };
}
},
): Promise<CreateEnvironmentResult | undefined> => createEnvInternal(progress, token),
);
}

Expand Down
21 changes: 21 additions & 0 deletions src/client/pythonEnvironments/creation/provider/hideEnvCreation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { Disposable } from 'vscode';

const envCreationTracker: Disposable[] = [];

export function hideEnvCreation(): Disposable {
const disposable = new Disposable(() => {
const index = envCreationTracker.indexOf(disposable);
if (index > -1) {
envCreationTracker.splice(index, 1);
}
});
envCreationTracker.push(disposable);
return disposable;
}

export function shouldDisplayEnvCreationProgress(): boolean {
return envCreationTracker.length === 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import * as os from 'os';
import { CancellationToken, ProgressLocation, WorkspaceFolder } from 'vscode';
import { CancellationToken, CancellationTokenSource, ProgressLocation, WorkspaceFolder } from 'vscode';
import { Commands, PVSC_EXTENSION_ID } from '../../../common/constants';
import { createVenvScript } from '../../../common/process/internal/scripts';
import { execObservable } from '../../../common/process/rawProcessApis';
Expand Down Expand Up @@ -31,6 +31,8 @@ import {
CreateEnvironmentOptions,
CreateEnvironmentResult,
} from '../proposed.createEnvApis';
import { shouldDisplayEnvCreationProgress } from './hideEnvCreation';
import { noop } from '../../../common/utils/misc';

interface IVenvCommandArgs {
argv: string[];
Expand Down Expand Up @@ -333,6 +335,36 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
}

const args = generateCommandArgs(installInfo, addGitIgnore);
const createEnvInternal = async (progress: CreateEnvironmentProgress, token: CancellationToken) => {
progress.report({
message: CreateEnv.statusStarting,
});

let envPath: string | undefined;
try {
if (interpreter && workspace) {
envPath = await createVenv(workspace, interpreter, args, progress, token);
if (envPath) {
return { path: envPath, workspaceFolder: workspace };
}
throw new Error('Failed to create virtual environment. See Output > Python for more info.');
}
throw new Error('Failed to create virtual environment. Either interpreter or workspace is undefined.');
} catch (ex) {
traceError(ex);
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
return { error: ex as Error };
}
};

if (!shouldDisplayEnvCreationProgress()) {
const token = new CancellationTokenSource();
try {
return await createEnvInternal({ report: noop }, token.token);
} finally {
token.dispose();
}
}

return withProgress(
{
Expand All @@ -343,29 +375,7 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
async (
progress: CreateEnvironmentProgress,
token: CancellationToken,
): Promise<CreateEnvironmentResult | undefined> => {
progress.report({
message: CreateEnv.statusStarting,
});

let envPath: string | undefined;
try {
if (interpreter && workspace) {
envPath = await createVenv(workspace, interpreter, args, progress, token);
if (envPath) {
return { path: envPath, workspaceFolder: workspace };
}
throw new Error('Failed to create virtual environment. See Output > Python for more info.');
}
throw new Error(
'Failed to create virtual environment. Either interpreter or workspace is undefined.',
);
} catch (ex) {
traceError(ex);
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
return { error: ex as Error };
}
},
): Promise<CreateEnvironmentResult | undefined> => createEnvInternal(progress, token),
);
}

Expand Down