[python] PYTHONPATH vs. sys.path

Another developer and I disagree about whether PYTHONPATH or sys.path should be used to allow Python to find a Python package in a user (e.g., development) directory.

We have a Python project with a typical directory structure:

Project
    setup.py
    package
        __init__.py
        lib.py
        script.py

In script.py, we need to do import package.lib. When the package is installed in site-packages, script.py can find package.lib.

When working from a user directory, however, something else needs to be done. My solution is to set my PYTHONPATH to include "~/Project". Another developer wants to put this line of code in the beginning of script.py:

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

So that Python can find the local copy of package.lib.

I think this is a bad idea, as this line is only useful for developers or people running from a local copy, but I can't give a good reason why it is a bad idea.

Should we use PYTOHNPATH, sys.path, or is either fine?

This question is related to python python-import pythonpath sys.path

The answer is


If the only reason to modify the path is for developers working from their working tree, then you should use an installation tool to set up your environment for you. virtualenv is very popular, and if you are using setuptools, you can simply run setup.py develop to semi-install the working tree in your current Python installation.


I hate PYTHONPATH. I find it brittle and annoying to set on a per-user basis (especially for daemon users) and keep track of as project folders move around. I would much rather set sys.path in the invoke scripts for standalone projects.

However sys.path.append isn't the way to do it. You can easily get duplicates, and it doesn't sort out .pth files. Better (and more readable): site.addsitedir.

And script.py wouldn't normally be the more appropriate place to do it, as it's inside the package you want to make available on the path. Library modules should certainly not be touching sys.path themselves. Instead, you'd normally have a hashbanged-script outside the package that you use to instantiate and run the app, and it's in this trivial wrapper script you'd put deployment details like sys.path-frobbing.


In general I would consider setting up of an environment variable (like PYTHONPATH) to be a bad practice. While this might be fine for a one off debugging but using this as
a regular practice might not be a good idea.

Usage of environment variable leads to situations like "it works for me" when some one
else reports problems in the code base. Also one might carry the same practice with the test environment as well, leading to situations like the tests running fine for a particular developer but probably failing when some one launches the tests.


I think, that in this case using PYTHONPATH is a better thing, mostly because it doesn't introduce (questionable) unneccessary code.

After all, if you think of it, your user doesn't need that sys.path thing, because your package will get installed into site-packages, because you will be using a packaging system.

If the user chooses to run from a "local copy", as you call it, then I've observed, that the usual practice is to state, that the package needs to be added to PYTHONPATH manually, if used outside the site-packages.


Neither hacking PYTHONPATH nor sys.path is a good idea due to the before mentioned reasons. And for linking the current project into the site-packages folder there is actually a better way than python setup.py develop, as explained here:

pip install --editable path/to/project

If you don't already have a setup.py in your project's root folder, this one is good enough to start with:

from setuptools import setup
setup('project')

Along with the many other reasons mentioned already, you could also point outh that hard-coding

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

is brittle because it presumes the location of script.py -- it will only work if script.py is located in Project/package. It will break if a user decides to move/copy/symlink script.py (almost) anywhere else.


Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to python-import

Python: 'ModuleNotFoundError' when trying to import module from imported package ImportError: libSM.so.6: cannot open shared object file: No such file or directory Relative imports - ModuleNotFoundError: No module named x ModuleNotFoundError: What does it mean __main__ is not a package? Reading file using relative path in python project What does from __future__ import absolute_import actually do? Why does using from __future__ import print_function breaks Python2-style print? Automatically create requirements.txt Error importing Seaborn module in Python Why can't Python import Image from PIL?

Examples related to pythonpath

sys.path different in Jupyter and Python - how to import own modules in Jupyter? Effect of using sys.path.insert(0, path) and sys.path(append) when loading modules PYTHONPATH on Linux How to configure custom PYTHONPATH with VM and PyCharm? How to get the PYTHONPATH in shell? adding directory to sys.path /PYTHONPATH set pythonpath before import statements Why use sys.path.append(path) instead of sys.path.insert(1, path)? Import Error: No module named django django import error - No module named core.management

Examples related to sys.path

Get parent of current directory from Python script Permanently adding a file path to sys.path in Python PYTHONPATH vs. sys.path