Ultimate answer to relative python imports
Question: I know that there are lots of questions about the same import issues in Python
but it seems that nobody managed to provide a clear example of correct usage.

Let's say that we have a package `mypackage` with two modules `foo` and `bar`.
Inside `foo` we need to be able to access `bar`.

Because we are still developing it, `mypackage` is not in `sys.path`.

We want to be able to:

  * import `mypackage.foo`
  * run `foo.py` as a script and execute the sample usage or tests from the `__main__` section.
  * use Python 2.5

How do we have to do the import in foo.py in order to be sure it will work in
all these cases.

    
    
    # mypackage/__init__.py
    ...
    
    # mypackage/foo/__init__.py
    ...
    
    # mypackage/bar.py  
    def doBar()
        print("doBar")
    
    # mypackage/foo/foo.py
    import bar # fails with module not found
    import .bar #fails due to ValueError: Attempted relative import in non-package
    
    def doFoo():
        print(doBar())
    
    if __name__ == '__main__':
        doFoo()
    


Answer: Take a look at the following info from [PEP
328](http://www.python.org/dev/peps/pep-0328/#relative-imports-and-name):

> Relative imports use a module's `__name__` attribute to determine that
> module's position in the package hierarchy. If the module's name does not
> contain any package information (e.g. it is set to `'__main__'`) then
> relative imports are resolved as if the module were a top level module,
> regardless of where the module is actually located on the file system.

When you run `foo.py` as a script, that module's `__name__` is `'__main__'`,
so you cannot do relative imports. This would be true even if `mypackage` was
on `sys.path`. Basically, you can only do relative imports from a module if
that module was imported.

Here are a couple of options for working around this:

1) In `foo.py`, check if `__name__ == '__main__'` and conditionally add
`mypackage` to `sys.path`:

    
    
    if __name__ == '__main__':
        import os, sys
        # get an absolute path to the directory that contains mypackage
        foo_dir = os.path.dirname(os.path.join(os.getcwd(), __file__))
        sys.path.append(os.path.normpath(os.path.join(foo_dir, '..', '..')))
        from mypackage import bar
    else:
        from .. import bar
    

2) Always import `bar` using `from mypackage import bar`, and execute `foo.py`
in such a way that `mypackage` is visible automatically:

    
    
    $ cd <path containing mypackage>
    $ python -m mypackage.foo.foo
    

