I need to find out if there is Python installed on the computer.
My specific issue is that I am distributing a program that comes with its own interpreter + standard library (the end-user may not have Python). In the installation, I am giving the option to use the user's own installed Python interpreter + library if they have it. However, I need the location of that. I can ask the user to find it manually, but I was hoping there was an automatic way.
Since my installer uses my included interpreter, sys.prefix refers to the included interpreter (I know this because I tried it out, I have Python 2.7 and 3.3 installed).
I also tried using subprocess.call: subprocess.call(['py', '-c', '"import sys; print sys.prefix"']) which would use the standard Python interpreter if there was one, but I'm not sure how to capture this output.
Thus, are there any other ways to find out if there is a default Python version installed on the user's computer and where?
Actually, in the light of my other answer, an even better way to find the Python installation directory would probably be to check the Windows registry, since the Python installer places some information there.
Take a look at this answer and this Python module.
Some users might have placed their local Python directory into the system's PATH environment variable and some might even have set the PYTHONPATH environment variable.
You could try the following:
import os
if "python" in os.environ["PATH"].lower():
# Confirm that the Python executable actually is there
if "PYTHONPATH" in os.environ.keys():
# Same as in the last if...
As for the subprocess.call(...), set the stdout parameter for something that passes for a file object, and afterwards just .read() the file object you gave to see the output from the call.
Related
I'm using Cython in --embed mode to produce a .exe. I'm evaluating the Minimal set of files required to distribute an embed-Cython-compiled code and make it work on any machine. To do this, I only copy a minimal number of files from the Python Windows embeddable package.
In order to check this, I need to be sure that the current process I'm testing doesn't in fact use my system default Python install, i.e. C:\Python38.
To do this, I open a new cmd.exe and do set PATH= which temporarily removes everything from the PATH. Then I can test any self-compiled app.exe and make sure it doesn't reuse C:\Python38's files under the hood.
It works, except for the modules. Even after doing set PATH=, my code app.py
import json
print(json.dumps({"a":"b"}))
when Cython---embed-compiled into a .exe works, but it still uses C:\Python38\Lib\json\__init__.py! I know this for sure, because if I temporarily remove this file, my .exe now fails, because it cannot find the json module.
How to completely remove any link to C:\Python38 when debugging a Python program which shouldn't use these files?
Why isn't set PATH= enough? Which other environment variable does it use for modules? I checked all my system variables and I think I don't find any which seems related to Python.
Python has a quite complicated heuristic for finding its "installation" (see for example this SO-question or this description), so probably it doesn't find the installation you are providing but the "default" installation.
Probably the most simple way is to set the environment variable PYTHONPATH pointing to the desired installation prior to start of the embedded interpreter.
By examination of sys.path one can check whether the correct installation was found.
Thanks to #ead's answer and his link getpath.c finally redirecting to getpathp.c in the case of Windows, we can learn that the rule for building the path for module etc. is:
current directory first
PYTHONPATH env. variable
registry key HKEY_LOCAL_MACHINE\SOFTWARE\Python or the same in HKCU
PYTHONHOME env. variable
finally:
Iff - we can not locate the Python Home, have not had a PYTHONPATH
specified, and can't locate any Registry entries (ie, we have nothing
we can assume is a good path), a default path with relative entries is
used (eg. .\Lib;.\DLLs, etc)
Conclusion: in order to debug an embedded version of Python, without interfering with the default system install (C:\Python38 in my case), I finally solved it by temporarily renaming the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Python to HKEY_LOCAL_MACHINE\SOFTWARE\PythonOld.
Side note: I'm not sure I will ever revert this registry key back to normal: my normal Python install shouldn't need it anyway to find its path, since when I run python.exe from anywhere (it is in the PATH for everyday use), it will automatically look in .\Lib\ and .\DLL\ which is correct. I don't see a single use case in which my normal install python.exe wouldn't find its subdir .\Lib\ or .\DLL\ and requiring the registry for this. In which use case would the registry be necessary? if python.exe is started then its path has been found, and it can take its .\Lib subfolder, without help from registry. I think 99,99% of the time this registry feature is doing more harm than good, preventing a Python install to be really "portable" (i.e. that we can move from one folder to another).
Notes:
To be 100% sure, I also did this in command line, but I don't think it's necessary:
set PATH=
set PYTHONPATH=
set PYTHONHOME=
Might be helpful to do debugging of an embedded Python: import ctypes. If you haven't _ctypes.pyd and libffi-7.dll in your embedded install folder, it should fail. If it doesn't, this means it looks somewhere else (probably in your default system-wide Python install).
I understand the difference between starting a python script like:
#!/usr/bin/env python
or
#!/usr/bin/python
From what I understood, just executes python as we would do in our shell, so it looks in $PATH. The second one is not a fixed path, which has the inconvenient that in a different system the python interpreter might be located in another path.
My question is, why do we need env? Why can we just do:
#!python
This works perfectly fine in my computer? Is there a reason to prefer calling env?
Short answer:
This depends on the shell. in bash #!python will just be ignored and you have to use #!/usr/bin/env python. zsh on the other hand seems to be able to handle #!python.
The long answer (for bash):
let's imagine your python file is named 'tst.py'
and has following contents
#!python
import sys
print(sys.executable, sys.version)
then you can always type
python tst.py
The first line is completely irrelevant and is not even looked at.
However if you do following (for example on linux)
chmod +x tst.py
./tst.py
Then the first line is looked at to determine which interpreter shall be used (bash, perl, python, something else?) and here at least for my OS (ubuntu) and my shell (bash) an absolute path is required for the executable name (e.g. /bin/bash, /bin/python, /usr/bin/env)
If I call ./tst.py on my ubuntu machine I get
bash: ./tst.py: python: bad interpreter: No such file or directory
Special case Windows, when typing tst.py or clicking on a python script.
If you're on windows, the line is looked at, but even if it is wrong a default python interpreter will be used. On Windows, this line could be used to select explicitly python2 or python3 for example.
Windows uses file type associations to determine which executable to call for which suffix. for .py files (python 3.x is installed) this is normally py.exe which is an executable located in the system path, that will just call a python interpreter. depending on installed versions, the shebang line and environment vars, that might indicate a virtualenv
Addendum:
The first line is interpreted by the shell or in the windows case by py.exe.
It seems bash requires absolute paths for command, whereas zsh accepts relative paths as well.
So for zsh only
#!python
works perfectly well whereas bash requiers absolute paths and thus the trick with the env command
#!/usr/bin/env python
For scripts that shall be executed by a cronjob it's best to hardcode the path of the python executable as PATH is rather minimalistic for cronjobs, so there it's best to have something like
#!/usr/bin/python3.5
or
#!/home/username/myvirtualenv/bin/python
Each Python script is written with a particular version of Python in mind. If the shebang is #!/usr/bin/env python, that puts the version used under the control of the individual caller, whose PATH may not provide the right version.
#!/usr/bin/python is a little better, as it puts the decision in the hands of the script itself. However, the script author doesn't necessarily know where the correction version of Python is on your system, so it still may not work.
The solution is to specify the correct location on your system when you install the module or script. The Python installer (pip, etc) will, at that time, rewrite any shebang containing the word python (#!python being the minimal such shebang) to the path specified by the installer.
Now when you run the script, it will point to the correct path that you have already provided, without being subject to runtime PATH lookup that could choose the wrong version.
Note that #!python is not meant to be used as-is, though for various reasons it might work for you. It's is a means towards making sure the script gets a fixed, absolute path to the correct interpreter. #!/usr/bin/python is also subject to install-time replacement, so may serve as a usable default.
This question already has answers here:
"python" not recognized as a command
(14 answers)
Closed 2 years ago.
This is a really annoying problem. I've prowled the web for solutions, but all I found was tips about changing the PATH variable, which I did, of course. My Python install directory is C:\Python27. It' a 32 bit version. Whenever I type python in the command prompt, it says that it isn't recognised as an internal or external command. Currently, my PATH variable is set to C:\Python27;C:\Python27\Lib\site-packages\;C:\Python27\Scripts. Anyone has any ideas? I run Windows 7 by the way (64 bit). I'm pretty desperate. Heck, if nothing works I guess I'll try dual-booting Linux and Windows 7...
Just adding the Python path and trying again worked for me (without reboot).
MS-dos command for Python 2.7:
set PATH=%PATH%;C:\python27\
MS-dos command for Python 3.3:
set PATH=%PATH%;C:\python33\
(check if that is the folder where you installed Python).
Quick fix: May not be the most elegant or long term fix but if you are really frustrated and just want to get it to run, just copy paste the python.exe file to your current directory. This worked for me.
After adding the python folder to the system PATH variable, you should reboot your computer.
Another simple solution is: create a shortcut of the python.exe executable (probably it is in C:\Python27\python.exe, or similar) in a place like C:\Windows\system32 (that is, a place that already is listed in the PATH variable). The name of your shortcut should be python (maybe python.exe should work too). I mean, it can't be python - shortcut or similar, for your purposes.
To see the contents of the PATH variable, go to the cmd and enter set PATH.
After changing the PATH variable in windows, you need to reboot your system before it takes effect.
Edit: As stated by #tdelaney, only a restart of cmd.exe should be required. This is true atleast for Windows 7 64bit.
In your PATH have you got a leading space before your Python path?
For example:
"C:\somedirectory\bin; C:\Python27;C:\Python27\Lib\site-packages\;C:\Python27\Scripts"
If you have a leading space between path's "ry\bin; C:\Pyt", it won't work and is usually the cause for this type of issue.
When installing, there is a checkbox that is by default not selected, but it asks to add python to the environment variable. Re-install and check that box.
I'd rather the installer do it than struggle in the weeds myself.
Okay, as you said your Python install directory is C:\Python27, open my computer, then open c: drive,
if you don't see "Python27" named folder there then try to search it using search option, (in my case i found it in old.window folder, don't know how it moved there) cut and past it in c drive along with folders like, program files, user etc... , now open cmd and type python and hit enter to check if it is working now,
This is only a partial answer, but I found (repeatedly) that I'd have similar issues when I would use the gui installer and not go through the custom setup.
Using the custom setup option, then using the same settings, the "install for all users" (that then installs to C://python.version/blah instead of the user based default structure) WOULD allow the installer to setup PATH correctly.
I have installed a new version of Python, so I want to make sure when Python is invoked that version is first in my path. So, now on my 'C' drive I have "Python27" and "Python32" (old and new version, respectively).
When I type "python" in the command line I get "Python 2.7". Using control panel I have changed the "path" and "pythonpath" user variables (from 'C:\Python27' to 'C:\Python32') and to be sure I have reload the system. It still does not work. Does anyone have any idea how I can force the system to use the new version of Python?
ADDED
May be this is important. When I go to the 'Python32' directory and type in command line 'python', I do get the new version.
I know you say you've updated %PATH%. However, from the description of the symptoms it is almost certain that c:\Python27 still appears on the %PATH% instead of (or before) c:\Python32.
To diagnose, start cmd.exe and type set. Then locate PATH and see what Python directories it contains and in what order.
Personally, I put the dirs to all installed Python versions in %PATH%, but changed the executable names for all but the 'default' version. E.g., I have a C:\Python26\Python.exe, C:\Python27\Python27.exe and a C:\Python32\Python32.exe. This way I can easily start any version from the command line.
I have a MacBook Pro with Snow Leopard, and the Python 2.6 distribution that comes standard. Numpy does not work properly on it. Loadtxt gives errors of the filename being too long, and getfromtxt does not work at all (no object in module error). So then I tried downloading the py26-numpy port on MacPorts. Of course when I use python, it defaults the mac distribution. How can I switch it to use the latest and greatest from MacPorts. This seems so much simpler than building all the tools I need from source...
Thanks!
First of all, add the MacPorts path (/opt/local/bin) to your $PATH. In .bashrc (or whatever shell config file you use):
export PATH="/opt/local/bin:${PATH}"
If you have multiple versions of Python installed via MacPorts, and/or want to easily switch between the MacPorts and Apple distributions, you can install the python_select port as well.
Also note that the MacPorts version of Python 2.6 is installed into /opt/local/bin/python2.6, so to use that interpreter, you'll have to do one of three things:
Start the interpreter using python2.6 (not just python).
Set up a shell alias so that python calls python2.6 (alias python=python2.6).
Manually set up a symlink from /opt/local/bin/python -> /opt/local/bin/python2.6.
Use python_select to set the Python used by calling python.
Options #3 or #4 are probably the best bet.
You need to update your PATH so that the stuff from MacPorts is in front of the standard system directories, e.g., export PATH=/opt/local/bin:/opt/local/sbin:/opt/local/Library/Frameworks/Python.framework/Versions/Current/bin/:$PATH.
UPDATE: Pay special attention to the fact that /opt/local/Library/Frameworks/Python.framework/Versions/Current/bin is in front of your old PATH value.
The existing answers are quite useful, but I noticed that neither of them spell out how to make the change stick. If you're not familiar with the unix command line this might be important.
First, and explanation: In unix based operating systems, important configuration information in the shell is stored in things called environment variables. The environment variable called PATH directs your shell to a list of places to look for programs. When you type a command, it starts at the leftmost end of the PATH variable, and looks in that folder for the program you tried to run. If it finds it, it runs it; else it looks in the next folder. When you have multiple versions of the same program installed, you can use the PATH variable to give one precedence.
To make use of this, put the folder with the shiny new version in front of the path, like this:
PATH=/opt/local/bin:/usr/bin:/usr/local/bin
To make this change in a single version of your shell, you can type
export PATH=/opt/local/bin:/usr/bin:/usr/local/bin
To make the change in every shell you open, you need to instruct your shell to set this variable every time it starts. There is a file called .bashrc, and another one called .bash_profile that bash will read when it starts up. The .bashrc file is generally used to contain instructions for all shells, and .bash_profile is used to contain instructions only for interactive shells. So, to make this change stick, you can edit /Users/yourname/.bashrc to include a line like this:
export PATH="/opt/local/bin:$PATH"
What that does is add /opt/local/bin to the front of the path variable while leaving the rest of the path alone. If that change doesn't seem to work, you will need to either ensure .bashrc is getting called by adding source $HOME/.bashrc to your .bash_profile script, or just move the necessary line into .bash_profile.