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

13,563

Solution 1

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.

Solution 2

You shouldn't need to mess with pip's path, python actually handles it's pathing automatically in my experience. It appears you have two pythons installed. If you type:

which pip
which python

what paths do you see? If they're not in the same /bin folder, then that's your problem. I'm guessing that the python you're running (probably the original system one), doesn't have it's own pip installed. You probably just need make sure the path for the python you want to run should come before /usr/bin in your .bashrc or .zshrc

If this is correct, then you should see that:

which easy_install

shares the same path as the python installation you're using, maybe under /usr/local/bin. Then just run:

easy_install pip

And start installing the right packages for the python that you're using.

Solution 3

Answer to direct question

You could create a directory called sitecustomize in your site-packages directory. We'll turn this into a sitecustomize module as described here (Python 2 here). Specifically:

an attempt is made to import a module named sitecustomize, which can perform arbitrary site-specific customizations. It is typically created by a system administrator in your site-packages directory.

In the sitecustomize directory create a file called __init__.py and add the manipulations you want to perform there. A very simple example is:

import sys
sys.path = ['/your/path/to/pip/install'] + sys.path

In your case, I think your/path... would be /usr/local/lib/python2.7/dist-packages. You might want to do something more sophisticated, but this crudely prepends to sys.path and is run whenever python is started (e.g. starting the interpreter in the command line, or running a python script from a file).

Caveat

I'm not a huge advocate of doing this - it's a bit of a blunt way to do what you want. But you specifically say that using a virtualenv is undesirable for you and you want to make the change "globally" and I think this will do what you want.

Thoughts on underlying issue

I think @fivetentaylor's answer is on the right track here - it appears you are using pip from one install with python executable for another. Masking this by messing with the path could get very confusing very quickly. I'd definitely ensure you have a separate pip for each install of python and you use that. That should keep the directory structures for the separate installs separate. Otherwise, you are forcing one install to use packages from a different installation's directories. No problem technically, but confusing logistically.

Solution 4

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.

Nope, you can use --system-site-packages.

Edit

# make your new virtualenv
user@darkstar:~$ mkvirtualenv --system-site-packages max
(max)user@darkstar:~$ python
>>> pprint(sys.path)
['',
 '/home/user/.virtualenvs/max/lib64/python27.zip',
 '/home/user/.virtualenvs/max/lib64/python2.7',
 '/home/user/.virtualenvs/max/lib64/python2.7/plat-linux2',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-old',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-dynload',
 '/usr/lib64/python2.7',
 '/usr/lib/python2.7',
 '/usr/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/google_api_python_client-1.2-py2.7.egg',
 '/usr/lib64/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/PIL',
 '/usr/lib64/python2.7/site-packages/gtk-2.0',
 '/usr/lib64/python2.7/site-packages/IPython/extensions']

As you see, the path of this virtualenv include the system path. To check if it was working, i installed a package system-wide after making the virtualenv.

root@darkstar:~: pip install igraph
Collecting igraph
  Downloading igraph-0.1.8-py2.py3-none-any.whl (119kB)
    100% |████████████████████████████████| 122kB 1.7MB/s
Collecting ipython (from igraph)
  Downloading ipython-3.2.1-py2-none-any.whl (3.4MB)
    100% |████████████████████████████████| 3.4MB 203kB/s 
Installing collected packages: ipython, igraph
Successfully installed igraph-0.1.8 ipython-3.2.1
root@darkstar:~: python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

(max)user@darkstar:max$ python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

Obviously, what is installed inside the virtualenv takes precedence over the system-wide libraries.

I belive that answer your needs.

Solution 5

I would do this with sitecustomize as described in the site.py docs. This file is imported after the initial sys.path is configured and you can use it to alter sys.path in arbitrary ways as needed.

I've used it as a sysadmin to include custom release locations and it does the job quite nicely.

https://docs.python.org/2/library/site.html

Share:
13,563
max
Author by

max

Updated on June 07, 2022

Comments

  • max
    max about 2 years

    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!