Python 3 weird behavior of subprocess.call

Viewed 140

Environment:

Windows: 10
Python: 2.7.13 and 3.8.1
default Python launcher: py -3
Default python: 2.7.13

> python -V
> Python 2.7.13

> py -3 -V
> Python 3.8.1



launcher.py:

import subprocess
subprocess.call(['python', '-V'])


  1. Test 1: py -3 launcher.py

    Output: python 3.8.1 (HOW!)

  2. Test 2: py -2 launcher.py

    Output: Python 2.7.13


The output should be Python 2.7.13 only, even the launcher runs under py 3!
note that, adding shell=True will work, but the idea is not to use it, and if I ran

subprocess.call(['python', 'script_under_py_2.py']) # Will run python 3 with script python 2!

Thanks
Adam

2 Answers

This behavior is due to the inconsistent handling of the PATH environment variable when calling Popen on Windows and Unix.

Windows creates its sub-processes using CreateProcess function. The search path for CreateProcess includes parent process directory, which may be the reason why you are having different binaries executed.

On Windows, PATH is only considered when shell=True is also passed.

You can learn more about the issue here:

If the problem is that subprocess.call is failing to honour os.environ['PATH'] then you could always explicitly search that path for the executable you want to call, and then call it by its absolute path, as follows:

# Manually search the operating system's PATH for python[.exe]
import os, sys
ospath = os.environ['PATH'].split(os.path.pathsep)
_, extension = os.path.splitext(sys.executable)
target = 'python' + extension
matches = [os.path.join(directory, target) for directory in ospath]
matches = [match for match in matches if os.path.isfile(match)]
if not matches: raise OSError('{!r} was not found in any PATH directory'.format(target))
python = matches[0]

# Test:
import subprocess
print('I am Python {} and I am calling "{}" -V'.format(sys.version.split()[0], python))
subprocess.call([python, '-V'])

Of course, that won't do what you want if the py -3 wrapper works by actually changing the path before launching Python... I'm not familiar with that wrapper so I don't know whether that will be a problem.

Related