PYTHONPATH для конкретного приложения - PullRequest
4 голосов
/ 22 июля 2011

У меня есть приложение с иерархией пакетов.Существует немало модулей, которые ссылаются на другие модули выше в иерархии пакетов.Как показано ниже, я могу использовать относительный импорт для решения этой проблемы.Однако запуск модуля непосредственно для тестирования завершается неудачно с исключением Attempted relative import in non-package.

Существует ли лучший способ организовать мое приложение или операторы импорта, чтобы модули могли выполняться по отдельности для тестирования и импортироваться из других модулей??

Пример

\spam
    \morespam
        child.py
    base.py
\eggs
    user.py

base.py

class Base(object):
    def hello(self):
        print 'Um, wot?'

child.py

from ..base import Base       # references the parent package correctly, 
                              # but fails when this module is executed individually

class Child(Base):
    def hello(self):
        print 'Hello, world!'

if __name__ == '__main__':
    import unittest
    # ... unit test code ...

user.py

from spam.morespam.child import Child
print Child().hello()

Существующее решение

Я обнаружил, что могу добавить следующий заголовок, добавленный в начало модуля, который долженссылочные модули выше в иерархии:

if __name__ == '__main__':
    import sys, os
    sys.path.append(os.path.abspath(os.path.join(sys.path[0], '..')))

Недостатком является то, что мне нужно добавить этот код повсюду, и он не является постоянным: относительный путь '..' зависит от глубиныпакет в иерархии.

Другие возможные решения ...

  1. Я мог бы создать файл .pth с корнем своего приложения.К сожалению, это должно быть добавлено в папку site-packages моей установки Python, так что это не очень специфично для приложения.
  2. Я мог бы временно добавить корень моего приложения в PYTHONPATH и сделатьвсе мои модули ссылаются на пакеты из корня.Это исключает простоту запуска сценария простым вызовом python.exe whatever.py, хотя.
  3. Я мог бы написать какой-то модуль, который при импорте будет искать файл маркера в корневой папке моего приложения.Этот универсальный модуль затем может быть установлен в мою локальную установку Python и импортирован каждым модулем в моем приложении, что гарантирует, что корень находится в PYTHONPATH, независимо от того, какой модуль я выполняю.

Ответы [ 2 ]

1 голос
/ 19 августа 2011

Вам необходимо добавить __init__.py как пустые файлы в папки, из которых вы хотите импортировать файлы.Это приведет к тому, что python будет обращаться с каталогами как с пакетами, что позволит вам использовать их в операторах импорта:

\spam
    \morespam
        __init__.py
        child.py
    __init__.py
    base.py
\eggs
    __init__.py
    user.py

После того, как вы сделаете это и установите PYTHONPATH для базы этого каталога, вы можете затем выполнить импорт:

base.py :

from morespam.child import Child
from ..eggs import user

Хотя требуется только файл __init__.py, вы также можете определить переменную __ALL__ в этом файлекак список модулей в этом каталоге, которые вы хотите импортировать, если скрипт пытается использовать import *.

0 голосов
/ 01 ноября 2011

Я решил это с помощью PyCharm, который автоматически добавляет мой исходный корень в PYTHONPATH при каждом запуске моего приложения. Насколько я могу судить, PyCharm в основном делает для меня вариант №2.

...