Skip to content

Commit

Permalink
Apply API recommendations for Create Env API (microsoft#21804)
Browse files Browse the repository at this point in the history
  • Loading branch information
karthiknadig authored Aug 15, 2023
1 parent 0248fa8 commit 5140a8d
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 60 deletions.
17 changes: 9 additions & 8 deletions src/client/pythonEnvironments/creation/createEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ function fireStartedEvent(options?: CreateEnvironmentOptions): void {
}

function fireExitedEvent(result?: CreateEnvironmentResult, options?: CreateEnvironmentOptions, error?: Error): void {
onCreateEnvironmentExitedEvent.fire({
options,
workspaceFolder: result?.workspaceFolder,
path: result?.path,
action: result?.action,
error: error || result?.error,
});
startedEventCount -= 1;
if (result) {
onCreateEnvironmentExitedEvent.fire({ options, ...result });
} else if (error) {
onCreateEnvironmentExitedEvent.fire({ options, error });
}
}

export function getCreationEvents(): {
Expand Down Expand Up @@ -195,5 +193,8 @@ export async function handleCreateEnvironmentCommand(
}
}

return result;
if (result) {
return Object.freeze(result);
}
return undefined;
}
99 changes: 71 additions & 28 deletions src/client/pythonEnvironments/creation/proposed.createEnvApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,83 @@ export interface EnvironmentWillCreateEvent {
/**
* Options used to create a Python environment.
*/
options: CreateEnvironmentOptions | undefined;
readonly options: CreateEnvironmentOptions | undefined;
}

export type CreateEnvironmentResult =
| {
/**
* Workspace folder associated with the environment.
*/
readonly workspaceFolder?: WorkspaceFolder;

/**
* Path to the executable python in the environment
*/
readonly path: string;

/**
* User action that resulted in exit from the create environment flow.
*/
readonly action?: CreateEnvironmentUserActions;

/**
* Error if any occurred during environment creation.
*/
readonly error?: Error;
}
| {
/**
* Workspace folder associated with the environment.
*/
readonly workspaceFolder?: WorkspaceFolder;

/**
* Path to the executable python in the environment
*/
readonly path?: string;

/**
* User action that resulted in exit from the create environment flow.
*/
readonly action: CreateEnvironmentUserActions;

/**
* Error if any occurred during environment creation.
*/
readonly error?: Error;
}
| {
/**
* Workspace folder associated with the environment.
*/
readonly workspaceFolder?: WorkspaceFolder;

/**
* Path to the executable python in the environment
*/
readonly path?: string;

/**
* User action that resulted in exit from the create environment flow.
*/
readonly action?: CreateEnvironmentUserActions;

/**
* Error if any occurred during environment creation.
*/
readonly error: Error;
};

/**
* Params passed on `onDidCreateEnvironment` event handler.
*/
export interface EnvironmentDidCreateEvent extends CreateEnvironmentResult {
export type EnvironmentDidCreateEvent = CreateEnvironmentResult & {
/**
* Options used to create the Python environment.
*/
options: CreateEnvironmentOptions | undefined;
}

export interface CreateEnvironmentResult {
/**
* Workspace folder associated with the environment.
*/
workspaceFolder: WorkspaceFolder | undefined;

/**
* Path to the executable python in the environment
*/
path: string | undefined;

/**
* User action that resulted in exit from the create environment flow.
*/
action: CreateEnvironmentUserActions | undefined;

/**
* Error if any occurred during environment creation.
*/
error: Error | undefined;
}
readonly options: CreateEnvironmentOptions | undefined;
};

/**
* Extensions that want to contribute their own environment creation can do that by registering an object
Expand Down Expand Up @@ -120,14 +163,14 @@ export interface ProposedCreateEnvironmentAPI {
* provider (including internal providers). This will also receive any options passed in
* or defaults used to create environment.
*/
onWillCreateEnvironment: Event<EnvironmentWillCreateEvent>;
readonly onWillCreateEnvironment: Event<EnvironmentWillCreateEvent>;

/**
* This API can be used to detect when the environment provider exits for any registered
* provider (including internal providers). This will also receive created environment path,
* any errors, or user actions taken from the provider.
*/
onDidCreateEnvironment: Event<EnvironmentDidCreateEvent>;
readonly onDidCreateEnvironment: Event<EnvironmentDidCreateEvent>;

/**
* This API will show a QuickPick to select an environment provider from available list of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { CancellationToken, ProgressLocation, WorkspaceFolder } from 'vscode';
import * as path from 'path';
import { Commands, PVSC_EXTENSION_ID } from '../../../common/constants';
import { traceError, traceLog } from '../../../logging';
import { traceError, traceInfo, traceLog } from '../../../logging';
import { CreateEnvironmentProgress } from '../types';
import { pickWorkspaceFolder } from '../common/workspaceSelection';
import { execObservable } from '../../../common/process/rawProcessApis';
Expand Down Expand Up @@ -77,7 +77,7 @@ async function createCondaEnv(
args: string[],
progress: CreateEnvironmentProgress,
token?: CancellationToken,
): Promise<string | undefined> {
): Promise<string> {
progress.report({
message: CreateEnv.Conda.creating,
});
Expand Down Expand Up @@ -174,6 +174,7 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
traceError('Workspace was not selected or found for creating conda environment.');
return MultiStepAction.Cancel;
}
traceInfo(`Selected workspace ${workspace.uri.fsPath} for creating conda environment.`);
return MultiStepAction.Continue;
},
undefined,
Expand All @@ -196,6 +197,7 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
traceError('Python version was not selected for creating conda environment.');
return MultiStepAction.Cancel;
}
traceInfo(`Selected Python version ${version} for creating conda environment.`);
return MultiStepAction.Continue;
},
undefined,
Expand All @@ -217,8 +219,6 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
progress: CreateEnvironmentProgress,
token: CancellationToken,
): Promise<CreateEnvironmentResult | undefined> => {
let hasError = false;

progress.report({
message: CreateEnv.statusStarting,
});
Expand All @@ -237,17 +237,20 @@ async function createEnvironment(options?: CreateEnvironmentOptions): Promise<Cr
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);
hasError = true;
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
throw ex;
} finally {
if (hasError) {
showErrorMessageWithLogs(CreateEnv.Conda.errorCreatingEnvironment);
}
}
return { path: envPath, workspaceFolder: workspace, action: undefined, error: undefined };
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { createVenvScript } from '../../../common/process/internal/scripts';
import { execObservable } from '../../../common/process/rawProcessApis';
import { createDeferred } from '../../../common/utils/async';
import { Common, CreateEnv } from '../../../common/utils/localize';
import { traceError, traceLog, traceVerbose } from '../../../logging';
import { traceError, traceInfo, traceLog, traceVerbose } from '../../../logging';
import { CreateEnvironmentProgress } from '../types';
import { pickWorkspaceFolder } from '../common/workspaceSelection';
import { IInterpreterQuickPick } from '../../../interpreter/configuration/types';
Expand Down Expand Up @@ -144,6 +144,7 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
traceError('Workspace was not selected or found for creating virtual environment.');
return MultiStepAction.Cancel;
}
traceInfo(`Selected workspace ${workspace.uri.fsPath} for creating virtual environment.`);
return MultiStepAction.Continue;
},
undefined,
Expand Down Expand Up @@ -183,6 +184,7 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
traceError('Virtual env creation requires an interpreter.');
return MultiStepAction.Cancel;
}
traceInfo(`Selected interpreter ${interpreter} for creating virtual environment.`);
return MultiStepAction.Continue;
},
undefined,
Expand Down Expand Up @@ -237,8 +239,6 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
progress: CreateEnvironmentProgress,
token: CancellationToken,
): Promise<CreateEnvironmentResult | undefined> => {
let hasError = false;

progress.report({
message: CreateEnv.statusStarting,
});
Expand All @@ -247,18 +247,19 @@ export class VenvCreationProvider implements CreateEnvironmentProvider {
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);
hasError = true;
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
throw ex;
} finally {
if (hasError) {
showErrorMessageWithLogs(CreateEnv.Venv.errorCreatingEnvironment);
}
}

return { path: envPath, workspaceFolder: workspace, action: undefined, error: undefined };
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ suite('Conda Creation provider tests', () => {
assert.deepStrictEqual(await promise, {
path: 'new_environment',
workspaceFolder: workspace1,
action: undefined,
error: undefined,
});
assert.isTrue(showErrorMessageWithLogsStub.notCalled);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,6 @@ suite('venv Creation provider tests', () => {
assert.deepStrictEqual(actual, {
path: 'new_environment',
workspaceFolder: workspace1,
action: undefined,
error: undefined,
});
interpreterQuickPick.verifyAll();
progressMock.verifyAll();
Expand Down

0 comments on commit 5140a8d

Please sign in to comment.