Home > Net >  How does windows decide which python executable to use when multiple are defined in $env:path?
How does windows decide which python executable to use when multiple are defined in $env:path?

Time:10-24

I have several python executables available from within a default powershell prompt as shown by where.exe python:

C:\Program Files\Inkscape\bin\python.exe
C:\Users\921479\AppData\Local\Programs\Python\Python310\python.exe
C:\Users\921479\AppData\Local\Microsoft\WindowsApps\python.exe

When I launch a python interpreter from this powershell prompt, it uses the first executable:

>>>python
Python 3.9.7 (default, Sep 22 2021, 08:12:47)  [GCC 10.3.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', 'C:\\Program Files\\Inkscape\\lib\\python39.zip', 'C:\\Program Files\\Inkscape\\lib\\python3.9', 'C:\\Program Files\\Inkscape\\lib\\python3.9\\lib-dynload', 'C:\\Users\\921479', 'C:\\Program Files\\Inkscape\\lib\\python3.9\\site-packages']

I don't want to remove C:\Program Files\Inkscape\bin from my windows path environment variable, since I use the inkscape command line tool for other purposes. However, I would prefer that powershell use the local installation of python 3.10 as my "default" python interpreter.

When I check the $env:path variable, it looks like the Inkscape folder is defined after the python 3.10 folder. So it looks like something else is used to resolve the python executable:

>>>$env:path
C:\Python310\Scripts\;C:\Python310\;C:\Python39\Scripts\;C:\Python39\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\ProgramData\chocolatey\bin;C:\Users\921479\AppData\Local\SumatraPDF;C:\Program Files\Git\cmd;C:\texlive\2021\bin\win32;C:\Program Files (x86)\PDFtk Server\bin\;C:\Program Files (x86)\Lua\5.1;C:\Program Files (x86)\Lua\5.1\clibs;C:\Program Files\Inkscape\bin;C:\Program Files\dotnet\;C:\Users\921479\AppData\Local\Programs\Python\Python310\Scripts\;C:\Users\921479\AppData\Local\Programs\Python\Python310\;C:\Users\921479\AppData\Local\Microsoft\WindowsApps;C:\Users\921479\.dotnet\tools

How does powershell/windows decide which python executable to use? How can I modify this?

CodePudding user response:

What Windows will execute is not trivial, since it might depend on the API used.

One of them is CreateProcessW:

  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.

Since Windows Vista, the environment variable %NoDefaultCurrentDirectoryInExePath% configures whether or not the current directory should be searched (Source: MSDN).

Also: if you just run python without an extension, the environment variable %PathExt% is used to find executable extensions. (Source: MSDN).

The default value for the PATHEXT variable is: .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

A great tool for troubleshooting such issues is SysInternals Process Monitor. Set a filter for "path contains python" (not python.exe) and you'll see the exact search order. It will report "NO SUCH FILE" for directories which do not contain a Python executable.

Also note: the search order for DLLs may be different.

CodePudding user response:

Thomas Weller's helpful answer provides good general information.

As for using direct invocation of executables by name only (with or without including their filename extension) in PowerShell:

  • Executables specified by name only are looked for in the directories listed in $env:Path, in order, and the executable from the first matching directory is used.

    • Note that PowerShell - unlike cmd.exe - by design, as a security feature, does not execute executables located in the current directory by name only and requires you to signal the intent to invoke such a program explicitly, by prefixing the name with .\ (or by using a full path).

This is consistent with your experience: even though your $env:Path variable has entries for C:\Python310\ and C:\Python39\ that precede C:\Program Files\Inkscape\bin, these do not contain a python.exe executable, as implied by your where.exe command's output, which shows that the only relevant directories are C:\Program Files\Inkscape\bin, C:\Users\921479\AppData\Local\Programs\Python\Python310, and C:\Users\921479\AppData\Local\Microsoft\WindowsApps, which are reflected in that order in your $env:Path value.

The equivalent of your where.exe call in PowerShell would be (except for PowerShell never listing any match in the current directory), using the Get-Command cmdlet:

Get-Command python -All

Omitting -All would show only the effective form of the command, i.e. the one that is actually used on invocation.

  • Related