Python — Импорт из исходного корня приводит к «отсутствию модуля с именем «»»

#python #import #importerror #directory-structure #modulenotfounderror

#python #импорт #ошибка импорта #структура каталогов #modulenotfounderror

Вопрос:

Исследуя, как я должен структурировать свои проекты и тесты, я клонировал в репозиторий nose и обнаружил ту же проблему, что и у меня.

Вот как структурирован проект:

 nose <----- repository root
    nose <- source root
        __main__.py
        __init__.py
        core.py
        [...]
    unit_tests
    .gitignore
    [...]
 

Если я запускаю

 python nose/__main__.py
 

Я получаю

 File "/home/daniel/Projects/nose/nose/__main__.py", line 3, in <module>
    from nose.core import run_exit
ModuleNotFoundError: No module named 'nose'
 

Я понимаю, что, вероятно, есть исправление, связанное PYTHONPATH с Python, но, будучи довольно новичком в Python, я чувствую, что должен быть способ, чтобы проект работал «из коробки» без необходимости возиться с какими-либо системными переменными.

Для контекста все это расследование началось с того, что я обнаружил, что мои тесты завершились неудачей, потому что импорт в моем нетестовом коде завершится неудачей (структура моего проекта такая же, как у Nose). Например:

 from package import module
from package.subpackage import module
 

Приведет к следующей ошибке при выполнении тестов:

 ModuleNotFoundError: No module named 'package'
 

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

 from project.package import module
from project.package.subpackage import module
 

Но тогда я столкнулся с вышеупомянутой ошибкой при попытке запустить программу в обычном режиме.

 ModuleNotFoundError: No module named 'project'
 

Комментарии:

1. Корневой каталог при выполнении ваших тестов и при запуске вашего приложения должен отличаться. Можете ли вы распечатать первый элемент sys.path при запуске ваших тестов и при запуске вашего приложения, чтобы увидеть, есть ли разница?

2. @SpaceBurger вы правы, при запуске моих тестов путь — это корень тестов (project / test), а при запуске моего приложения путь — это корень моих источников (project / project)

3. Тогда самым прямым решением было бы добавить каталог вашего источника перед sys.path (с помощью простого sys.path.insert(abs_path_to_sources_root)) . Таким образом, вам не нужно изменять импорт в своих источниках или тестах. Однако это должно быть запущено до начала любых тестов; возможно, в вашем тестовом модуле есть опция, которая может делать это автоматически, и вам даже не нужно писать код. Другим решением было бы поместить ваши тесты вместе с вашим кодом, но я не знаю, рекомендуется ли это. Зависит от того, какой у вас модуль тестирования.