views:

144

answers:

1

I have a "canonical file structure" like that (I'm giving sensible names to ease the reading):

mainpack/

  __main__.py
  __init__.py 

  - helpers/
     __init__.py
     path.py

  - network/
     __init__.py
     clientlib.py
     server.py

  - gui/
     __init__.py
     mainwindow.py
     controllers.py

In this structure, for example modules contained in each package may want to access the helpers utilities through relative imports in something like:

# network/clientlib.py
from ..helpers.path import create_dir

The program is runned "as a script" using the __main__.py file in this way:

python mainpack/

Trying to follow the PEP 366 I've put in __main__.py these lines:

___package___ = "mainpack"
from .network.clientlib import helloclient 

But when running:

$ python mainpack 
Traceback (most recent call last):
  File "/usr/lib/python2.6/runpy.py", line 122, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.6/runpy.py", line 34, in _run_code
    exec code in run_globals
  File "path/mainpack/__main__.py", line 2, in <module>
    from .network.clientlib import helloclient
SystemError: Parent module 'mainpack' not loaded, cannot perform relative import

What's wrong? What is the correct way to handle and effectively use relative imports?

I've tried also to add the current directory to the PYTHONPATH, nothing changes.

+1  A: 

The loading code seems to be something like this:

    try:
        return sys.modules[pkgname]
    except KeyError:
        if level < 1:
            warn("Parent module '%s' not found while handling "
                 "absolute import" % pkgname, RuntimeWarning, 1)
            return None
        else:
            raise SystemError, ("Parent module '%s' not loaded, cannot "
                                "perform relative import" % pkgname)

which makes me think that maybe your module is not on sys.path. If you start Python (normally) and just type "import mainpack" on the prompt, what does it do? It should be able to find it.

I have tried it myself and got the same error. After reading a bit I found the following solution:

# foo/__main__.py
import sys
mod = __import__('foo')
sys.modules["foo"]=mod

__package__='foo'
from .bar import hello

hello()

It seems a bit hackish to me but it does work. The trick seems to be making sure package foo is loaded so the import can be relative.

extraneon
I'm able to import it from the directory I'm launching, I've to watch this better
pygabriel
@pygabriel Is it possible for you to zip it and put it on the web somewhere?
extraneon
for sure! http://dl.dropbox.com/u/1276730/mainpack.zip
pygabriel
@pygabriel Found a solution. It may not be very beautiful but it does work :)
extraneon
thank you very very much, anyway this saves a lot of hackish code in other modules! (various sys.path munging)
pygabriel