Could we add Python to system PATH by default?

The 3.7 app distribution may take precedence over PATH when running “python” or “pythonw” using the shell execute family of functions and COM interfaces, or when getting a command line to run “python” by way of SHEvaluateSystemCommandTemplate. These API functions prefer registered application names in the system (but not user) “App Paths” key over searching PATH. A searched name either has to literally match a registered name or has to have no extension and match with “.EXE” appended (*).

Shell API execution is used, for example, by the Win+R dialog and Python’s os.startfile. On the other hand, CMD and PowerShell will search PATH first, so it’s not an issue with the regular command-line shell interface. Also, a direct CreateProcessW call has no knowledge of the shell API “App Paths”, so it’s not an issue there either.

The 3.7 app distribution registers system and user “App Paths” subkeys for “python.exe”, “pythonw.exe”, “idle.exe”, and “pip.exe”. The 3.8 app distribution registers only “3.8” specific names such as “python3.8.exe” and “pip3.8.exe”. These registered names run binaries from the corresponding system app directory under “%ProgramFiles%\WindowsApps”.

This is particularly problematic if both the 3.7 and 3.8 app distributions are installed. The “python.exe” name will be registered to run the “python.exe” binary of the 3.7 app. Executing this binary directly from a normal session context is only allowed if the user’s corresponding appexec link in “%LocalAppData%\Microsoft\WindowsApps” resolves to the same file. But when the 3.8 app is installed, the user’s “python.exe” appexec link instead resolves to the path of the 3.8 binary. Consequently running python from the Win+R dialog or os.startfile('python') will fail with a permission error.


(*) Running “python3.8.exe” via the registered “App Paths” key requires using the “.exe” extension. From the POV of the shell, “python3.8” has the extension “.8”, so it won’t try appending “.EXE” to match the registered name. However, a literal match works, so we can copy the “python3.8.exe” subkey to a new subkey named “python3.8”.

2 Likes