views:

52

answers:

2

I have a directory struture like that:

project
|  __init__.py
| project.py
| src/
    | __init__.py
    | class_one.py
    | class_two.py
| test/
    | __init__.py
    | test_class_one.py

Which project.py just instantiate ClassOne and run it.

My problem is in the tests, I don't know how to import src classes. I've tried importing these ways and I got nothing:

from project.src.class_one import ClassOne

and

from ..src.class_one import ClassOne

What am I doing wrong? Is there a better directory structure?

----- EDIT -----

I changed my dir structure, it's like this now:

Project/
|   project.py
|   project/
    |   __init__.py
    |   class_one.py
    |   class_two.py
    |   test/
        |   __init__.py
        |   test_class_one.py

And in the test_class_one.py file I'm trying to import this way:

from project.class_one import ClassOne

And it still doesn't work. I'm not using the executable project.py inside a bin dir exactly because I can't import a package from a higher level dir. :(

Thanks. =D

A: 

From Jp Calderone's excellent blog post:

Do:

  • name the directory something related to your project. For example, if your project is named "Twisted", name the top-level directory for its source files Twisted. When you do releases, you should include a version number suffix: Twisted-2.5.
  • create a directory Twisted/bin and put your executables there, if you have any. Don't give them a .py extension, even if they are Python source files. Don't put any code in them except an import of and call to a main function defined somewhere else in your projects. (Slight wrinkle: since on Windows, the interpreter is selected by the file extension, your Windows users actually do want the .py extension. So, when you package for Windows, you may want to add it. Unfortunately there's no easy distutils trick that I know of to automate this process. Considering that on POSIX the .py extension is a only a wart, whereas on Windows the lack is an actual bug, if your userbase includes Windows users, you may want to opt to just have the .py extension everywhere.)
  • If your project is expressable as a single Python source file, then put it into the directory and name it something related to your project. For example, Twisted/twisted.py. If you need multiple source files, create a package instead (Twisted/twisted/, with an empty Twisted/twisted/__init__.py) and place your source files in it. For example, Twisted/twisted/internet.py.
  • put your unit tests in a sub-package of your package (note - this means that the single Python source file option above was a trick - you always need at least one other file for your unit tests). For example, Twisted/twisted/test/. Of course, make it a package with Twisted/twisted/test/__init__.py. Place tests in files like Twisted/twisted/test/test_internet.py.
  • add Twisted/README and Twisted/setup.py to explain and install your software, respectively, if you're feeling nice.

Don't:

  • put your source in a directory called src or lib. This makes it hard to run without installing.
  • put your tests outside of your Python package. This makes it hard to run the tests against an installed version.
  • create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module instead of a package, it's simpler.
  • try to come up with magical hacks to make Python able to import your module or package without having the user add the directory containing it to their import path (either via PYTHONPATH or some other mechanism). You will not correctly handle all cases and users will get angry at you when your software doesn't work in their environment.
Ignacio Vazquez-Abrams
Nice tips, but I still have problem importing a package in a higher level.
CrociDB
+1  A: 

It all depends on your python path. The easiest way to achieve what you're wanting to do here is to set the PYTHONPATH environment variable to where the "project" directory resides. For example, if your source is living in:

/Users/crocidb/src/project/

I would:

export PYTHONPATH=/Users/crocidb/src

and then in the test_one.py I could:

import project.src.class_one

Actually I would probably do it this way:

export PYTHONPATH=/Users/crocidb/src/project

and then this in test_one.py:

import src.class_one

but that's just my preference and really depends on what the rest of your hierarchy is. Also note that if you already have something in PYTHONPATH you'll want to add to it:

export PYTHONPATH=/Users/crocidb/src/project:$PYTHONPATH

or in the other order if you want your project path to be searched last.

This all applies to windows, too, except you would need to use windows' syntax to set the environment variables.

cygnl7
Further info: http://docs.python.org/tutorial/modules.html#the-module-search-path
cygnl7
It worked! I just had to add my project's dir to the PYTHONPATH. Thank you. =D
CrociDB