Skip to content

Commit eff2094

Browse files
authored
Merge branch 'main' into update-wording-variety
2 parents 2e1255e + e4d98a6 commit eff2094

9 files changed

Lines changed: 201 additions & 40 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
mode: agent
3+
---
4+
5+
If the user does not specify an event name or properties, pick an informative and descriptive name for the telemetry event based on the task or feature. Add properties as you see fit to collect the necessary information to achieve the telemetry goal, ensuring they are relevant and useful for diagnostics or analytics.
6+
7+
When adding telemetry:
8+
9+
- If the user wants to record when an action is started (such as a command invocation), place the telemetry call at the start of the handler or function.
10+
- If the user wants to record successful completions or outcomes, place the telemetry call at the end of the action, after the operation has succeeded (and optionally, record errors or failures as well).
11+
12+
Instructions to add a new telemetry event:
13+
14+
1. Add a new event name to the `EventNames` enum in `src/common/telemetry/constants.ts`.
15+
2. Add a corresponding entry to the `IEventNamePropertyMapping` interface in the same file, including a GDPR comment and the expected properties.
16+
3. In the relevant code location, call `sendTelemetryEvent` with the new event name and required properties. Example:
17+
```typescript
18+
sendTelemetryEvent(EventNames.YOUR_EVENT_NAME, undefined, { property: value });
19+
```
20+
4. If the event is triggered by a command, ensure the call is placed at the start of the command handler.
21+
22+
Expected output: The new event is tracked in telemetry and follows the GDPR and codebase conventions.

README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Python Environments (experimental)
1+
# Python Environments (preview)
22

33
## Overview
44

@@ -62,22 +62,32 @@ A "Python Project" is any file or folder that contains runnable Python code and
6262

6363
Projects can be added via the Python Environments pane or in the File Explorer by right-clicking on the folder/file and selecting the "Add as Python Project" menu item.
6464

65-
There are a couple of ways that you can add a Python Project from the Python Environments panel:
65+
There are a few ways to add a Python Project from the Python Environments panel:
6666

6767
| Name | Description |
6868
| ------------ | ---------------------------------------------------------------------- |
6969
| Add Existing | Allows you to add an existing folder from the file explorer. |
7070
| Auto find | Searches for folders that contain `pyproject.toml` or `setup.py` files |
71+
| Create New | Creates a new project from a template. |
72+
73+
#### Create New Project from Template
74+
The **Python Envs: Create New Project from Template** command simplifies the process of starting a new Python project by scaffolding it for you. Whether in a new workspace or an existing one, this command configures the environment and boilerplate file structure, so you don’t have to worry about the initial setup, and only the code you want to write. There are currently two project types supported:
75+
76+
- Package: A structured Python package with files like `__init__.py` and setup configurations.
77+
- Script: A simple project for standalone Python scripts, ideal for quick tasks or just to get you started.
7178

7279
## Command Reference
7380

81+
All commands can be accessed via the Command Palette (`ctrl/cmd + Shift + P`):
82+
7483
| Name | Description |
7584
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
76-
| Python: Create Environment | Create a virtual environment using your preferred environment manager preconfigured with "Quick Create" or configured to your choices. |
77-
| Python: Manage Packages | Install and uninstall packages in a given Python environment. |
78-
| Python: Activate Environment in Current Terminal | Activates the currently opened terminal with a particular environment. |
79-
| Python: Deactivate Environment in Current Terminal | Deactivates environment in currently opened terminal. |
80-
| Python: Run as Task | Runs Python module as a task. |
85+
| Create Environment | Create a virtual environment using your preferred environment manager preconfigured with "Quick Create" or configured to your choices. |
86+
| Manage Packages | Install and uninstall packages in a given Python environment. |
87+
| Activate Environment in Current Terminal | Activates the currently opened terminal with a particular environment. |
88+
| Deactivate Environment in Current Terminal | Deactivates environment in currently opened terminal. |
89+
| Run as Task | Runs Python module as a task. |
90+
| Create New Project from Template | Creates scaffolded project with virtual environments based on a template. |
8191

8292
## Settings Reference
8393

src/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ export interface EnvironmentManager {
379379
quickCreateConfig?(): QuickCreateConfig | undefined;
380380

381381
/**
382-
* Creates a new Python environment within the specified scope.
382+
* Creates a new Python environment within the specified scope. Create should support adding a .gitignore file if it creates a folder within the workspace.
383383
* @param scope - The scope within which to create the environment.
384384
* @param options - Optional parameters for creating the Python environment.
385385
* @returns A promise that resolves to the created Python environment, or undefined if creation failed.

src/common/pickers/environments.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { Uri, ThemeIcon, QuickPickItem, QuickPickItemKind, ProgressLocation, QuickInputButtons } from 'vscode';
2-
import { IconPath, PythonEnvironment, PythonProject } from '../../api';
1+
import { ProgressLocation, QuickInputButtons, QuickPickItem, QuickPickItemKind, ThemeIcon, Uri } from 'vscode';
2+
import { CreateEnvironmentOptions, IconPath, PythonEnvironment, PythonProject } from '../../api';
33
import { InternalEnvironmentManager } from '../../internal.api';
44
import { Common, Interpreter, Pickers } from '../localize';
5-
import { showQuickPickWithButtons, showQuickPick, showOpenDialog, withProgress } from '../window.apis';
65
import { traceError } from '../logging';
7-
import { pickEnvironmentManager } from './managers';
8-
import { handlePythonPath } from '../utils/pythonPath';
6+
import { EventNames } from '../telemetry/constants';
7+
import { sendTelemetryEvent } from '../telemetry/sender';
98
import { isWindows } from '../utils/platformUtils';
9+
import { handlePythonPath } from '../utils/pythonPath';
10+
import { showOpenDialog, showQuickPick, showQuickPickWithButtons, withProgress } from '../window.apis';
11+
import { pickEnvironmentManager } from './managers';
1012

1113
type QuickPickIcon =
1214
| Uri
@@ -77,12 +79,24 @@ async function createEnvironment(
7779
projectEnvManagers.filter((m) => m.supportsCreate),
7880
);
7981

80-
const manager = managers.find((m) => m.id === managerId);
82+
let manager: InternalEnvironmentManager | undefined;
83+
let createOptions: CreateEnvironmentOptions | undefined = undefined;
84+
if (managerId?.includes(`QuickCreate#`)) {
85+
manager = managers.find((m) => m.id === managerId.split('#')[1]);
86+
createOptions = {
87+
projects: projectEnvManagers.map((m) => m),
88+
quickCreate: true,
89+
} as CreateEnvironmentOptions;
90+
} else {
91+
manager = managers.find((m) => m.id === managerId);
92+
}
93+
8194
if (manager) {
8295
try {
96+
// add telemetry here
8397
const env = await manager.create(
8498
options.projects.map((p) => p.uri),
85-
undefined,
99+
createOptions,
86100
);
87101
return env;
88102
} catch (ex) {
@@ -111,6 +125,10 @@ async function pickEnvironmentImpl(
111125
if (selected.label === Interpreter.browsePath) {
112126
return browseForPython(managers, projectEnvManagers);
113127
} else if (selected.label === Interpreter.createVirtualEnvironment) {
128+
sendTelemetryEvent(EventNames.CREATE_ENVIRONMENT, undefined, {
129+
manager: 'none',
130+
triggeredLocation: 'pickEnv',
131+
});
114132
return createEnvironment(managers, projectEnvManagers, options);
115133
}
116134
return (selected as { result: PythonEnvironment })?.result;

src/common/telemetry/constants.ts

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,34 @@ export enum EventNames {
1111
VENV_CREATION = 'VENV.CREATION',
1212

1313
PACKAGE_MANAGEMENT = 'PACKAGE_MANAGEMENT',
14+
ADD_PROJECT = 'ADD_PROJECT',
15+
/**
16+
* Telemetry event for when a Python environment is created via command.
17+
* Properties:
18+
* - manager: string (the id of the environment manager used, or 'none')
19+
* - triggeredLocation: string (where the create command is called from)
20+
*/
21+
CREATE_ENVIRONMENT = 'CREATE_ENVIRONMENT',
1422
}
1523

1624
// Map all events to their properties
1725
export interface IEventNamePropertyMapping {
1826
/* __GDPR__
1927
"extension.activation_duration": {
20-
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
28+
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
2129
}
2230
*/
2331
[EventNames.EXTENSION_ACTIVATION_DURATION]: never | undefined;
2432
/* __GDPR__
2533
"extension.manager_registration_duration": {
26-
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
34+
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
2735
}
2836
*/
2937
[EventNames.EXTENSION_MANAGER_REGISTRATION_DURATION]: never | undefined;
3038

3139
/* __GDPR__
3240
"environment_manager.registered": {
33-
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
41+
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
3442
}
3543
*/
3644
[EventNames.ENVIRONMENT_MANAGER_REGISTERED]: {
@@ -39,7 +47,7 @@ export interface IEventNamePropertyMapping {
3947

4048
/* __GDPR__
4149
"package_manager.registered": {
42-
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
50+
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
4351
}
4452
*/
4553
[EventNames.PACKAGE_MANAGER_REGISTERED]: {
@@ -48,7 +56,7 @@ export interface IEventNamePropertyMapping {
4856

4957
/* __GDPR__
5058
"environment_manager.selected": {
51-
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
59+
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
5260
}
5361
*/
5462
[EventNames.ENVIRONMENT_MANAGER_SELECTED]: {
@@ -57,19 +65,19 @@ export interface IEventNamePropertyMapping {
5765

5866
/* __GDPR__
5967
"package_manager.selected": {
60-
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
68+
"managerId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
6169
}
6270
*/
6371
[EventNames.PACKAGE_MANAGER_SELECTED]: {
6472
managerId: string;
6573
};
6674

6775
/* __GDPR__
68-
"venv.using_uv": {"owner": "karthiknadig" }
76+
"venv.using_uv": {"owner": "eleanorjboyd" }
6977
*/
7078
[EventNames.VENV_USING_UV]: never | undefined /* __GDPR__
7179
"venv.creation": {
72-
"creationType": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
80+
"creationType": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
7381
}
7482
*/;
7583
[EventNames.VENV_CREATION]: {
@@ -78,12 +86,38 @@ export interface IEventNamePropertyMapping {
7886

7987
/* __GDPR__
8088
"package_management": {
81-
"managerId": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" },
82-
"result": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "karthiknadig" }
89+
"managerId": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
90+
"result": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
8391
}
8492
*/
8593
[EventNames.PACKAGE_MANAGEMENT]: {
8694
managerId: string;
8795
result: 'success' | 'error' | 'cancelled';
8896
};
97+
98+
/* __GDPR__
99+
"add_project": {
100+
"template": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
101+
"quickCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
102+
"totalProjectCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
103+
"triggeredLocation": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
104+
}
105+
*/
106+
[EventNames.ADD_PROJECT]: {
107+
template: string;
108+
quickCreate: boolean;
109+
totalProjectCount: number;
110+
triggeredLocation: 'templateCreate' | 'add' | 'addGivenResource';
111+
};
112+
113+
/* __GDPR__
114+
"create_environment": {
115+
"manager": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
116+
"triggeredLocation": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" }
117+
}
118+
*/
119+
[EventNames.CREATE_ENVIRONMENT]: {
120+
manager: string;
121+
triggeredLocation: string;
122+
};
89123
}

0 commit comments

Comments
 (0)