pythonimportpytest

Importing correctly with pytest


I just got set up to use pytest with Python 2.6. It has worked well so far with the exception of handling "import" statements: I can't seem to get pytest to respond to imports in the same way that my program does.

My directory structure is as follows:

src/
    main.py
    util.py
    test/
        test_util.py
    geom/
        vector.py
        region.py
        test/
            test_vector.py
            test_region.py

To run, I call python main.py from src/.

In main.py, I import both vector and region with

from geom.region import Region
from geom.vector import Vector

In vector.py, I import region with

from geom.region import Region

These all work fine when I run the code in a standard run. However, when I call "py.test" from src/, it consistently exits with import errors.


Some Problems and My Solution Attempts

My first problem was that, when running "test/test_foo.py", py.test could not "import foo.py" directly. I solved this by using the "imp" tool. In "test_util.py":

import imp
util = imp.load_source("util", "util.py")

This works great for many files. It also seems to imply that when pytest is running "path/test/test_foo.py" to test "path/foo.py", it is based in the directory "path".

However, this fails for "test_vector.py". Pytest can find and import the vector module, but it cannot locate any of vector's imports. The following imports (from "vector.py") both fail when using pytest:

from geom.region import *
from region import *

These both give errors of the form

ImportError: No module named [geom.region / region]

I don't know what to do next to solve this problem; my understanding of imports in Python is limited.

What is the proper way to handle imports when using pytest?


Edit: Extremely Hacky Solution

In vector.py, I changed the import statement from

from geom.region import Region

to simply

from region import Region

This makes the import relative to the directory of "vector.py".

Next, in "test/test_vector.py", I add the directory of "vector.py" to the path as follows:

import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))

This enables Python to find "../region.py" from "geom/test/test_vector.py".

This works, but it seems extremely problematic because I am adding a ton of new directories to the path. What I'm looking for is either

1) An import strategy that is compatible with pytest, or

2) An option in pytest that makes it compatible with my import strategy

So I am leaving this question open for answers of these kinds.


Solution

  • import looks in the following directories to find a module:

    1. The home directory of the program. This is the directory of your root script. When you are running pytest your home directory is where it is installed (/usr/local/bin probably). No matter that you are running it from your src directory because the location of your pytest determines your home directory. That is the reason why it doesn't find the modules.
    2. PYTHONPATH. This is an environment variable. You can set it from the command line of your operating system. In Linux/Unix systems you can do this by executing: 'export PYTHONPATH=/your/custom/path' If you wanted Python to find your modules from the test directory you should include the src path in this variable.
    3. The standard libraries directory. This is the directory where all your libraries are installed.
    4. There is a less common option using a pth file.

    sys.path is the result of combining the home directory, PYTHONPATH and the standard libraries directory. What you are doing, modifying sys.path is correct. It is something I do regularly. You could try using PYTHONPATH if you don't like messing with sys.path