Резюме
У меня следующая структура каталогов. Моя цель - сделать module1 импортируемым (в данном случае из test_module1.py), а также иметь возможность вызывать module1.py напрямую, когда я нахожусь в каталоге module1. Я чувствую, что или есть хорошее решение этой проблемы, или что-то не так с тем, как я структурирую приложение, поэтому предлагаемые решения или изменения в структуре приложения могут решить эту проблему
Детали
Структура каталогов
.
├── module1
│ ├── __init__.py
│ ├── module1.py
│ ├── module2
│ │ ├── __init__.py
│ │ └── module2.py
└── tests
└── test_module1.py
Мои файлы заполняются следующим образом
test_module1.py
from module1.module1 import Module1
def test_fake():
pass
module1.py
from module2.module2 import Module2
class Module1:
pass #or regular __init__, etc
module2.py
class Module2:
pass #or regular __init__, etc
Так что я бы хотел иметь возможность
1) запустить module1 из каталога module1
cd module1
python module1.py
2) запустить тесты из основного каталога, используя
pytest
В вышеприведенном случае # 1 работает, но # 2 не работает с
from module1.module1 import Module1
E ModuleNotFoundError: No module named 'module1'
Это связано с проверкой pytest в тестовой директории только для модулей. Это решается запуском python -m pytest
, что позволяет искать в каталоге .
Тем не менее, все еще есть ошибка, и это то, что я не могу понять.
Traceback:
tests/test_module1.py:1: in <module>
from module1.module1 import Module1
module1/module1.py:1: in <module>
from module2.module2 import Module2
E ModuleNotFoundError: No module named 'module2.Module2'
Проверенные решения
Тест находит модуль 1, но при импорте модуля 1 ему нужно найти модуль 2. Он ищет это в каталоге .
, но не в ./module1
. Эту проблему можно решить, изменив импорт в module1.py с from module2.module2 import Module2
на from .module2.module2 import Module2
(обратите внимание на добавленный .
в начале). Это относительный импорт, абсолютный импорт также решает проблему. Оба решения заставляют python -m pytest
проходить, так что # 2 работает. Тем не менее, оба также нарушают функциональность # 1, где я хотел иметь возможность запускать module1 непосредственно из модуля. Пройдя немного дальше, я попытался запустить module1.py из .
, это выдает ошибку: No module named '__main__.module2'; '__main__' is not a package
. Я смог наконец заставить его работать, используя python -m module1.module1
, но это кажется супер каруселью. Подробнее об этих решениях ниже
ModuleNotFoundError: Что значит __main__ не является пакетом?
Как сделать относительный импорт в Python?
По сути, я обнаружил, что абсолютный и относительный импорт теперь вынуждают вызывать module1 из корневого каталога с помощью -m. Мне кажется, это указывает на большую проблему, заключающуюся в том, что при использовании вложенных модулей в Python модуль более низкого уровня никогда не сможет использоваться сам по себе. Скажем, module2 содержит два файла, и один нужно импортировать другой. Он также будет вынужден использовать относительный или абсолютный импорт, и теперь module2 должен запускаться из module1 с использованием -m, что затрудняет создание одного из этих сценариев.
Я чувствую, что, возможно, я тоже что-то делаю в файлах __init__.py
и нашел предложение сделать относительный импорт в __init__.py
в документации по Python https://docs.python.org/3/reference/import.html#submodules, но у меня это не сработало .
Некоторая справка (необязательно читать) : Причины, по которым я хочу это:
1), который я разрабатываю в возвышенном тексте, чтобы я мог просто создать файл непосредственно при кодировании
2) Я потратил много времени на поиск хорошего способа структурирования приложения на Python с точки зрения модулей и тестов, и это то, что я придумал. Если я что-то делаю неправильно, пожалуйста, дайте мне знать, но если это хорошая структура, то возможность запуска кода непосредственно в модуле, а также возможность импорта модуля (из тестового сценария или в другом месте) кажутся довольно простой функциональностью, которая должно быть достижимо.