Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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
84 changes: 63 additions & 21 deletions src/common/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,74 @@ export namespace ProjectViews {
export const noPackages = l10n.t('No packages found');
}

export namespace VenvManagerStrings {
export const venvManagerDescription = l10n.t('Manages virtual environments created using `venv`');
export const venvInitialize = l10n.t('Initializing virtual environments');
export const venvRefreshing = l10n.t('Refreshing virtual environments');
export const venvGlobalFolder = l10n.t('Select a folder to create a global virtual environment');
export const venvGlobalFoldersSetting = l10n.t('Venv Folders Setting');
export class VenvManagerStringsNoUv {
static venvManagerDescription = l10n.t('Manages virtual environments created using `venv`');
static venvInitialize = l10n.t('Initializing virtual environments');
static venvRefreshing = l10n.t('Refreshing virtual environments');
static venvGlobalFolder = l10n.t('Select a folder to create a global virtual environment');
static venvGlobalFoldersSetting = l10n.t('Venv Folders Setting');

static venvErrorNoBasePython = l10n.t('No base Python found');
static venvErrorNoPython3 = l10n.t('Did not find any base Python 3');

static venvName = l10n.t('Enter a name for the virtual environment');
static venvNameErrorEmpty = l10n.t('Name cannot be empty');
static venvNameErrorExists = l10n.t('A folder with the same name already exists');
static venvCreateFailed = l10n.t('Failed to create virtual environment');

static venvRemoving = l10n.t('Removing virtual environment');
static venvRemoveFailed = l10n.t('Failed to remove virtual environment');

static installEditable = l10n.t('Install project as editable');
static searchingDependencies = l10n.t('Searching for dependencies');

static selectQuickOrCustomize = l10n.t('Select environment creation mode');
static quickCreate = l10n.t('Quick Create');
static quickCreateDescription = l10n.t('Create a virtual environment in the workspace root');
static customize = l10n.t('Custom');
static customizeDescription = l10n.t('Choose python version, location, packages, name, etc.');
}

export const venvErrorNoBasePython = l10n.t('No base Python found');
export const venvErrorNoPython3 = l10n.t('Did not find any base Python 3');
export class VenvManagerStringsWithUv {
static venvManagerDescription = l10n.t('Manages virtual environments created using `venv [uv]`');
static venvInitialize = l10n.t('Initializing virtual environments');
static venvRefreshing = l10n.t('Refreshing virtual environments');
static venvGlobalFolder = l10n.t('Select a folder to create a global virtual environment');
static venvGlobalFoldersSetting = l10n.t('Venv Folders Setting');

export const venvName = l10n.t('Enter a name for the virtual environment');
export const venvNameErrorEmpty = l10n.t('Name cannot be empty');
export const venvNameErrorExists = l10n.t('A folder with the same name already exists');
export const venvCreateFailed = l10n.t('Failed to create virtual environment');
static venvErrorNoBasePython = l10n.t('No base Python found');
static venvErrorNoPython3 = l10n.t('Did not find any base Python 3');

export const venvRemoving = l10n.t('Removing virtual environment');
export const venvRemoveFailed = l10n.t('Failed to remove virtual environment');
static venvName = l10n.t('Enter a name for the virtual environment');
static venvNameErrorEmpty = l10n.t('Name cannot be empty');
static venvNameErrorExists = l10n.t('A folder with the same name already exists');
static venvCreateFailed = l10n.t('Failed to create virtual environment');

export const installEditable = l10n.t('Install project as editable');
export const searchingDependencies = l10n.t('Searching for dependencies');
static venvRemoving = l10n.t('Removing virtual environment');
static venvRemoveFailed = l10n.t('Failed to remove virtual environment');

export const selectQuickOrCustomize = l10n.t('Select environment creation mode');
export const quickCreate = l10n.t('Quick Create');
export const quickCreateDescription = l10n.t('Create a virtual environment in the workspace root');
export const customize = l10n.t('Custom');
export const customizeDescription = l10n.t('Choose python version, location, packages, name, etc.');
static installEditable = l10n.t('Install project as editable');
static searchingDependencies = l10n.t('Searching for dependencies');

static selectQuickOrCustomize = l10n.t('Select environment creation mode');
static quickCreate = l10n.t('Quick Create');
static quickCreateDescription = l10n.t(
'Create a virtual environment in the workspace root using uv for fast installs',
);
static customize = l10n.t('Custom');
static customizeDescription = l10n.t(
'Choose python version, location, packages, name, etc. (uses uv for installs)',
);
}

/**
* VenvManagerStrings is assigned to either VenvManagerStringsNoUv or VenvManagerStringsWithUv
* depending on which environment manager is active. This variable can be reassigned at runtime.
*/
export let VenvManagerStrings: typeof VenvManagerStringsNoUv | typeof VenvManagerStringsWithUv = VenvManagerStringsNoUv;

export function setVenvManagerStrings(val: typeof VenvManagerStringsNoUv | typeof VenvManagerStringsWithUv) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karthiknadig can you just review this to make sure this structure of setting strings makes sense and follows good coding practices

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually looks a bit weird. There are several string duplicates.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karthiknadig moved to duplicates to a diff function so there shouldn't be repeats. Lmk your thoughts

VenvManagerStrings = val;
}

export namespace SysManagerStrings {
Expand Down
10 changes: 10 additions & 0 deletions src/managers/builtin/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Disposable, LogOutputChannel } from 'vscode';
import { PythonEnvironmentApi } from '../../api';
import { setVenvManagerStrings, VenvManagerStringsWithUv } from '../../common/localize';
import { createSimpleDebounce } from '../../common/utils/debounce';
import { onDidEndTerminalShellExecution } from '../../common/window.apis';
import { createFileSystemWatcher, onDidDeleteFiles } from '../../common/workspace.apis';
import { getPythonApi } from '../../features/pythonApi';
import { NativePythonFinder } from '../common/nativePythonFinder';
import { isUvInstalled } from './helpers';
import { PipPackageManager } from './pipManager';
import { isPipInstallCommand } from './pipUtils';
import { SysPythonManager } from './sysPythonManager';
Expand All @@ -20,6 +22,14 @@ export async function registerSystemPythonFeatures(
const venvManager = new VenvManager(nativeFinder, api, envManager, log);
const pkgManager = new PipPackageManager(api, log, venvManager);

const uvAvailable = await isUvInstalled(log);
if (uvAvailable) {
venvManager.setDisplayName('venv [uv]');
log.info('uv detected - updating venv manager display name');
// Switch all venv-related UI strings to uv versions
setVenvManagerStrings(VenvManagerStringsWithUv);
}

disposables.push(
api.registerPackageManager(pkgManager),
api.registerEnvironmentManager(envManager),
Expand Down
6 changes: 3 additions & 3 deletions src/managers/builtin/pipUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as path from 'path';
import { LogOutputChannel, ProgressLocation, QuickInputButtons, QuickPickItem, Uri } from 'vscode';
import { PackageManagementOptions, PythonEnvironment, PythonEnvironmentApi, PythonProject } from '../../api';
import { EXTENSION_ROOT_DIR } from '../../common/constants';
import { PackageManagement, Pickers, VenvManagerStrings } from '../../common/localize';
import { PackageManagement, Pickers, VenvManagerStringsNoUv } from '../../common/localize';
import { traceInfo } from '../../common/logging';
import { showQuickPickWithButtons, withProgress } from '../../common/window.apis';
import { findFiles } from '../../common/workspace.apis';
Expand Down Expand Up @@ -36,7 +36,7 @@ function getTomlInstallable(toml: tomljs.JsonMap, tomlPath: Uri): Installable[]
extras.push({
name,
displayName: name,
description: VenvManagerStrings.installEditable,
description: VenvManagerStringsNoUv.installEditable,
group: 'TOML',
args: ['-e', projectDir],
uri: tomlPath,
Expand Down Expand Up @@ -177,7 +177,7 @@ export async function getProjectInstallable(
await withProgress(
{
location: ProgressLocation.Notification,
title: VenvManagerStrings.searchingDependencies,
title: VenvManagerStringsNoUv.searchingDependencies,
},
async (_progress, token) => {
const results: Uri[] = (
Expand Down
24 changes: 16 additions & 8 deletions src/managers/builtin/venvManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
SetEnvironmentScope,
} from '../../api';
import { PYTHON_EXTENSION_ID } from '../../common/constants';
import { VenvManagerStrings } from '../../common/localize';
import { VenvManagerStringsNoUv } from '../../common/localize';
import { traceError, traceWarn } from '../../common/logging';
import { createDeferred, Deferred } from '../../common/utils/deferred';
import { showErrorMessage, withProgress } from '../../common/window.apis';
Expand Down Expand Up @@ -66,7 +66,7 @@ export class VenvManager implements EnvironmentManager {
public readonly onDidChangeEnvironments = this._onDidChangeEnvironments.event;

readonly name: string;
readonly displayName: string;
displayName: string; // Made mutable to update with uv detection
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Remove comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the comment as requested. The code is now cleaner without the explanatory comment. Commit: bb30e4f

readonly preferredPackageManagerId: string;
readonly description?: string | undefined;
readonly tooltip?: string | MarkdownString | undefined;
Expand All @@ -83,7 +83,7 @@ export class VenvManager implements EnvironmentManager {
// Descriptions were a bit too visually noisy
// https://github.com/microsoft/vscode-python-environments/issues/167
this.description = undefined;
this.tooltip = new MarkdownString(VenvManagerStrings.venvManagerDescription, true);
this.tooltip = new MarkdownString(VenvManagerStringsNoUv.venvManagerDescription, true);
this.preferredPackageManagerId = 'ms-python.python:pip';
this.iconPath = new ThemeIcon('python');
}
Expand All @@ -97,7 +97,7 @@ export class VenvManager implements EnvironmentManager {
this._initialized = createDeferred();

try {
await this.internalRefresh(undefined, false, VenvManagerStrings.venvInitialize);
await this.internalRefresh(undefined, false, VenvManagerStringsNoUv.venvInitialize);
} finally {
this._initialized.resolve();
}
Expand All @@ -119,6 +119,14 @@ export class VenvManager implements EnvironmentManager {
};
}

/**
* Updates the display name for this environment manager.
* @param name The new display name to set.
*/
public setDisplayName(name: string): void {
this.displayName = name;
}

async create(
scope: CreateEnvironmentScope,
options: CreateEnvironmentOptions | undefined,
Expand Down Expand Up @@ -148,15 +156,15 @@ export class VenvManager implements EnvironmentManager {
// error on missing information
if (!this.globalEnv) {
this.log.error('No base python found');
showErrorMessage(VenvManagerStrings.venvErrorNoBasePython);
showErrorMessage(VenvManagerStringsNoUv.venvErrorNoBasePython);
throw new Error('No base python found');
}
if (!this.globalEnv.version.startsWith('3.')) {
this.log.error('Did not find any base python 3.*');
globals.forEach((e, i) => {
this.log.error(`${i}: ${e.version} : ${e.environmentPath.fsPath}`);
});
showErrorMessage(VenvManagerStrings.venvErrorNoPython3);
showErrorMessage(VenvManagerStringsNoUv.venvErrorNoPython3);
throw new Error('Did not find any base python 3.*');
}
if (this.globalEnv && this.globalEnv.version.startsWith('3.')) {
Expand Down Expand Up @@ -284,14 +292,14 @@ export class VenvManager implements EnvironmentManager {
}

async refresh(scope: RefreshEnvironmentsScope): Promise<void> {
return this.internalRefresh(scope, true, VenvManagerStrings.venvRefreshing);
return this.internalRefresh(scope, true, VenvManagerStringsNoUv.venvRefreshing);
}

async watcherRefresh(): Promise<void> {
if (this.skipWatcherRefresh) {
return;
}
return this.internalRefresh(undefined, true, VenvManagerStrings.venvRefreshing);
return this.internalRefresh(undefined, true, VenvManagerStringsNoUv.venvRefreshing);
}

private async internalRefresh(
Expand Down
Loading
Loading