Skip to content
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
8 changes: 7 additions & 1 deletion src/features/envCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export async function refreshPackagesCommand(context: unknown, managers?: Enviro
}
}

/**
* Creates a Python environment using the manager implied by the context (no user prompt).
*/
export async function createEnvironmentCommand(
context: unknown,
em: EnvironmentManagers,
Expand All @@ -94,7 +97,7 @@ export async function createEnvironmentCommand(
const scope = selected.length === 0 ? 'global' : selected.map((p) => p.uri);
const env = await manager.create(scope, undefined);
if (env) {
await em.setEnvironments(scope, env);
await em.setEnvironmentsIfUnset(scope, env);
}
return env;
} else {
Expand All @@ -114,6 +117,9 @@ export async function createEnvironmentCommand(
}
}

/**
* Prompts the user to pick the environment manager and project(s) for environment creation.
*/
export async function createAnyEnvironmentCommand(
em: EnvironmentManagers,
pm: PythonProjectManager,
Expand Down
76 changes: 63 additions & 13 deletions src/features/envManagers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Disposable, EventEmitter, Uri, workspace, ConfigurationTarget, Event } from 'vscode';
import { ConfigurationTarget, Disposable, Event, EventEmitter, Uri, workspace } from 'vscode';
import {
DidChangeEnvironmentEventArgs,
DidChangeEnvironmentsEventArgs,
Expand All @@ -10,13 +10,14 @@ import {
PythonProject,
SetEnvironmentScope,
} from '../api';
import { traceError, traceVerbose } from '../common/logging';
import {
EditAllManagerSettings,
getDefaultEnvManagerSetting,
getDefaultPkgManagerSetting,
setAllManagerSettings,
} from './settings/settingHelpers';
EnvironmentManagerAlreadyRegisteredError,
PackageManagerAlreadyRegisteredError,
} from '../common/errors/AlreadyRegisteredError';
import { traceError, traceVerbose } from '../common/logging';
import { EventNames } from '../common/telemetry/constants';
import { sendTelemetryEvent } from '../common/telemetry/sender';
import { getCallingExtension } from '../common/utils/frameUtils';
import {
DidChangeEnvironmentManagerEventArgs,
DidChangePackageManagerEventArgs,
Expand All @@ -30,13 +31,12 @@ import {
PythonProjectManager,
PythonProjectSettings,
} from '../internal.api';
import { getCallingExtension } from '../common/utils/frameUtils';
import {
EnvironmentManagerAlreadyRegisteredError,
PackageManagerAlreadyRegisteredError,
} from '../common/errors/AlreadyRegisteredError';
import { sendTelemetryEvent } from '../common/telemetry/sender';
import { EventNames } from '../common/telemetry/constants';
EditAllManagerSettings,
getDefaultEnvManagerSetting,
getDefaultPkgManagerSetting,
setAllManagerSettings,
} from './settings/settingHelpers';

function generateId(name: string): string {
const newName = name.toLowerCase().replace(/[^a-zA-Z0-9-_]/g, '_');
Expand Down Expand Up @@ -165,6 +165,10 @@ export class PythonEnvironmentManagers implements EnvironmentManagers {
this._onDidChangePackages.dispose();
}

/**
* Returns the environment manager for the given context.
* Uses the default from settings if context is undefined or a Uri; otherwise uses the id or environment's managerId passed in via context.
*/
public getEnvironmentManager(context: EnvironmentManagerScope): InternalEnvironmentManager | undefined {
if (this._environmentManagers.size === 0) {
traceError('No environment managers registered');
Expand Down Expand Up @@ -256,6 +260,10 @@ export class PythonEnvironmentManagers implements EnvironmentManagers {
}
}

/**
* Sets the environment for a single scope, scope of undefined checks 'global'.
* If given an array of scopes, delegates to setEnvironments for batch setting.
*/
public async setEnvironment(scope: SetEnvironmentScope, environment?: PythonEnvironment): Promise<void> {
if (Array.isArray(scope)) {
return this.setEnvironments(scope, environment);
Expand Down Expand Up @@ -299,6 +307,10 @@ export class PythonEnvironmentManagers implements EnvironmentManagers {
}
}

/**
* Sets the given environment for the specified project URIs or globally.
* If a list of URIs is provided, sets the environment for each project; if 'global', sets it as the global environment.
*/
public async setEnvironments(scope: Uri[] | string, environment?: PythonEnvironment): Promise<void> {
if (environment) {
const manager = this.managers.find((m) => m.id === environment.envId.managerId);
Expand Down Expand Up @@ -403,6 +415,44 @@ export class PythonEnvironmentManagers implements EnvironmentManagers {
}
}

/**
* Sets the environment for the given scopes, but only if the scope is not already set (i.e., is global or undefined).
* Existing environments for a scope are not overwritten.
*
*/
public async setEnvironmentsIfUnset(scope: Uri[] | string, environment?: PythonEnvironment): Promise<void> {
if (!environment) {
return;
}
if (typeof scope === 'string' && scope === 'global') {
const current = await this.getEnvironment(undefined);
if (!current) {
await this.setEnvironments('global', environment);
}
} else if (Array.isArray(scope)) {
const urisToSet: Uri[] = [];
for (const uri of scope) {
const current = await this.getEnvironment(uri);
if (!current || current.envId.managerId === 'ms-python.python:system') {
// If the current environment is not set or is the system environment, set the new environment.
urisToSet.push(uri);
}
}
if (urisToSet.length > 0) {
await this.setEnvironments(urisToSet, environment);
}
}
}

/**
* Gets the current Python environment for the given scope URI or undefined for 'global'.
*
* This method queries the appropriate environment manager for the latest environment for the scope.
* It also updates the internal cache and fires an event if the environment has changed since last check.
*
* @param scope The scope to get the environment.
* @returns The current PythonEnvironment for the scope, or undefined if none is set.
*/
async getEnvironment(scope: GetEnvironmentScope): Promise<PythonEnvironment | undefined> {
const manager = this.getEnvironmentManager(scope);
if (!manager) {
Expand Down
37 changes: 19 additions & 18 deletions src/internal.api.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { CancellationError, Disposable, Event, LogOutputChannel, MarkdownString, Uri } from 'vscode';
import {
PythonEnvironment,
EnvironmentManager,
PackageManager,
Package,
IconPath,
CreateEnvironmentOptions,
CreateEnvironmentScope,
DidChangeEnvironmentEventArgs,
DidChangeEnvironmentsEventArgs,
DidChangePackagesEventArgs,
PythonProject,
RefreshEnvironmentsScope,
GetEnvironmentsScope,
CreateEnvironmentScope,
SetEnvironmentScope,
EnvironmentGroupInfo,
EnvironmentManager,
GetEnvironmentScope,
PythonEnvironmentId,
PythonEnvironmentExecutionInfo,
PythonEnvironmentInfo,
GetEnvironmentsScope,
IconPath,
Package,
PackageChangeKind,
PackageId,
PackageInfo,
PythonProjectCreator,
ResolveEnvironmentContext,
PackageManagementOptions,
EnvironmentGroupInfo,
PackageManager,
PythonEnvironment,
PythonEnvironmentExecutionInfo,
PythonEnvironmentId,
PythonEnvironmentInfo,
PythonProject,
PythonProjectCreator,
QuickCreateConfig,
CreateEnvironmentOptions,
RefreshEnvironmentsScope,
ResolveEnvironmentContext,
SetEnvironmentScope,
} from './api';
import { CreateEnvironmentNotSupported, RemoveEnvironmentNotSupported } from './common/errors/NotSupportedError';
import { sendTelemetryEvent } from './common/telemetry/sender';
import { EventNames } from './common/telemetry/constants';
import { sendTelemetryEvent } from './common/telemetry/sender';

export type EnvironmentManagerScope = undefined | string | Uri | PythonEnvironment;
export type PackageManagerScope = undefined | string | Uri | PythonEnvironment | Package;
Expand Down Expand Up @@ -111,6 +111,7 @@ export interface EnvironmentManagers extends Disposable {

setEnvironment(scope: SetEnvironmentScope, environment?: PythonEnvironment): Promise<void>;
setEnvironments(scope: Uri[] | string, environment?: PythonEnvironment): Promise<void>;
setEnvironmentsIfUnset(scope: Uri[] | string, environment?: PythonEnvironment): Promise<void>;
getEnvironment(scope: GetEnvironmentScope): Promise<PythonEnvironment | undefined>;

getProjectEnvManagers(uris: Uri[]): InternalEnvironmentManager[];
Expand Down