diff --git a/src/common/pickers/environments.ts b/src/common/pickers/environments.ts index 5af90d7c..5f6ab63b 100644 --- a/src/common/pickers/environments.ts +++ b/src/common/pickers/environments.ts @@ -157,6 +157,12 @@ export async function pickEnvironment( ]; if (options?.recommended) { + const pathDescription = options.recommended.displayPath; + const description = + options.recommended.description && options.recommended.description.trim() + ? `${options.recommended.description} (${pathDescription})` + : pathDescription; + items.push( { label: Common.recommended, @@ -164,7 +170,7 @@ export async function pickEnvironment( }, { label: options.recommended.displayName, - description: options.recommended.description, + description: description, result: options.recommended, iconPath: getIconPath(options.recommended.iconPath), }, @@ -179,9 +185,13 @@ export async function pickEnvironment( const envs = await manager.getEnvironments('all'); items.push( ...envs.map((e) => { + const pathDescription = e.displayPath; + const description = + e.description && e.description.trim() ? `${e.description} (${pathDescription})` : pathDescription; + return { label: e.displayName ?? e.name, - description: e.description, + description: description, result: e, manager: manager, iconPath: getIconPath(e.iconPath), @@ -194,12 +204,18 @@ export async function pickEnvironment( } export async function pickEnvironmentFrom(environments: PythonEnvironment[]): Promise { - const items = environments.map((e) => ({ - label: e.displayName ?? e.name, - description: e.description, - e: e, - iconPath: getIconPath(e.iconPath), - })); + const items = environments.map((e) => { + const pathDescription = e.displayPath; + const description = + e.description && e.description.trim() ? `${e.description} (${pathDescription})` : pathDescription; + + return { + label: e.displayName ?? e.name, + description: description, + e: e, + iconPath: getIconPath(e.iconPath), + }; + }); const selected = await showQuickPick(items, { placeHolder: Pickers.Environments.selectEnvironment, ignoreFocusOut: true, diff --git a/src/test/common/environmentPicker.unit.test.ts b/src/test/common/environmentPicker.unit.test.ts new file mode 100644 index 00000000..dc0ee3c1 --- /dev/null +++ b/src/test/common/environmentPicker.unit.test.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import assert from 'node:assert'; +import { Uri } from 'vscode'; +import { PythonEnvironment } from '../../api'; + +/** + * Test the logic used in environment pickers to include interpreter paths in descriptions + */ +suite('Environment Picker Description Logic', () => { + const createMockEnvironment = ( + displayPath: string, + description?: string, + name: string = 'Python 3.9.0', + ): PythonEnvironment => ({ + envId: { id: 'test', managerId: 'test-manager' }, + name, + displayName: name, + displayPath, + version: '3.9.0', + environmentPath: Uri.file(displayPath), + description, + sysPrefix: '/path/to/prefix', + execInfo: { run: { executable: displayPath } }, + }); + + suite('Description formatting with interpreter path', () => { + test('should use displayPath as description when no original description exists', () => { + const env = createMockEnvironment('/usr/local/bin/python'); + + // This is the logic from our updated picker + const pathDescription = env.displayPath; + const description = + env.description && env.description.trim() ? `${env.description} (${pathDescription})` : pathDescription; + + assert.strictEqual(description, '/usr/local/bin/python'); + }); + + test('should append displayPath to existing description in parentheses', () => { + const env = createMockEnvironment('/home/user/.venv/bin/python', 'Virtual Environment'); + + // This is the logic from our updated picker + const pathDescription = env.displayPath; + const description = + env.description && env.description.trim() ? `${env.description} (${pathDescription})` : pathDescription; + + assert.strictEqual(description, 'Virtual Environment (/home/user/.venv/bin/python)'); + }); + + test('should handle complex paths correctly', () => { + const complexPath = '/usr/local/anaconda3/envs/my-project-env/bin/python'; + const env = createMockEnvironment(complexPath, 'Conda Environment'); + + // This is the logic from our updated picker + const pathDescription = env.displayPath; + const description = + env.description && env.description.trim() ? `${env.description} (${pathDescription})` : pathDescription; + + assert.strictEqual(description, `Conda Environment (${complexPath})`); + }); + + test('should handle empty description correctly', () => { + const env = createMockEnvironment('/opt/python/bin/python', ''); + + // This is the logic from our updated picker + const pathDescription = env.displayPath; + const description = + env.description && env.description.trim() ? `${env.description} (${pathDescription})` : pathDescription; + + // Empty string should be treated like no description, so just use path + assert.strictEqual(description, '/opt/python/bin/python'); + }); + + test('should handle Windows paths correctly', () => { + const windowsPath = 'C:\\Python39\\python.exe'; + const env = createMockEnvironment(windowsPath, 'System Python'); + + // This is the logic from our updated picker + const pathDescription = env.displayPath; + const description = + env.description && env.description.trim() ? `${env.description} (${pathDescription})` : pathDescription; + + assert.strictEqual(description, 'System Python (C:\\Python39\\python.exe)'); + }); + }); +});