Wol*_*ger 17 python packaging pypi
我正在学习如何根据教程(https://packaging.python.org/en/latest/tutorials/packaging-projects/)为 PyPI 打包 Python 项目。对于示例项目,他们使用文件夹结构:
\npackaging_tutorial/\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 LICENSE\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 pyproject.toml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src/\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 example_package_YOUR_USERNAME_HERE/\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 example.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 tests/\nRun Code Online (Sandbox Code Playgroud)\n我只是想知道为什么src/需要该文件夹?它有特定的目的吗?可以直接将包包含在顶部文件夹中吗?例如会
packaging_tutorial/\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 LICENSE\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 pyproject.toml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 example_package_YOUR_USERNAME_HERE/\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 example.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 tests/\nRun Code Online (Sandbox Code Playgroud)\n有什么缺点或引起并发症吗?
\na_g*_*est 14
有一篇关于这个主题的有趣的博客文章;基本上,使用src可以防止在项目目录中运行测试时,导入包源文件夹而不是已安装的包(并且测试应始终针对已安装的包运行,以便情况与用户相同)。
考虑以下示例项目,其中正在开发的包的名称是mypkg。它包含一个__init__.py文件和另一个DATA.txt非代码资源:
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 mypkg\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 DATA.txt\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 pyproject.toml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 setup.cfg\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test\n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test_data.py\nRun Code Online (Sandbox Code Playgroud)\n在这里,mypkg/__init__.py访问DATA.txt资源并加载其内容:
from importlib.resources import read_text\n \ndata = read_text(\'mypkg\', \'DATA.txt\').strip() # The content is \'foo\'.\nRun Code Online (Sandbox Code Playgroud)\n该脚本test/test_data.py检查mypkg.data实际包含\'foo\':
import mypkg\n \ndef test():\n assert mypkg.data == \'foo\'\nRun Code Online (Sandbox Code Playgroud)\n现在,coverage run -m pytest从基本目录中运行给人的印象是该项目一切正常:
$ coverage run -m pytest\n[...]\ntest/test_data.py . [100%]\n\n========================== 1 passed in 0.01s ==========================\nRun Code Online (Sandbox Code Playgroud)\n然而,有一个微妙的问题。运行coverage run -m pytest调用pytestvia python -m pytest,即使用-m开关。正如文档中提到的,这有一个“副作用”:
\n\n[...] 与该
\n-c选项一样,当前目录将添加到sys.path. [...]
这意味着在导入时mypkg,test/test_data.py它不会导入已安装的版本,而是从源树导入包mypkg。
现在,我们进一步假设我们忘记DATA.txt在项目规范中包含该资源(毕竟,没有MANIFEST.in)。所以这个文件实际上不包含在安装版本中mypkg(例如通过安装python -m pip install .)。这是通过pytest直接运行来揭示的:
$ pytest\n[...]\n======================= short test summary info =======================\nERROR test/test_data.py - FileNotFoundError: [Errno 2] No such file ...\n!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!\n========================== 1 error in 0.13s ===========================\nRun Code Online (Sandbox Code Playgroud)\n因此,coverage尽管安装被破坏,但使用时测试还是通过了mypkg。该测试没有捕获这一点,因为它是针对源树而不是安装的版本运行的。如果我们使用src目录来包含mypkg包,那么通过添加当前工作目录-m不会引起任何问题,因为mypkg当前工作目录中不再有包。
但最终,使用src不是一个要求,而是更多的约定/最佳实践。例如,请求不使用src,但它们仍然设法成为一个流行且成功的项目。