3

I have a small python module

+-- address_book
|   +-- models.py
|   +-- __init__.py 
    +-- test
    |   +-- test_models.py 

When I run python address_book/test/test_models.py I get this error

Traceback (most recent call last):
  File "address_book/test/test_models.py", line 5, in <module>
    from address_book import models
ImportError: No module named 'address_book'

test_models.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest
from address_book import models
...
...
...
if __name__ == '__main__':
    unittest.main()
4
  • 6
    Your tree is strange. __init__.py is a file, not a directory, right? Commented Oct 10, 2016 at 8:51
  • @S.deMelo I've updated the tree Commented Oct 10, 2016 at 9:24
  • What directory do you run your tests from? You may find that python address_book/test/test_models.py works where python test_models.py does not. Commented Oct 10, 2016 at 9:59
  • @Dunes both don't work Commented Oct 10, 2016 at 10:07

4 Answers 4

2

Your file structure should look like

+-- address_book
|    +-- __init__.py
|    +-- models.py
     +-- test
     |    +-- test_models.py
     |    +-- __init__.py

For your code to work you also have to be in the directory above address_book.

Sign up to request clarification or add additional context in comments.

Comments

2

Like said in comment, your tree looks strange. Put tests on the same level as address_book.

To run the tests, you should use auto test discovery tools like nose or pytest (in doubt, go for pytest). Those tools automatically find the packages they are testing so that you don't have to install them or care in any way about their presence in the PATH.

It might sound like a burden at first, having to learn a new tool, but it's pretty straightforward, and on the long run, pytest is really helpful.

2 Comments

Actually I'm using nose and it's working, but if I want to generate test code coverage coverage run --source python address_book/test/test_models.py It won't work and give me the same error above.
When using nose, I used to use the coverage plugin with the --with-coverage flag. (I know this does not really answer the OP, but it might help.)
1

The problem stems from the fact that python does not know where to look for address_book. You can fix this by setting the PYTHONPATH environment variable before starting python.

Given the following directory structure:

base_dir
+-- address_book
|   +-- __init__.py 
|   +-- models.py
    +-- test
    |   +-- test_models.py

Then this will work:

$ env PYTHONPATH=/path/to/base_dir python address_book/test/test_models.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

PYTHONPATH can be a relative path as well, just so long as the relative path points to the source directory from the current working directory

To avoid typing out the env PYTHONPATH=/path/to/base_dir each time you can set it using your shells appropriate syntax. Below I set the PYTHONPATH environment variable using a bash syntax.

$ cd /path/to/base_dir
$ export PYTHONPATH=. # the current directory as a relative link
$ python address_book/test/test_models.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

As a side note I would alter your directory structure as it's not a great idea to keep your tests in the same directory tree as your source directory. Typically you might do something like this:

base_dir
+-- address_book
|   +-- __init__.py 
|   +-- models.py
+-- test # no __init__, not a module
|   +-- test_models.py

This allows you to more easily package your project without also including your tests.

Comments

0
There is problem with import of module from parent directory as __main__ lies in child folder
if you do the folder structure like below your same code for import will work

+----test
     +---test_models.py
     +---__init__.py
     +---address_book
         +---__init__.py
         +---models.py

or you can add your project path to PYTHONPATH variable and your same code will work

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.