Mismatch Between Sys.Executable and Sys.Version in Python

Mismatch between sys.executable and sys.version in Python

Both @Graeme

The fact that python may be unable to retrieve this suggests that it
is doing its own PATH search (…)

and @twalberg

(…) it looks like sys.executable searches the current PATH instead of
resolving argv[0] (or maybe because argv[0] is simpy python in this
case...), (…)

were basically right. I was reluctant to believe that Python does something so simple (silly?) as using PATH to locate itself but this is true.

Python's sys module is implemented in Python/sysmodule.c file. As of version 2.7.6, sys.executable is set at line 1422 like this:

 SET_SYS_FROM_STRING("executable",
PyString_FromString(Py_GetProgramFullPath()));

Py_GetProgramFullPath() function is defined in file Modules/getpath.c starting from line 701:

char *
Py_GetProgramFullPath(void)
{
if (!module_search_path)
calculate_path();
return progpath;
}

Function calcuate_path() is defined in the same file and contains the following comment:

/* If there is no slash in the argv0 path, then we have to
* assume python is on the user's $PATH, since there's no
* other way to find a directory to start the search from. If
* $PATH isn't exported, you lose.
*/

As can be seen in my case, one loses also when the first Python on exported $PATH is different than the Python being run.

More information on the process of calculating placement of interpreter's executable can be found at the top of getpath.c file:

Before any searches are done, the location of the executable is
determined. If argv[0] has one or more slashes in it, it is used
unchanged. Otherwise, it must have been invoked from the shell's path,
so we search $PATH for the named executable and use that. If the
executable was not found on $PATH (or there was no $PATH environment
variable), the original argv[0] string is used.

Next, the executable location is examined to see if it is a symbolic
link. If so, the link is chased (correctly interpreting a relative
pathname if one is found) and the directory of the link target is used.

Let's make a couple of tests to verify the above:

If argv[0] has one or more slashes in it, it is used unchanged.

[user@localhost ~]$ sudo /usr/local/bin/python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

Ok.

If the executable was not found on $PATH (or there was no $PATH environment variable), the original argv[0] string is used.

[user@localhost ~]$ sudo PATH= python what_python.py
<empty line>
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

Wrong. In this case statement from sys module's documentation is true – If Python is unable to retrieve the real path to its executable, sys.executable will be an empty string or None. .

Let's see if adding location of python's binary back to the PATH (after sudo had removed it) fixes the problem:

[user@localhost ~]$ sudo PATH=$PATH python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

It does.

Related:

  • Python issue 7774 – sys.executable: wrong location if zeroth command argument is modified.
  • Python issue 10835 – sys.executable default and altinstall
  • python-dev mailing list thread – towards a stricter definition of sys.executable
  • Stackoverflow question – how to find the location of the executable in C

Is sys.version_info reliable for Python version checking?

Yes. sys.version_info is a reliable way to determine Python version.

See Python 3 documentation and Python 2 documentation.

Note: sys.version_info is reliable, but not sys.version:

sys.version


A string containing the version number of the Python interpreter plus additional information on the build number and compiler used. This string is displayed when the interactive interpreter is started. Do not extract version information out of it, rather, use version_info and the functions provided by the platform module.

If you're worried about bad modules changing the values of sys.version_info or something else, you can force a reload of <module 'sys' (built-in)>:

import sys
sys.version_info = "boo"
print(sys.version_info) # boo

sys.modules.pop("sys")
import sys # reloaded
print(sys.version_info)
# Output: sys.version_info(major=3, minor=6, ...

How do you get Visual Studio Code to use different Python interpreter?

Open command pallete with F1 (on Windows) and type Python: Select Interpreter.

ipython reads wrong python version

Okay quick fix:

which python

gives you /usr/bin/python, right? Do

which ipython

and I bet that'll be /usr/local/bin/ipython. Let's look inside:

Edit 9/7/16 -- The file now looks like this:

cat /usr/local/bin/ipython

#!/usr/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from IPython import start_ipython

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(start_ipython())

And mine works properly like this, but my situation isn't exactly like the OP's.


Original answer -- 9/30/13:

cat /usr/local/bin/ipython

#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'ipython==0.12.1','console_scripts','ipython'
__requires__ = 'ipython==0.12.1'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.exit(
load_entry_point('ipython==0.12.1', 'console_scripts', 'ipython')()
)

Aha - open /usr/local/bin/ipython in your editor (with privileges), and change the first line to

#!/usr/local/bin/python

save, start iPython, should say it's using the version you want now.

ProtocolConnectionException in the context of Python versions

I suspect this Python version stuff is a red herring. What's happening is this code is attempting to listen on a TCP port (whatever self.port is), but something else is already listening there. On Linux, you could run sudo netstat -anp | grep LISTEN to figure out what process that is.



Related Topics



Leave a reply



Submit