views:

547

answers:

3

I have a python project with this directory structure and these files:

/home/project_root
|---__init__.py
|---setup
       |---__init__.py
       |---configs.py
|---test_code
       |---__init__.py
       |---tester.py

The tester script imports from setup/configs.py with the reference "setup.configs". It runs fine on my development machine.

This works on the development (Linux) computer. When I move this to another (Linux) computer, I set the PYTHONPATH with

PYTHONPATH = "/home/project_root"

But when I run tester.py, it can't find the configs module. And when I run the interactive Python interpreter, sys.path doesn't include the /home/project_root directory. But /home/project_root does appear when I echo $PYTHPATH.

What am I doing wrong here?

(I don't want to rely on the .bashrc file to set the PYTHONPATH for the target machine -- the code is for a Django application, and will eventually be run by www-data. And, I know that the apache configuration for Django includes a specification of the PYTHONPATH, but I don't want to use that here as I'm first trying to make sure the code passes its unit tests in the target machine environment.)

CURIOUSER AND CURIOUSER This seems to be a userid and permissions problem. - When launched by a command from an ordinary user, the interpreter can import modules as expected. - When launched by sudo (I'm running Ubuntu here), the interpreter cannot import modules as expected. - I've been calling the test script with sudo, as the files are owned by www-data (b/c they'll be called by the user running apache as part of the Django application). - After changing the files' ownership to that of an ordinary user, the test script does run without import errors (albeit, into all sorts of userid related walls).

Sorry to waste your time. This question should be closed.

A: 

Try explicitly setting your python path in your scripts. If you don't want to have to change it, you could always add something like "../" to the path in tester. That is to say:

sys.path.append("../")
Paul McMillan
I thought of that, but that would require adding lines to many scripts. And the lines would break whenever a file was moved relative to the root directory.
chernevik
+4  A: 

Stick this in the tester script right before the import setup.configs

import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir))

sys.path is a list of all the directories the python interpreter looks for when importing a python module. This will add the parent directory which contains setup module to the beginning of that list which means that the local directory will be checked first. That is important if you have your module installed system wide. More info on that here: sys doc.

EDIT: You could also put a .pth file in /usr/local/lib/python2.X/site-packages/ A .pth file is simply a text file with a directory path on each line that the python interpreter will search in. So just add a file with this line in it:

/home/project_root
DoR
Okay, but what if my unit tests are spread over many files? I'd need to add this to all of them, or setup a single python file to run them all. (I do have a "run all" script, but right now it's in bash, though of course that's easy enough to change.)
chernevik
Ok, I updated my answer.
DoR
Adding the directory to the python path with a .pth file was the ultimate answer. I had to figure out some Ubuntu quirks to the the .pth file to work (the directory suggested by the answer didn't work for my computer -- see question 1369947, python-pth-files-arent-working).
chernevik
Good answer, but a couple issues with the code as given: 1) dirname needs an os.path prefix (unless we're assuming it's been directly imported?), and 2) there's a missing ')' on the end. Might also want to add the import statements for os and sys to be extra clear.
overthink
@overthink: Thanks for pointing that out.
DoR
A: 

(I don't want to rely on the .bashrc file to set the PYTHONPATH for the target machine -- the code is for a Django application, and will eventually be run by www-data. And, I know that the apache configuration for Django includes a specification of the PYTHONPATH, but I don't want to use that here as I'm first trying to make sure the code passes its unit tests in the target machine environment.)

If the code is for a Django application, is there a reason you're not testing it in the context of a Django project? Testing it in the context of a Django project gives a couple benefits:

  1. Django's manage.py will set up your Python environment for you. It'll add the appropriate project paths to sys.path, and it'll set the environment variable DJANGO_SETTINGS_MODULE correctly.
  2. Django's libraries include ample unit testing facilities, and you can easily extend that functionality to include your own testing facilities. Executing tests in a Django project is as easy as executing a single command via manage.py.
mipadi
The code in question isn't Django specific. It's a sort of library to be called by more Django specific code, but also written to provide services to other graphic interfaces beyond browsers calling Django. So testing in a Django environment hadn't occurred to me, and I haven't thought of how I'd do so.
chernevik
Use the django unit testing commands. http://docs.djangoproject.com/en/dev/topics/testing/ Then you'll be testing in an environment which is close to your deploy environment.
Paul McMillan