具有相对导入和pytest的Python项目结构

时间:2018-12-13 09:17:24

标签: python pytest

想象一下这个项目结构:

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()

常规存储库要求

  1. mypkg1可以使用mypkg2中的脚本。
  2. mypkg1应该可作为独立程序包运行。
  3. Pytest用于测试。

必需的使用行为

  1. 从myrepo目录运行软件包:python -m mypkg1
  2. 从myrepo目录外部运行软件包:python -m [some path] .myrepo.mypkg1
  3. 从myrepo目录运行独立的软件包脚本:python -m mypkg1.standalone
  4. 从外部myrepo目录运行独立软件包脚本:python -m [some path] .myrepo.mypkg1.standalone

必需的测试行为

  1. 从myrepo目录调用pytest应该从以下位置收集并运行所有测试 测试文件夹
  2. mypkg1_mod1_test.py和mod1_test.py应该可以从其父目录中运行
  3. mypkg1_mod1_test.py和mod1_test.py应该可从任何外部目录运行

结论

  1. 由于需要从myrepo之外的路径运行软件包,因此需要相对导入。
  2. 此行对于查找兄弟姐妹包是必需的 sys.path.append(str((Path(inspect.getfile(inspect.currentframe())) / '../..').resolve()))

最后是我的问题

  1. 在此项目结构中,有什么方法可以使standalone.py作为其程序包中的脚本运行?就像双击脚本文件一样。当我像这样独立运行时,出现此错误: ModuleNotFoundError: No module named '__main__.mod2'; '__main__' is not a package 此错误是由程序包中的相对导入引起的。
  2. 我的项目/包结构约定中是否有任何反样式?
  3. 有什么事情应该纠正或改善吗?

0 个答案:

没有答案