@@ -407,7 +407,7 @@ class PythonModule(ExtensionModule):
407407
408408 def __init__ (self , interpreter : 'Interpreter' ) -> None :
409409 super ().__init__ (interpreter )
410- self .installations : T .Dict [str , MaybePythonProg ] = {}
410+ self .installations : T .Dict [T . Tuple [ str , ...] , MaybePythonProg ] = {}
411411 self .methods .update ({
412412 'find_installation' : self .find_installation ,
413413 })
@@ -480,7 +480,7 @@ def _get_win_pythonpath(name_or_path: str) -> T.Optional[str]:
480480 else :
481481 return None
482482
483- def _find_installation_impl (self , state : 'ModuleState' , display_name : str , name_or_path : str , required : bool ) -> MaybePythonProg :
483+ def _find_installation_impl (self , state : 'ModuleState' , display_name : str , name_or_path : T . Union [ str , T . List [ str ], None ] , required : bool ) -> MaybePythonProg :
484484 build_config = self .interpreter .environment .coredata .optstore .get_value_for (OptionKey ('python.build_config' ))
485485 assert isinstance (build_config , str ), 'for mypy'
486486
@@ -490,19 +490,19 @@ def _find_installation_impl(self, state: 'ModuleState', display_name: str, name_
490490 tmp_python = ExternalProgram .from_entry (display_name , name_or_path )
491491 python = PythonExternalProgram (display_name , ext_prog = tmp_python , build_config_path = build_config )
492492
493+ program_name = name_or_path if isinstance (name_or_path , str ) else name_or_path [0 ]
493494 if not python .found () and mesonlib .is_windows ():
494- pythonpath = self ._get_win_pythonpath (name_or_path )
495+ pythonpath = self ._get_win_pythonpath (program_name )
495496 if pythonpath is not None :
496- name_or_path = pythonpath
497- python = PythonExternalProgram (name_or_path )
497+ python = PythonExternalProgram (pythonpath )
498498
499499 # Last ditch effort, python2 or python3 can be named python
500500 # on various platforms, let's not give up just yet, if an executable
501501 # named python is available and has a compatible version, let's use
502502 # it
503- if not python .found () and name_or_path in {'python2' , 'python3' }:
503+ if not python .found () and program_name in {'python2' , 'python3' }:
504504 tmp_python = ExternalProgram .from_entry (display_name , 'python' )
505- python = PythonExternalProgram (name_or_path , ext_prog = tmp_python , build_config_path = build_config )
505+ python = PythonExternalProgram (program_name , ext_prog = tmp_python , build_config_path = build_config )
506506
507507 if python .found ():
508508 if python .sanity (state ):
@@ -530,27 +530,27 @@ def find_installation(self, state: 'ModuleState', args: T.Tuple[T.Optional[str]]
530530 feature_check = FeatureNew ('Passing "feature" option to find_installation' , '0.48.0' )
531531 disabled , required , feature = extract_required_kwarg (kwargs , state .subproject , feature_check )
532532
533- # FIXME: this code is *full* of sharp corners. It assumes that it's
534- # going to get a string value (or now a list of length 1), of `python2`
535- # or `python3` which is completely nonsense. On windows the value could
533+ # FIXME: this code is *full* of sharp corners. On windows the value could
536534 # easily be `['py', '-3']`, or `['py', '-3.7']` to get a very specific
537535 # version of python. On Linux we might want a python that's not in
538536 # $PATH, or that uses a wrapper of some kind.
539537 np : T .List [str ] = state .environment .lookup_binary_entry (MachineChoice .HOST , 'python' ) or []
540538 fallback = args [0 ]
541539 display_name = fallback or 'python'
542- if not np and fallback is not None :
540+ if not np and fallback :
543541 np = [fallback ]
544- name_or_path = np [0 ] if np else None
542+
543+ prog_label = ' ' .join (np ) if np else 'python'
544+ cache_key = tuple (np )
545545
546546 if disabled :
547- mlog .log ('Program' , name_or_path or 'python' , 'found:' , mlog .red ('NO' ), '(disabled by:' , mlog .bold (feature ), ')' )
547+ mlog .log ('Program' , prog_label , 'found:' , mlog .red ('NO' ), '(disabled by:' , mlog .bold (feature ), ')' )
548548 return NonExistingExternalProgram ()
549549
550- python = self .installations .get (name_or_path )
550+ python = self .installations .get (cache_key )
551551 if not python :
552- python = self ._find_installation_impl (state , display_name , name_or_path , required )
553- self .installations [name_or_path ] = python
552+ python = self ._find_installation_impl (state , display_name , np , required )
553+ self .installations [cache_key ] = python
554554
555555 want_modules = kwargs ['modules' ]
556556 found_modules : T .List [str ] = []
@@ -581,11 +581,11 @@ def find_installation(self, state: 'ModuleState', args: T.Tuple[T.Optional[str]]
581581
582582 if not python .found ():
583583 if required :
584- raise mesonlib .MesonException ('{} not found' .format (name_or_path or 'python' ))
584+ raise mesonlib .MesonException ('{} not found' .format (prog_label ))
585585 return NonExistingExternalProgram (python .name )
586586 elif missing_modules :
587587 if required :
588- raise mesonlib .MesonException ('{} is missing modules: {}' .format (name_or_path or 'python' , ', ' .join (missing_modules )))
588+ raise mesonlib .MesonException ('{} is missing modules: {}' .format (prog_label , ', ' .join (missing_modules )))
589589 return NonExistingExternalProgram (python .name )
590590 else :
591591 assert isinstance (python , PythonExternalProgram ), 'for mypy'
0 commit comments