pythonpython-3.xpathoperating-system

Is There a Portable Way to Deduce the Current Python Interpreter?


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:

  1. Using 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).
  2. Deducing the path from 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?


Solution

  • 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