У меня есть "каноническая файловая структура" как этот (я даю разумные имена для упрощения чтения):
mainpack/
__main__.py
__init__.py
- helpers/
__init__.py
path.py
- network/
__init__.py
clientlib.py
server.py
- gui/
__init__.py
mainwindow.py
controllers.py
В этой структуре например, модули, содержавшиеся в каждом пакете, могут хотеть получить доступ helpers
утилиты через относительный импорт в чем-то как:
# network/clientlib.py
from ..helpers.path import create_dir
Программа является runned "как сценарием" использование __main__.py
файл таким образом:
python mainpack/
При попытке следовать за PEP 366 я вставил __main__.py
эти строки:
___package___ = "mainpack"
from .network.clientlib import helloclient
Но при выполнении:
$ 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
from .network.clientlib import helloclient
SystemError: Parent module 'mainpack' not loaded, cannot perform relative import
Что случилось? Что корректный путь состоит в том, чтобы обработать и эффективно использовать относительный импорт?
Я попытался также добавить текущий каталог к PYTHONPATH, ничто не изменяется.
Код загрузки кажется чем-то вроде 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)
что заставляет меня думать, что, возможно, ваш модуль не находится в sys.path. Если вы запустите Python (нормально) и просто напечатаете "import mainpack" в приглашении, что он сделает? Он должен быть в состоянии найти его.
Я попробовал это сам и получил ту же ошибку. Почитав немного, я нашел следующее решение:
# foo/__main__.py
import sys
mod = __import__('foo')
sys.modules["foo"]=mod
__package__='foo'
from .bar import hello
hello()
Мне оно кажется немного хакерским, но оно работает. Похоже, что хитрость заключается в том, чтобы убедиться, что пакет foo
загружен, так что импорт может быть относительным.