Suppose I have a file called a_python2_script.py with content
print "Hello"
and call it in Python 3 with:
from subprocess import Popen
Popen(["python2", "a_python2_script.py"])
This works, but I do not want to hardcode python2 interpreter call, since the program should run on Windows and Linux.
I know about sys.executable but that would give me the path of the current (i.e. Python 3) interpreter. What is the pythonic way to get the Python 2 interpreter path from within the Python 3 script?
Note: I am calling an external Python 2 library and have no chance to convert it to Python 3.
Use os.get_exec_path() (available from 3.2) to get a list of directories that will be searched for an executable.
In [1]: import os
In [2]: paths = os.get_exec_path()
In [5]: for p in paths:
...: for prog in ["python2", "python2.exe"]:
...: attempt = os.path.join(p, prog)
...: if os.path.isfile(attempt):
...: print(attempt)
...:
/usr/local/bin/python2
This might be one possible way to figure it out. I am currently running Windows and have Python installed using Anaconda and Anaconda3. My PATH contains both of these folders.
A simple script could check each PATH location for the presence of the Python executable. You could then execute python --version at each location:
import sys, os
from subprocess import Popen
python_paths = []
for path in os.environ["PATH"].split(os.pathsep):
for executable in ["python", "python.exe", "python2"]:
if os.path.isfile(os.path.join(path, executable)):
python_paths.append(path)
for path in python_paths:
Popen([os.path.join(path, "python"), "--version"])
print(python_paths)
On my Windows machine this gives:
['d:\\Anaconda', 'd:\\Anaconda3']
Python 2.7.9 :: Anaconda 2.2.0 (32-bit)
Python 3.4.3 :: Anaconda 2.3.0 (32-bit)
Tested using Python 3.4.3. I am not currently able to check the outcome for Linux though.
Related
Python is on my machine, I just don't know where, if I type python in terminal it will open Python 2.6.4, this isn't in it's default directory, there surely is a way of finding it's install location from here?
sys has some useful stuff:
$ python
Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.executable
'c:\\Python26\\python.exe'
>>> sys.exec_prefix
'c:\\Python26'
>>>
>>> print '\n'.join(sys.path)
c:\Python26\lib\site-packages\setuptools-0.6c11-py2.6.egg
c:\Python26\lib\site-packages\nose-1.0.0-py2.6.egg
C:\Windows\system32\python26.zip
c:\Python26\DLLs
c:\Python26\lib
c:\Python26\lib\plat-win
c:\Python26\lib\lib-tk
c:\Python26
c:\Python26\lib\site-packages
c:\Python26\lib\site-packages\win32
c:\Python26\lib\site-packages\win32\lib
c:\Python26\lib\site-packages\Pythonwin
c:\Python26\lib\site-packages\wx-2.8-msw-unicode
In unix (mac os X included) terminal you can do
which python
and it will tell you.
Platform independent solution in one line is
Python 2:
python -c "import sys; print sys.executable"
Python 3:
python -c "import sys; print(sys.executable)"
For Windows CMD run: where python
For Windows PowerShell run: Get-Command python
Have a look at sys.path:
>>> import sys
>>> print(sys.path)
On UNIX-like systems, you should be able to type which python, which will print out the path to python. The equivalent in Windows Command Prompt is where python, and Get-Command python in Windows Powershell.
Another (cross-platform) method is to type this into IDLE or REPL (type python into your terminal):
import re
re.__file__
Or in one line from your terminal:
python -c "import re; print(re.__file__)"
This will print the path to the re module, consequently showing you where the python command points to. You can put any other module that you know is installed, and the path will point to that module, also giving you the path to python.
To find all the installations of Python on Windows run this at the command prompt:
dir site.py /s
Make sure you are in the root drive. You will see something like this.
If you are using wiindows OS (I am using windows 10 ) just type
where python
in command prompt ( cmd )
It will show you the directory where you have installed .
For Windows Users:
If the python command is not in your $PATH environment var.
Open PowerShell and run these commands to find the folder
cd \
ls *ython* -Recurse -Directory
That should tell you where python is installed
First search for PYTHON IDLE from search bar
Open the IDLE and use below commands.
import sys
print(sys.path)
It will give you the path where the python.exe is installed. For eg:
C:\Users\\...\python.exe
Add the same path to system environment variable.
On windows search python,then right click and click on "Open file location".That's how I did
Run below command
where python
When I make a python venv on Windows:
C:\> mkdir C:\tvenv
C:\> cd C:\tvenv
C:\> python -m venv v
And then create these three files:
t.bat
call "C:\tvenv\v\Scripts\activate.bat"
python t1.py
t1.py
import subprocess
import sys
print('T1', sys.executable)
subprocess.run(['python', 't2.py'])
t2.py
import sys
print('T2', sys.executable)
And then I run t.bat:
C:\> t.bat
OBSERVED OUTPUT
T1 C:\tvenv\v\Scripts\python.exe
T2 C:\Program Files\Python38\python.exe
The following happens:
t.bat activates a venv and calls t1.py.
t1.py correctly reports the sys.executable from the venv
t1.py then calls subprocess.run(['python', 't2.py'])
t2.py then reports the system-wide sys.executable, not the one from the venv
ie I would have expected the output to be:
EXPECTED OUTPUT
T1 C:\tvenv\v\Scripts\python.exe
T2 C:\tvenv\v\Scripts\python.exe
as activate.bat sets:
set PATH=%VIRTUAL_ENV%\Scripts;%PATH%
It puts the venv Scripts dir at the front of the PATH.
so why doesn't subprocess.run(['python']) find the venv python instead of the system-wide one?
Update
I am on latest Windows 10 x64. I just completely reinstalled Python 3.9.1 from the standard python.org Windows installer, and didn't even put it in my PATH. Problem is still present.
The issue is indeed linked to Windows behavior and in fact the main solution is to use sys.exectuable instead of python to actually launch the expected python binary instead of letting the OS resolving that by himself.
Much more explanations on the issue and how OS are impacting the behavior of subprocess.run command: https://github.com/python/cpython/issues/86207
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'])
Test 1: py -3 launcher.py
Output: python 3.8.1 (HOW!)
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
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:
subprocess PATH semantics and portability (notice the "needs patch" stage)
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.
I'm new to Python and programming in general.
I'm trying to force my scripts to use Python3.4 as installed using the python installer from python.org.
My script has this.
#!/usr/local/bin/python3.4
import sys
print(sys.version)
print("Hello, World!")
Terminal returns this:
$ python pyscript.py
2.7.5 (default, Aug 25 2013, 00:04:04)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)]
Hello, World!
The shebang path is correct, according to "which python3.4"
By calling python on your script you are using the python in your path. As the comment suggests run the file directly after setting the execution bit.
Shebang is only used when you run your script directly using command like this
$ ./pyscript.py
When you python interpreter from command line, the shell doesn't consult shebang line. It simply runs the first python executable it finds on the command line.
To change the default python executable, adjust your path. Or better yet use python virtual environment. More information on virtual environment is here
Depending on your installation, python can be installed in a multitude of places on OS X.
Without any other additional changes, you are likely running the python located in /usr/bin/python. This can be verified by typing which python
~ $ which python
/usr/bin/python
Note that while /usr/local/bin/python3.4 may be the correct path to python 3.4, when you type python script.py you are not invoking the command you found when you did which python3.4.
To fix this you can do one of:
Invoke the script directly. Type script.py (with the executable bit) rather than as python script.py. You may need to change the permissions on the script to executable with chmod u+x script.py.
Change the version in /usr/bin/python to the version you want. Note that this may be very dangerous in that other things expecting the base install python of 2.7.5 can become very unhappy
Change your $PATH to put /usr/local/bin/ before /usr/bin and have python in /usr/local/bin/python point to the 3.4 version.
The shebang path is only used by the OS when you make the file executable and run it directly, like this:
chmod 755 pyscript.py
./pyscript.py
For python, the shebang is only a comment. The only way to force it even when calling the interpreter directly on the CLI is to compare the version and if it's less re-launch it using os.execv or similar. Something like this should do (not tested though):
#!/usr/local/bin/python3.4
import sys
import os
if (sys.hexversion < 0x3040000):
sys.argv.insert(0, '/usr/local/bin/python3.4')
os.execv(sys.argv[0], sys.argv)
print(sys.version)
print("Hello, World!")
You might want to use env on the shebang to avoid specifying the path, and avoid hardcoding the path on the python code too...
For example, in a python script file called script.py, in my case I have a 3.7 Python at the following path:
#! /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
import sys
print("--- Python version ---")
print(sys.version)
print("--- Python version info ---")
print(sys.version_info)
print("--- Python path executable ---")
print(sys.executable)
As others say, give permissions and do a proper execution so that shebang can be applied:
In the terminal type the following to make script.py a executable file for your user, that is:
$ chmod u+x script.py
In the terminal script.py is run with ./ at the beginning (not using python):
$ ./script.py
In my case I've got:
--- Python version ---
3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:52:21)
[Clang 6.0 (clang-600.0.57)]
--- Python version info ---
sys.version_info(major=3, minor=7, micro=3, releaselevel='final', serial=0)
--- Python path executable ---
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
Considerations:
shebang path cannot contain spaces.
"Python path executable" not necessarily match with shebang path as long as the python at the shebang path can be an "alias". Aliases in Mac point to other file, you can see it with right click on a file and select "Get info" to check the "Original" value.
New to Python and programming in general. I want to "install" a module from the command line for v 2.6, but it looks like my default Python is 2.5. (python --version returns 2.5.4)
How can I run my python setup.py build/install on 2.6 instead?
Many thanks in advance,
Brock
You can use explicit paths:
c:\python26\python setup.py install
c:\python25\python setup.py install
Recent versions of Python install PyLauncher. It is installed in the path so no need to add an explicit Python to the path, and it allows easy switching between multiple Python versions.
Examples:
py -3 setup.py # run latest Python 3
py -2 setup.py # run latest Python 2
py -3.3
py -2.7-32 # use 32-bit version
py # run default version
The default version can be specified in the environment variable PY_PYTHON, e.g. PY_PYTHON=3 (latest Python 3).
It depends on your operating system. If you have python 2.6 installed, you need to change your environment path to point to the 2.6 executable rather than the 2.5 executable. Do a Google search for changing your PATH variable on your operating system.
If you're on Windows and you just need to run a different version of Python temporarily or, as was the case for me, a third party program needs to run a different version of Python, then modify your path at the command prompt:
> python --version
> set PATH=<path-to-desired-python-version>;%PATH%
> python --version
For me it was:
> python --version
Python 3.4.2
> set PATH=C:\tools\python2\;%PATH%
> python --version
Python 2.7.9
> npm install...
(success)
This allowed the third party program to install successfully. The PATH modification only affects programs running in the same command prompt session and only lasts as long as the command prompt session..
They are a couple of ways you can do this
1) python virtual environment
2) pylauncher
3) Changing your windows path variable, tedious to say the least
All three outlined in this video https://www.youtube.com/watch?v=ynDlb0n27cw
It sounds like you are on windows. If so, run this with the python you want, to set that python as the windows one. (not my code)
import sys
from _winreg import *
# tweak as necessary
version = sys.version[:3]
installpath = sys.prefix
regpath = "SOFTWARE\\Python\\Pythoncore\\%s\\" % (version)
installkey = "InstallPath"
pythonkey = "PythonPath"
pythonpath = "%s;%s\\Lib\\;%s\\DLLs\\" % (
installpath, installpath, installpath
)
def RegisterPy():
try:
reg = OpenKey(HKEY_LOCAL_MACHINE, regpath)
except EnvironmentError:
try:
reg = CreateKey(HKEY_LOCAL_MACHINE, regpath)
except Exception, e:
print "*** Unable to register: %s" % e
return
SetValue(reg, installkey, REG_SZ, installpath)
SetValue(reg, pythonkey, REG_SZ, pythonpath)
CloseKey(reg)
print "--- Python %s at %s is now registered!" % (version, installpath)
if __name__ == "__main__":
RegisterPy()
Download Python v2.6.