У вас есть несколько вариантов здесь.
Ваш лучший вариант - сохранить пакеты отдельно от сценариев, которые используют пакет. Посмотрите на entry_points
для setuptools. Вы указываете setuptools на функцию в вашем пакете и создаете скрипт, чтобы вызвать его. Острота ...
В играя с этим, я создал следующую структуру пакета:
test_dir
+ __init__.py
+ main.py
+ sub1
--+ __init__.py
--+ script.py
+ sub2
--+ __init__.py
--+ module.py
и я убедился, что test_dir
доступен через PYTHONPATH
.
Сценарии все супер просто (только печать некоторые вещи):
# main.py
def func_in_main():
print("Hello from main.py!")
# module.py
def run_func():
print("Hello from script in sub2.py!")
# script.py
from ..sub2 import module
from .. import main
def entry_point():
module.run_func()
main.func_in_main()
if __name__ == '__main__':
entry_point()
Теперь, что произойдет, если я пытаюсь запустить это напрямую?
$ python test_package/test_dir/sub1/script.py
Traceback (most recent call last):
File "test_package/test_dir/sub1/script.py", line 2, in <module>
from ..sub2 import module
ValueError: Attempted relative import in non-package
Хм ... Облом (это тот случай, когда я пытался описать в комментариях к исходному вопросу). Это происходит независимо от моего текущего рабочего каталога, кстати ... Тем не менее, из любого места на моей файловой системе, я могу запустить это с помощью -m
флага :
$ python -m test_dir.sub1.script
Hello from script in sub2.py!
Hello from main.py!
Horray! Нам нужно только указать путь к модулю, а затем мы золотые (помните, что test_dir
ДОЛЖЕН быть доступным через ваш PYTHONPATH, чтобы это работало). Хорошо, но что, если мы действительно хотим вызвать скрипт вместо использования пути к модулю?Если это так, то мы можем изменить переменную __package__
, прежде чем делать какие-либо импортирование:
# script.py (updated)
if __name__ == '__main__' and __package__ is None:
__package__ = 'test_dir.sub1'
import test_dir # needed to suppress SystemError -- I'm not sure why...
from .. import main
from ..sub2 import module
def entry_point():
module.run_func()
main.func_in_main()
if __name__ == '__main__':
entry_point()
Теперь попробуем запустить эту вещь прямо снова:
$ python test_package/test_dir/sub1/script.py
test_package/test_dir/sub1/script.py:4: RuntimeWarning: Parent module 'test_dir.sub1' not found while handling absolute import
import test_dir
Hello from script in sub2.py!
Hello from main.py!
Мы все еще получить RuntimeWarning
, но это работает Ok. Для получения дополнительной информации см. PEP-0366.
В общем, я запускать большинство из них из-за пределов пакета (один уровень выше test_dir
), но примеры работы, если я запускаю его из внутри пакета, а также. с -m
вы всегда указываете полный путь к модулю (test_dir.sub1.script
), без него вы указываете только относительный или абсолютный путь к файлу)
Какой скрипт вы вызываете? Вы пытаетесь запустить 'sub.py' напрямую (a.la' python dir_one/dir_two/sub.py')? Или вы импортируете 'sub.py' из другого места, и он не работает в этот момент? – mgilson
Я пытаюсь запустить sub.py напрямую – kwotsin
Ahh - В этом проблема. Обычно модули в пакетах не должны запускаться напрямую. Обычно способ структурирования этих вещей состоит в том, что у вас должен быть отдельный каталог (например, 'scripts', который импортирует пакет (и утилит в нем), который предоставляет точку входа в программу. – mgilson