From 684849247541acb25c1edc5145315c00357df86c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:32:39 +0000 Subject: [PATCH 1/2] chore(deps-dev): bump js-yaml from 4.1.1 to 4.2.0 in /examples/sample1 Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.2.0. - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/commits) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 4.2.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- examples/sample1/package-lock.json | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/sample1/package-lock.json b/examples/sample1/package-lock.json index 17d87895..b263745e 100644 --- a/examples/sample1/package-lock.json +++ b/examples/sample1/package-lock.json @@ -2663,10 +2663,20 @@ } }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" From a2c697ffee513033e913ddd4628950a18ca403d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 00:11:01 +0000 Subject: [PATCH 2/2] fix: use deterministic path-based hash for environment ID in createPythonEnvironmentItem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The integration test "File in project uses project environment" was failing because createPythonEnvironmentItem used Math.random() for the ID suffix. When setEnvironment() persists to python-envs.pythonProjects settings, registerInterpreterSettingsChangeListener re-triggers applyInitialEnvironmentSelection which re-resolves the same interpreter path — but creates a new object with a different random ID — and overwrites the in-memory state. The subsequent getEnvironment(fileUri) call then returns the wrong ID. Fix: replace Math.random() with a deterministic djb2-style hash of the normalized executable path so the same interpreter always maps to the same ID regardless of how many times it is resolved. --- src/features/pythonApi.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/features/pythonApi.ts b/src/features/pythonApi.ts index 1cd8217a..4e0f8650 100644 --- a/src/features/pythonApi.ts +++ b/src/features/pythonApi.ts @@ -34,7 +34,7 @@ import { import { traceError, traceInfo } from '../common/logging'; import { pickEnvironmentManager } from '../common/pickers/managers'; import { createDeferred } from '../common/utils/deferred'; -import { checkUri } from '../common/utils/pathUtils'; +import { checkUri, normalizePath } from '../common/utils/pathUtils'; import { handlePythonPath } from '../common/utils/pythonPath'; import { EnvironmentManagers, @@ -51,6 +51,23 @@ import { runInBackground } from './execution/runInBackground'; import { runInTerminal } from './terminal/runInTerminal'; import { TerminalManager } from './terminal/terminalManager'; +/** + * Produces a short, deterministic base-36 suffix from an environment executable fsPath. + * Using the path rather than Math.random() ensures that resolving the same interpreter + * multiple times within a session always yields the same environment ID. + * The path is normalized to handle case-insensitive file systems (e.g. Windows). + */ +function envPathHash(fsPath: string): string { + // djb2-style hash over the normalized path characters + const normalized = normalizePath(fsPath); + let hash = 5381; + for (let i = 0; i < normalized.length; i++) { + hash = ((hash << 5) + hash) ^ normalized.charCodeAt(i); + hash = hash >>> 0; // keep as unsigned 32-bit integer + } + return hash.toString(36); +} + class PythonEnvironmentApiImpl implements PythonEnvironmentApi { private readonly _onDidChangeEnvironments = new EventEmitter(); private readonly _onDidChangeEnvironment = new EventEmitter(); @@ -112,10 +129,14 @@ class PythonEnvironmentApiImpl implements PythonEnvironmentApi { if (!mgr) { throw new Error('Environment manager not found'); } - const randomStr = Math.random().toString(36).substring(2); + // Use a deterministic hash of the environment executable path so that resolving + // the same interpreter multiple times (e.g., during settings-change re-evaluation) + // always produces the same ID. This avoids ID mismatches when + // applyInitialEnvironmentSelection re-resolves an env that was just set by the API. + const pathSuffix = envPathHash(info.environmentPath.fsPath); const envId: PythonEnvironmentId = { managerId: mgr.id, - id: `${info.name}-${randomStr}`, + id: `${info.name}-${pathSuffix}`, }; return new PythonEnvironmentImpl(envId, info); }