How to prepend a path to sys.path in Python?

max picture max · Jul 14, 2015 · Viewed 11.5k times · Source

Problem description:

Using pip, I upgraded to the latest version of requests (version 2.7.0, with pip show requests giving the location /usr/local/lib/python2.7/dist-packages). When I import requests and print requests.__version__ in the interactive command line, though, I am seeing version 2.2.1. It turns out that Python is using the pre-installed Ubuntu version of requests (requests.__file__ is /usr/lib/python2.7/dist-packages/requests/__init__.pyc -- not /user/local/lib/...).

From my investigation, this fact is caused by Ubuntu's changes to the Python search path (I run Ubuntu 14.04) by prepending the path to Ubuntu's Python package (for my machine, this happens in usr/local/lib/python2.7/dist-packages/easy-install.pth). In my case, this causes the apt-get version of requests, which is pre-packaged with Ubuntu, to be used, rather than the pip version I want to use.

What I'm looking for:

I want to globally prepend pip's installation directory path to Python's search path (sys.path), before the path to Ubuntu's Python installation directory. Since requests (and many other packages) are used in many Python scripts of mine, I don't want to manually change the search path for every single file on my machine.

Unsatisfactory Solution 1: Using virtualenv

Using virtualenv would cause an unnecessary amount of change to my machine, since I would have to reinstall every package that exists globally. I only want to upgrade from Ubuntu's packages to pip's packages.

Unsatisfactory Solution 2: Changing easy-install.pth

Since easy-install.pth is overwritten every time easy-install is used, my changes to easy-install.pth would be removed if a new package is installed. This problem makes it difficult to maintain the packages on my machine.

Unsatisfactory (but best one I have so far) Solution 3: Adding a separate .pth file

In the same directory as easy-install.pth I added a zzz.pth with contents:

import sys; sys.__plen = len(sys.path)
/usr/lib/python2.7/dist-packages/test_dir
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

This file is read by site.py when Python is starting. Since its file name comes after easy-install.pth alphanumerically, it is consumed by site.py afterwards. Taken together, the first and last lines of the file prepend the path to sys.path (these lines were taken from easy-install.pth).

I don't like how this solution depends on the alphanumeric ordering of the file name to correctly place the new path.

PYTHONPATHs come after Ubuntu's paths

Another answer on Stack Overflow didn't work for me. My PYTHONPATH paths come after the paths in easy-install.pth, which uses the same code I mention in "Unsatisfactory solution 3" to prepend its paths.

Thank you in advance!

Answer

Nandhini Anand Jeyahar picture Nandhini Anand Jeyahar · Jul 24, 2015

This is not recommended, as it hard-codes a path and makes it difficult to run the script elsewhere, but you can do

>>> import sys
>>> sys.path.insert(0,'/home/anand/')
>>> print(sys.path)
['/home/anand/', '', '/usr/local/lib/python2.7/dist-packages/_pdbpp_path_hack', '/usr/local/lib/python2.7/dist-packages/goose-0.0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/jieba-0.33-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/cssselect-0.9.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanoservice-0.1.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanomsg-1.0a2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/msgpack_python-0.4.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/DecisionTree-2.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nudepy-0.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/wsgilog-0.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/distribute-0.7.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/PIL-1.1.7-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/MySQL_python-1.2.5-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/munkres-1.0.7-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/parsedatetime-1.4-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/argparse-1.3.0-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/tusker-0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/SQLAlchemy-1.0.3-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/numpy-1.9.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/turkic-0.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/scikits.bootstrap-0.3.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/pyvision-0.1-py2.7-linux-x86_64.egg', '/home/anand/playspace/languages/python_pkgs/ets', '/usr/local/lib/python2.7/dist-packages/Scrapy-1.1.0dev1-py2.7.egg', '/usr/lib/python2.7/dist-packages', '/home/anand/playspace', '/home/anand/workspace/pyvision/src', '/home/anand/playspace/yapf', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/Orange/orng', '/usr/local/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/wx-3.0-gtk2']
>>>

After this your imports will look into the prepended path before looking anywhere else.