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:
- The directory from which the application loaded.
- The current directory for the parent process.
- The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
- 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.
- The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
- 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).
- Note that PowerShell - unlike
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.