@@ -4,6 +4,7 @@ import * as path from 'path';
44import * as sinon from 'sinon' ;
55import { CancellationToken , LogOutputChannel , ShellExecution , TaskExecution , TaskProcessEndEvent } from 'vscode' ;
66import * as childProcessApis from '../../../common/childProcess.apis' ;
7+ import * as envApis from '../../../common/env.apis' ;
78import { Common , UvInstallStrings } from '../../../common/localize' ;
89import * as persistentState from '../../../common/persistentState' ;
910import { EventNames } from '../../../common/telemetry/constants' ;
@@ -36,6 +37,7 @@ suite('uvPythonInstaller - promptInstallPythonViaUv', () => {
3637 let isUvInstalledStub : sinon . SinonStub ;
3738 let showErrorMessageStub : sinon . SinonStub ;
3839 let showInformationMessageStub : sinon . SinonStub ;
40+ let launchBrowserStub : sinon . SinonStub ;
3941 let sendTelemetryEventStub : sinon . SinonStub ;
4042 let mockState : { get : sinon . SinonStub ; set : sinon . SinonStub ; clear : sinon . SinonStub } ;
4143
@@ -53,6 +55,7 @@ suite('uvPythonInstaller - promptInstallPythonViaUv', () => {
5355 sinon . stub ( helpers , 'getUvExecutable' ) . resolves ( 'uv' ) ;
5456 showErrorMessageStub = sinon . stub ( windowApis , 'showErrorMessage' ) ;
5557 showInformationMessageStub = sinon . stub ( windowApis , 'showInformationMessage' ) ;
58+ launchBrowserStub = sinon . stub ( envApis , 'launchBrowser' ) . resolves ( true ) ;
5659 sendTelemetryEventStub = sinon . stub ( telemetrySender , 'sendTelemetryEvent' ) ;
5760 } ) ;
5861
@@ -289,9 +292,31 @@ suite('uvPythonInstaller - promptInstallPythonViaUv', () => {
289292 UvInstallStrings . installUvForVersionLookupPrompt ,
290293 { modal : true } ,
291294 UvInstallStrings . installUv ,
295+ UvInstallStrings . otherPythonInstallationOptions ,
296+ UvInstallStrings . close ,
292297 ) ;
293298 } ) ;
294299
300+ test ( 'should open alternate Python installation guidance' , async ( ) => {
301+ isUvInstalledStub . resolves ( false ) ;
302+ showInformationMessageStub . resolves ( UvInstallStrings . otherPythonInstallationOptions ) ;
303+
304+ assert . strictEqual ( await ensureUvForPythonVersionLookup ( mockLog ) , false ) ;
305+ sinon . assert . calledOnceWithExactly (
306+ launchBrowserStub ,
307+ 'https://code.visualstudio.com/docs/python/python-tutorial#_install-a-python-interpreter' ,
308+ ) ;
309+ } ) ;
310+
311+ test ( 'should close global Python version lookup without installing uv' , async ( ) => {
312+ isUvInstalledStub . resolves ( false ) ;
313+ showInformationMessageStub . resolves ( UvInstallStrings . close ) ;
314+
315+ assert . strictEqual ( await ensureUvForPythonVersionLookup ( mockLog ) , false ) ;
316+ sinon . assert . notCalled ( launchBrowserStub ) ;
317+ assert . strictEqual ( showErrorMessageStub . callCount , 0 ) ;
318+ } ) ;
319+
295320 test ( 'should install uv for global Python version lookup after consent' , async ( ) => {
296321 isUvInstalledStub . onFirstCall ( ) . resolves ( false ) ;
297322 isUvInstalledStub . onSecondCall ( ) . resolves ( true ) ;
@@ -303,6 +328,17 @@ suite('uvPythonInstaller - promptInstallPythonViaUv', () => {
303328 assert . strictEqual ( executeTaskStub . callCount , 1 ) ;
304329 } ) ;
305330
331+ test ( 'should report a failed uv installation for global Python version lookup' , async ( ) => {
332+ isUvInstalledStub . resolves ( false ) ;
333+ showInformationMessageStub . resolves ( UvInstallStrings . installUv ) ;
334+ showErrorMessageStub . resolves ( Common . viewLogs ) ;
335+ stubUvInstallTask ( 1 ) ;
336+
337+ assert . strictEqual ( await ensureUvForPythonVersionLookup ( mockLog ) , false ) ;
338+ sinon . assert . calledOnceWithExactly ( showErrorMessageStub , UvInstallStrings . uvInstallFailed , Common . viewLogs ) ;
339+ sinon . assert . calledOnce ( mockLog . show as sinon . SinonStub ) ;
340+ } ) ;
341+
306342 test ( 'should install uv before fetching versions and selecting Python' , async ( ) => {
307343 const order : string [ ] = [ ] ;
308344 isUvInstalledStub . onFirstCall ( ) . resolves ( false ) ;
@@ -563,6 +599,7 @@ suite('uvPythonInstaller - executable handoff', () => {
563599 let spawnStub : sinon . SinonStub ;
564600 let executeTaskStub : sinon . SinonStub ;
565601 let telemetryStub : sinon . SinonStub ;
602+ let showInformationMessageStub : sinon . SinonStub ;
566603 let expectedExecutable : string ;
567604 const pythonPath = path . join ( home , 'managed-python' , 'python' ) ;
568605
@@ -588,7 +625,7 @@ suite('uvPythonInstaller - executable handoff', () => {
588625 expectedExecutable = path . join ( installDir , 'uv' ) ;
589626 telemetryStub = sinon . stub ( telemetrySender , 'sendTelemetryEvent' ) ;
590627 sinon . stub ( windowApis , 'showErrorMessage' ) ;
591- sinon . stub ( windowApis , 'showInformationMessage' ) ;
628+ showInformationMessageStub = sinon . stub ( windowApis , 'showInformationMessage' ) ;
592629 sinon
593630 . stub ( windowApis , 'withProgress' )
594631 . callsFake ( async ( _options , task ) =>
@@ -662,6 +699,19 @@ suite('uvPythonInstaller - executable handoff', () => {
662699 assert ( ! telemetryStub . calledWith ( EventNames . UV_PYTHON_INSTALL_FAILED ) ) ;
663700 } ) ;
664701
702+ test ( 'uses the installed executable to populate the Global version picker when PATH is unchanged' , async ( ) => {
703+ const originalPath = process . env . PATH ;
704+ showInformationMessageStub . resolves ( UvInstallStrings . installUv ) ;
705+ sinon . stub ( windowApis , 'showQuickPick' ) . callsFake ( async ( items ) => ( Array . isArray ( items ) ? items [ 0 ] : undefined ) ) ;
706+
707+ assert . strictEqual ( await selectPythonVersionToInstall ( ) , '3.11.15' ) ;
708+
709+ assert . strictEqual ( process . env . PATH , originalPath ) ;
710+ sinon . assert . calledWith ( spawnStub , expectedExecutable , [ '--version' ] ) ;
711+ sinon . assert . calledWith ( spawnStub , expectedExecutable , [ 'python' , 'list' , '--output-format' , 'json' ] ) ;
712+ assert . strictEqual ( await helpers . getUvExecutable ( ) , expectedExecutable ) ;
713+ } ) ;
714+
665715 test ( 'does not replace executable resolution after an installer failure' , async ( ) => {
666716 taskExitCode = 1 ;
667717 assert . strictEqual ( await installPythonWithUv ( ) , undefined ) ;
0 commit comments