Repository: mesonbuild/meson

Issue:
Suboptimal logging from `import('python').find_installation()`
The output from `import('python').find_installation('python')` when `python` is not found is confusing. The following `meson.python`
```
project('test')
py = find_program('python3.12', required: false)
py = import('python').find_installation('python3.12')
```
 results in this output:
```
Program python3.12 found: NO
Program nonexistingprogram found: NO

meson.build:5:22: ERROR: python3.12 not found
```
Where `Program python3.12 found: NO` comes from the `find_program()` call and `Program nonexistingprogram found: NO` comes from the `find_installation()` call. I think that `nonexistingprogram` would be better replaced with something more descriptive.

This is on macOS with Meson 1.1.0.


Discussion:
There is also a slight difference in the messages also when the Python instance is found: the `find_program()` output highlights with ansi escape codes the name of the program, but the `find_installation()` output does not.

Resolving patch:
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py
--- a/mesonbuild/modules/python.py
+++ b/mesonbuild/modules/python.py
@@ -300,12 +300,12 @@ def __init__(self, interpreter: 'Interpreter') -> None:
     # https://www.python.org/dev/peps/pep-0397/
     @staticmethod
     def _get_win_pythonpath(name_or_path: str) -> T.Optional[str]:
-        if name_or_path not in ['python2', 'python3']:
+        if not name_or_path.startswith(('python2', 'python3')):
             return None
         if not shutil.which('py'):
             # program not installed, return without an exception
             return None
-        ver = {'python2': '-2', 'python3': '-3'}[name_or_path]
+        ver = f'-{name_or_path[6:]}'
         cmd = ['py', ver, '-c', "import sysconfig; print(sysconfig.get_config_var('BINDIR'))"]
         _, stdout, _ = mesonlib.Popen_safe(cmd)
         directory = stdout.strip()
@@ -332,7 +332,8 @@ def _find_installation_impl(self, state: 'ModuleState', display_name: str, name_
             # named python is available and has a compatible version, let's use
             # it
             if not python.found() and name_or_path in {'python2', 'python3'}:
-                python = PythonExternalProgram('python')
+                tmp_python = ExternalProgram.from_entry(display_name, 'python')
+                python = PythonExternalProgram(name_or_path, ext_prog=tmp_python)
 
         if python.found():
             if python.sanity(state):
@@ -344,7 +345,7 @@ def _find_installation_impl(self, state: 'ModuleState', display_name: str, name_
                 else:
                     mlog.warning(sanitymsg, location=state.current_node)
 
-        return NonExistingExternalProgram()
+        return NonExistingExternalProgram(python.name)
 
     @disablerIfNotFound
     @typed_pos_args('python.find_installation', optargs=[str])
@@ -412,11 +413,11 @@ def find_installation(self, state: 'ModuleState', args: T.Tuple[T.Optional[str]]
         if not python.found():
             if required:
                 raise mesonlib.MesonException('{} not found'.format(name_or_path or 'python'))
-            return NonExistingExternalProgram()
+            return NonExistingExternalProgram(python.name)
         elif missing_modules:
             if required:
                 raise mesonlib.MesonException('{} is missing modules: {}'.format(name_or_path or 'python', ', '.join(missing_modules)))
-            return NonExistingExternalProgram()
+            return NonExistingExternalProgram(python.name)
         else:
             python = copy.copy(python)
             python.pure = kwargs['pure']


Test patch: