Представьте себе структуру этого проекта:
myproject
|-- mypkg1
| |-- __init__.py
| |-- __main__.py
| |-- mod1.py
| |-- mod2.py
| |-- standalone.py
|
|-- mypkg2
| |-- __init__.py
| |-- mod1.py
| |-- mod2.py
|
|-- tests
| |-- mypkg1
| | | --mod1_test.py
| |-- mypkg1_mod1_test.py
|
|-- mypkg1_run.py
|-- standalone_run.py
|-- conftest.py
|-- README
С этим содержимым файлов:
mypkg1 .__ init __. Py
import sys
import inspect
from pathlib import Path
sys.path.append(str((Path(inspect.getfile(inspect.currentframe())) / '../..').resolve()))
mypkg1 .__ main __. Py
from .mod1 import mod1_msg
from .mod2 import mod2_msg
from mypkg2 import mod1, mod2
def main():
print("Hello from mypkg1 main!")
print(mod1_msg())
print(mod2_msg())
print(mod1.mod1_msg())
print(mod2.mod2_msg())
if __name__ == '__main__':
main()
mypkg1.mod1.py
def mod1_msg():
return "Hello from mypkg1.mod1!"
mypkg1.mod2.py
from .mod1 import mod1_msg
def mod2_msg():
return "Hello from mypkg1.mod2 and {}".format(mod1_msg())
mypkg1.standalone.py
from .mod2 import mod2_msg
def main():
print("Hello from mypkg1.standalone!")
print(mod2_msg())
if __name__ == '__main__':
main()
mypkg2 .__ init __. Py
import sys
import inspect
from pathlib import Path
sys.path.append(str((Path(inspect.getfile(inspect.currentframe())) / '../..').resolve()))
mypkg2.mod1.py
def mod1_msg():
return "Hello from mypkg2.mod1!"
mypkg2.mod2.py
from .mod1 import mod1_msg
def mod2_msg():
return "Hello from mypkg2.mod2 and {}".format(mod1_msg())
tests.mypkg1.mod1_test.py и tests.mypkg1_mod1_test.py
from mypkg1.mod1 import mod1_msg
def test_mod1():
assert mod1_msg() == "Hello from mypkg1.mod1!"
mypkg1_run.py
from mypkg1.__main__ import main
if __name__ == '__main__':
main()
standalone_run.py
from mypkg1.standalone import main
if __name__ == '__main__':
main()
Общие требования к репозиторию
- mypkg1 может использовать скрипты из mypkg2.
- Mypkg1 должен запускаться как автономный пакет.
- Для тестирования используется Pytest.
Требуемое поведение при использовании
- Запустите пакет из директора myrepoy: python -m mypkg1
- Запустить пакет вне каталога myrepo: python -m [некоторый путь] .myrepo.mypkg1
- Запустить скрипт автономного пакета из каталога myrepo: python -m mypkg1.standalone
- Запустите скрипт автономного пакета из внешнего каталога myrepo: python -m [некоторый путь] .myrepo.mypkg1.standalone
Обязательное поведение при тестировании
- Вызов pytest из каталога myrepo должен собирать и запускать все тесты из папки тестов
- mypkg1_mod1_test.py и mod1_test.py должны запускаться из родительского каталога
- mypkg1_mod1_test.py и mod1_test.py должны запускаться из любых внешних каталогов
Выводы
- Относительный импорт необходим из-затребуется запуск пакета из пути, находящегося за пределами myrepo.
- Эта строка необходима для поиска пакетов одного уровня
sys.path.append(str((Path(inspect.getfile(inspect.currentframe())) / '../..').resolve()))
И, наконец, мои Вопросы
- Можно ли как-нибудь запустить standalone.py как скрипт из его пакета в этой структуре проекта?Как двойной щелчок по файлу скрипта.Когда я запускаю автономно, как это, я получаю эту ошибку:
ModuleNotFoundError: No module named '__main__.mod2'; '__main__' is not a package
Эта ошибка вызвана относительным импортом внутри пакета. - Есть ли какой-либо антипаттерн в моем соглашении о структуре проекта / пакета?
- Есть ликакие-либо вещи, которые должны быть исправлены или улучшены?