@@ -248,6 +248,51 @@ def check_any_install(cmd):
248248 return True
249249
250250
251+ def _list_available_fallback_runtimes (cmd ):
252+ from .commands import find_command
253+
254+ candidates = []
255+ try :
256+ list_cmd = find_command (["list" , "--online" , "-1" , "default" ], cmd .root )
257+ list_cmd .formatter_callable = lambda cmd , installs : candidates .extend (installs )
258+ list_cmd .fallback_source_only = True
259+ list_cmd .execute ()
260+ if not candidates :
261+ list_cmd .fallback_source_only = False
262+ list_cmd .execute ()
263+ except Exception :
264+ LOGGER .debug ("Check skipped: Failed to find 'list' command." , exc_info = True )
265+ return []
266+ except SystemExit :
267+ LOGGER .debug ("Check skipped: Failed to execute 'list' command." )
268+ return []
269+
270+ return candidates
271+
272+
273+ def check_latest_install (cmd ):
274+ LOGGER .debug ("Checking if any default runtime is installed" )
275+
276+ available = _list_available_fallback_runtimes (cmd )
277+ if not available :
278+ return "skip"
279+
280+ installs = cmd .get_installs (include_unmanaged = True , set_default = False )
281+ if not installs :
282+ LOGGER .debug ("Check failed: no installs found" )
283+ return False
284+
285+ present = {i .get ("tag" ) for i in installs }
286+ available = set (j for i in available for j in i .get ("install-for" , []))
287+ LOGGER .debug ("Already installed: %s" , sorted (present ))
288+ LOGGER .debug ("Available: %s" , sorted (available ))
289+ if available & present :
290+ LOGGER .debug ("Check passed: installs found" )
291+ return True
292+ LOGGER .debug ("Check failed: no equivalent 'default' runtime installed" )
293+ return False
294+
295+
251296def do_install (cmd ):
252297 from .commands import find_command
253298 try :
@@ -360,16 +405,19 @@ def first_run(cmd):
360405 welcome ()
361406 line_break ()
362407 shown_any = True
363- LOGGER .print ("!Y!The directory for versioned Python commands is not "
408+ LOGGER .print ("!Y!The global shortcuts directory is not "
364409 "configured.!W!" , level = logging .WARN )
365- LOGGER .print ("\n This will prevent commands like !B!python3.14.exe!W! "
366- "working, but will not affect the !B!python!W! or "
367- "!B!py!W! commands (for example, !B!py -V:3.14!W!)." ,
410+ LOGGER .print ("\n Configuring this enables commands like "
411+ "!B!python3.14.exe!W! to run from your terminal, "
412+ "but is not needed for the !B!python!W! or !B!py!W! "
413+ "commands (for example, !B!py -V:3.14!W!)." ,
414+ wrap = True )
415+ LOGGER .print ("\n We can add the directory (!B!%s!W!) to PATH now, "
416+ "but you will need to restart your terminal to use "
417+ "it. The entry will be removed if you run !B!py "
418+ "uninstall --purge!W!, or else you can remove it "
419+ "manually when uninstalling Python.\n " , cmd .global_dir ,
368420 wrap = True )
369- LOGGER .print ("\n We can add the directory to PATH now, but you will "
370- "need to restart your terminal to see the change, and "
371- "must manually edit environment variables to later "
372- "remove the entry.\n " , wrap = True )
373421 if (
374422 not cmd .confirm or
375423 not cmd .ask_ny ("Add commands directory to your PATH now?" )
@@ -399,6 +447,22 @@ def first_run(cmd):
399447 elif cmd .explicit :
400448 LOGGER .info ("Checked for any Python installs" )
401449
450+ if cmd .check_latest_install :
451+ if not check_latest_install (cmd ):
452+ welcome ()
453+ line_break ()
454+ shown_any = True
455+ LOGGER .print ("!Y!You do not have the latest Python runtime.!W!" ,
456+ level = logging .WARN )
457+ LOGGER .print ("\n Install the current latest version of CPython? If "
458+ "not, you can use '!B!py install default!W!' later to "
459+ "install.\n " , wrap = True )
460+ LOGGER .info ("" )
461+ if not cmd .confirm or cmd .ask_yn ("Install CPython now?" ):
462+ do_install (cmd )
463+ elif cmd .explicit :
464+ LOGGER .info ("Checked for the latest available Python install" )
465+
402466 if shown_any or cmd .explicit :
403467 line_break ()
404468 LOGGER .print ("!G!Configuration checks completed.!W!" , level = logging .WARN )
0 commit comments