I have a Python script that attempts to run a subprocess that runs the same interpreter as the currently-running interpreter. The subprocess's interpreter needs to be the same executable as the currently running interpreter's. Specifically, it needs to be the correct version even when multiple versions of Python are installed.
Here are some solutions that almost work and the reasons they aren't quite complete:
sys.executable
: The expected result of sys.executable
differs from it's actual implementation. It relies on potentially-incorrect paths from sys.argv
and the PATH
environment variable. For example, if sys.argv == ['']
and PATH
contains a bin directory which has python3
in it, sys.executable
will return the path to that python3
interpreter even if it is NOT the same as the current interpreter (IE it refers to a newer version than the current interpreter).os.__file__
: This approach works fine for Linux systems where the path to the interpreter can (typically) be safely deduced from this path (os.__file__
might be something like /usr/lib/python3.8/os.py
so we may deduce that the correct interpreter is /usr/bin/python3.8
). However, this deduction is only safe when the installation process for the current Python interpreter was "normal" (IE this does not work for embedded installations, custom Python builds installed to nonstandard directories, etc). In addition, I am unsure that it is possible to implement this deduction in a way that is OS-agnostic.In theory, an ideal implementation would leverage OS-dependent utilities to deduce the path of the currently-running executable. This would likely mean reading /proc/self/exe
or /proc/{pid}/exe
on Linux or GetModuleFileName(GetCurrentModule())
on Windows. Is there an easier way to do this?
psutil
package claims to be portable across several platforms
Can be tested with a little recursive script
import psutil
import subprocess,os
proc = psutil.Process().cmdline()
print(f"{os.getpid()} {psutil.Process().exe()} {proc}")
# set next command interpreter to the one found
proc[0]=psutil.Process().exe()
# run that command, forever :-p
subprocess.run(proc)
Running it as
python3.9 proc.py 2>/dev/null
13148 /usr/bin/python3.9 ['python3.9', 'proc.py']
13149 /usr/bin/python3.9 ['/usr/bin/python3.9', 'proc.py']
13150 /usr/bin/python3.9 ['/usr/bin/python3.9', 'proc.py']
13151 /usr/bin/python3.9 ['/usr/bin/python3.9', 'proc.py']
13152 /usr/bin/python3.9 ['/usr/bin/python3.9', 'proc.py']
^C