@@ -31,7 +31,7 @@ import {
3131import { showErrorMessage } from '../../common/errors/utils' ;
3232import { Common , VenvManagerStrings } from '../../common/localize' ;
3333import { isUvInstalled , runUV , runPython } from './helpers' ;
34- import { getWorkspacePackagesToInstall } from './pipUtils' ;
34+ import { getProjectInstallable , getWorkspacePackagesToInstall } from './pipUtils' ;
3535
3636export const VENV_WORKSPACE_KEY = `${ ENVS_EXTENSION_ID } :venv:WORKSPACE_SELECTED` ;
3737export const VENV_GLOBAL_KEY = `${ ENVS_EXTENSION_ID } :venv:GLOBAL_SELECTED` ;
@@ -347,6 +347,90 @@ export async function getGlobalVenvLocation(): Promise<Uri | undefined> {
347347 return undefined ;
348348}
349349
350+ async function createWithCustomization ( version : string ) : Promise < boolean | undefined > {
351+ const selection : QuickPickItem | undefined = await showQuickPick (
352+ [
353+ {
354+ label : VenvManagerStrings . quickCreate ,
355+ description : VenvManagerStrings . quickCreateDescription ,
356+ detail : l10n . t ( 'Uses Python version {0} and installs workspace dependencies.' , version ) ,
357+ } ,
358+ {
359+ label : VenvManagerStrings . customize ,
360+ description : VenvManagerStrings . customizeDescription ,
361+ } ,
362+ ] ,
363+ {
364+ placeHolder : VenvManagerStrings . selectQuickOrCustomize ,
365+ ignoreFocusOut : true ,
366+ } ,
367+ ) ;
368+
369+ if ( selection === undefined ) {
370+ return undefined ;
371+ } else if ( selection . label === VenvManagerStrings . quickCreate ) {
372+ return false ;
373+ }
374+ return true ;
375+ }
376+
377+ async function createWithProgress (
378+ nativeFinder : NativePythonFinder ,
379+ api : PythonEnvironmentApi ,
380+ log : LogOutputChannel ,
381+ manager : EnvironmentManager ,
382+ basePython : PythonEnvironment ,
383+ venvRoot : Uri ,
384+ envPath : string ,
385+ packages ?: string [ ] ,
386+ ) {
387+ const pythonPath =
388+ os . platform ( ) === 'win32' ? path . join ( envPath , 'Scripts' , 'python.exe' ) : path . join ( envPath , 'bin' , 'python' ) ;
389+
390+ return await withProgress (
391+ {
392+ location : ProgressLocation . Notification ,
393+ title : VenvManagerStrings . venvCreating ,
394+ } ,
395+ async ( ) => {
396+ try {
397+ const useUv = await isUvInstalled ( log ) ;
398+ if ( basePython . execInfo ?. run . executable ) {
399+ if ( useUv ) {
400+ await runUV (
401+ [ 'venv' , '--verbose' , '--seed' , '--python' , basePython . execInfo ?. run . executable , envPath ] ,
402+ venvRoot . fsPath ,
403+ log ,
404+ ) ;
405+ } else {
406+ await runPython (
407+ basePython . execInfo . run . executable ,
408+ [ '-m' , 'venv' , envPath ] ,
409+ venvRoot . fsPath ,
410+ manager . log ,
411+ ) ;
412+ }
413+ if ( ! ( await fsapi . pathExists ( pythonPath ) ) ) {
414+ log . error ( 'no python executable found in virtual environment' ) ;
415+ throw new Error ( 'no python executable found in virtual environment' ) ;
416+ }
417+ }
418+
419+ const resolved = await nativeFinder . resolve ( pythonPath ) ;
420+ const env = api . createPythonEnvironmentItem ( await getPythonInfo ( resolved ) , manager ) ;
421+ if ( packages && packages ?. length > 0 ) {
422+ await api . installPackages ( env , packages , { upgrade : false } ) ;
423+ }
424+ return env ;
425+ } catch ( e ) {
426+ log . error ( `Failed to create virtual environment: ${ e } ` ) ;
427+ showErrorMessage ( VenvManagerStrings . venvCreateFailed ) ;
428+ return ;
429+ }
430+ } ,
431+ ) ;
432+ }
433+
350434export async function createPythonVenv (
351435 nativeFinder : NativePythonFinder ,
352436 api : PythonEnvironmentApi ,
@@ -371,7 +455,27 @@ export async function createPythonVenv(
371455 return ;
372456 }
373457
374- const basePython = await pickEnvironmentFrom ( sortEnvironments ( filtered ) ) ;
458+ const sortedEnvs = sortEnvironments ( filtered ) ;
459+ const project = api . getPythonProject ( venvRoot ) ;
460+
461+ const customize = await createWithCustomization ( sortedEnvs [ 0 ] . version ) ;
462+ if ( customize === undefined ) {
463+ return ;
464+ } else if ( customize === false ) {
465+ const installables = await getProjectInstallable ( api , project ? [ project ] : undefined ) ;
466+ return await createWithProgress (
467+ nativeFinder ,
468+ api ,
469+ log ,
470+ manager ,
471+ sortedEnvs [ 0 ] ,
472+ venvRoot ,
473+ path . join ( venvRoot . fsPath , '.venv' ) ,
474+ installables ?. flatMap ( ( i ) => i . args ?? [ ] ) ,
475+ ) ;
476+ }
477+
478+ const basePython = await pickEnvironmentFrom ( sortedEnvs ) ;
375479 if ( ! basePython || ! basePython . execInfo ) {
376480 log . error ( 'No base python selected, cannot create virtual environment.' ) ;
377481 return ;
@@ -396,58 +500,14 @@ export async function createPythonVenv(
396500 }
397501
398502 const envPath = path . join ( venvRoot . fsPath , name ) ;
399- const pythonPath =
400- os . platform ( ) === 'win32' ? path . join ( envPath , 'Scripts' , 'python.exe' ) : path . join ( envPath , 'bin' , 'python' ) ;
401503
402- const project = api . getPythonProject ( venvRoot ) ;
403504 const packages = await getWorkspacePackagesToInstall (
404505 api ,
405506 { showSkipOption : true } ,
406507 project ? [ project ] : undefined ,
407508 ) ;
408509
409- return await withProgress (
410- {
411- location : ProgressLocation . Notification ,
412- title : VenvManagerStrings . venvCreating ,
413- } ,
414- async ( ) => {
415- try {
416- const useUv = await isUvInstalled ( log ) ;
417- if ( basePython . execInfo ?. run . executable ) {
418- if ( useUv ) {
419- await runUV (
420- [ 'venv' , '--verbose' , '--seed' , '--python' , basePython . execInfo ?. run . executable , envPath ] ,
421- venvRoot . fsPath ,
422- log ,
423- ) ;
424- } else {
425- await runPython (
426- basePython . execInfo . run . executable ,
427- [ '-m' , 'venv' , envPath ] ,
428- venvRoot . fsPath ,
429- manager . log ,
430- ) ;
431- }
432- if ( ! ( await fsapi . pathExists ( pythonPath ) ) ) {
433- log . error ( 'no python executable found in virtual environment' ) ;
434- throw new Error ( 'no python executable found in virtual environment' ) ;
435- }
436- }
437-
438- const resolved = await nativeFinder . resolve ( pythonPath ) ;
439- const env = api . createPythonEnvironmentItem ( await getPythonInfo ( resolved ) , manager ) ;
440- if ( packages && packages ?. length > 0 ) {
441- await api . installPackages ( env , packages , { upgrade : false } ) ;
442- }
443- return env ;
444- } catch ( e ) {
445- log . error ( `Failed to create virtual environment: ${ e } ` ) ;
446- showErrorMessage ( VenvManagerStrings . venvCreateFailed ) ;
447- return ;
448- }
449- } ,
450- ) ;
510+ return await createWithProgress ( nativeFinder , api , log , manager , basePython , venvRoot , envPath , packages ) ;
451511}
452512
453513export async function removeVenv ( environment : PythonEnvironment , log : LogOutputChannel ) : Promise < boolean > {
0 commit comments