想象一下这个项目结构:
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()
独立运行.py
from mypkg1.standalone import main
if __name__ == '__main__':
main()
一般存储库要求
- mypkg1 可以使用来自 mypkg2 的脚本。
- mypkg1 应该可以作为独立包运行。
- Pytest 用于测试。
必需的使用行为
- 从 myrepo 目录运行包: python -m mypkg1
- 从 myrepo 目录外部运行包: python -m [some path].myrepo.mypkg1
- 从 myrepo 目录运行独立包脚本: python -m mypkg1.standalone
- 从外部 myrepo 目录运行独立包脚本: python -m [some path].myrepo.mypkg1.standalone
所需的测试行为
- 从 myrepo 目录调用 pytest 应该收集并运行测试文件夹中的所有测试
- 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此错误是由包中的相对导入引起的。 - 我的项目/包结构约定中是否有任何反模式?
- 有什么需要纠正或改进的地方吗?