-
Notifications
You must be signed in to change notification settings - Fork 41
telemetry and comments to breakdown startup flow #1400
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
eleanorjboyd
merged 4 commits into
microsoft:main
from
eleanorjboyd:uninterested-meerkat
Mar 27, 2026
+182
−2
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
|
|
||
| # Startup Flow for Python Environments Extension | ||
|
|
||
|
|
||
| user opens VS Code | ||
| python environments extension begins activation | ||
|
|
||
| SYNC (`activate` in extension.ts): | ||
| 1. create core objects: ProjectManager, EnvironmentManagers, ManagerReady | ||
| 2. `setPythonApi()` — API object created, deferred resolved (API is now available to consumers) | ||
| 3. create views (EnvManagerView, ProjectView), status bar, terminal manager | ||
| 4. register all commands | ||
| 5. activate() returns — extension is "active" from VS Code's perspective | ||
|
|
||
| 📊 TELEMETRY: EXTENSION.ACTIVATION_DURATION { duration } | ||
|
|
||
| ASYNC (setImmediate callback, still in extension.ts): | ||
| 1. spawn PET process (`createNativePythonFinder`) | ||
| 1. sets up a JSON-RPC connection to it over stdin/stdout | ||
| 2. register all built-in managers in parallel (Promise.all): | ||
| - for each manager (system, conda, pyenv, pipenv, poetry): | ||
| 1. check if tool exists (e.g. `getConda(nativeFinder)` asks PET for the conda binary) | ||
| 2. if tool not found → log, return early (manager not registered) | ||
| 3. if tool found → create manager, call `api.registerEnvironmentManager(manager)` | ||
| - this adds it to the `EnvironmentManagers` map | ||
| - fires `onDidChangeEnvironmentManager` → `ManagerReady` deferred resolves for this manager | ||
| 3. all registrations complete (Promise.all resolves) | ||
|
|
||
| --- gate point: `applyInitialEnvironmentSelection` --- | ||
| 📊 TELEMETRY: ENV_SELECTION.STARTED { duration (activation→here), registeredManagerCount, registeredManagerIds, workspaceFolderCount } | ||
|
|
||
| 1. for each workspace folder + global scope (no workspace case), run `resolvePriorityChainCore` to find manager: | ||
| - P1: pythonProjects[] setting → specific manager for this project | ||
| - P2: user-configured defaultEnvManager setting | ||
| - P3: user-configured python.defaultInterpreterPath → nativeFinder.resolve(path) | ||
| - P4: auto-discovery → try venv manager (local .venv), fall back to system python | ||
| - for workspace scope: ask venv manager if there's a local env (.venv/venv in the folder) | ||
| - if found → use venv manager with that env | ||
| - if not found → fall back to system python manager | ||
| - for global scope: use system python manager directly | ||
|
|
||
| 2. get the environment from the winning priority level: | ||
|
|
||
| --- fork point: `result.environment ?? await result.manager.get(folder.uri)` --- | ||
| left side truthy = envPreResolved | left side undefined = managerDiscovery | ||
|
|
||
| envPreResolved — P3 won (interpreter → manager): | ||
| `resolvePriorityChainCore` calls `tryResolveInterpreterPath()`: | ||
| 1. `nativeFinder.resolve(path)` — single PET call, resolves just this one binary | ||
| 2. find which manager owns the resolved env (by managerId) | ||
| 3. return { manager, environment } — BOTH are known | ||
| → result.environment is set → the `??` short-circuits | ||
| → no `manager.get()` called, no `initialize()`, no full discovery | ||
|
|
||
| managerDiscovery — P1, P2, or P4 won (manager → interpreter): | ||
| `resolvePriorityChainCore` returns { manager, environment: undefined } | ||
| → result.environment is undefined → falls through to `await result.manager.get(scope)` | ||
| `manager.get(scope)` (e.g. `CondaEnvManager.get()`): | ||
| 4. `initialize()` — lazy, once-only per manager (guarded by deferred) | ||
| a. `nativeFinder.refresh(hardRefresh=false)`: | ||
| → `handleSoftRefresh()` checks in-memory cache (Map) for key 'all' (bc one big scan, shared cache, all managers benefit) | ||
| - on reload: cache is empty (Map was destroyed) → cache miss | ||
| - falls through to `handleHardRefresh()` | ||
| → `handleHardRefresh()`: | ||
| - adds request to WorkerPool queue (concurrency 1, so serialized) | ||
| - when its turn comes, calls `doRefresh()`: | ||
| 1. `configure()` — JSON-RPC to PET with search paths, conda/poetry/pipenv paths, cache dir | ||
| 2. `refresh` — JSON-RPC to PET, PET scans filesystem | ||
| - PET may use its own on-disk cache (cacheDirectory) to speed this up | ||
| - PET streams back results as 'environment' and 'manager' notifications | ||
| - envs missing version/prefix get an inline resolve() call | ||
| 3. returns NativeInfo[] (all envs of all types) | ||
| - result stored in in-memory cache under key 'all' | ||
| → subsequent managers calling nativeFinder.refresh(false) get cache hit → instant | ||
| b. filter results to this manager's env type (e.g. conda filters to kind=conda) | ||
| c. convert NativeEnvInfo → PythonEnvironment objects → populate collection | ||
| d. `loadEnvMap()` — reads persisted env path from workspace state | ||
| → matches path against freshly discovered collection via `findEnvironmentByPath()` | ||
| → populates `fsPathToEnv` map | ||
| 5. look up scope in `fsPathToEnv` → return the matched env | ||
|
|
||
| 📊 TELEMETRY: ENV_SELECTION.RESULT (per scope) { duration (priority chain + manager.get), scope, prioritySource, managerId, path, hasPersistedSelection } | ||
|
|
||
| 3. env is cached in memory (no settings.json write) | ||
| 4. Python extension / status bar can now get the selected env via `api.getEnvironment(scope)` | ||
|
|
||
| 📊 TELEMETRY: EXTENSION.MANAGER_REGISTRATION_DURATION { duration (activation→here), result, failureStage?, errorType? } | ||
|
|
||
| POST-INIT: | ||
| 1. register terminal package watcher | ||
| 2. register settings change listener (`registerInterpreterSettingsChangeListener`) — re-runs priority chain if settings change | ||
| 3. initialize terminal manager | ||
| 4. send telemetry (manager selection, project structure, discovery summary) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.