English|Python打包状态[1]原创作品|译者BERNATGABOR|请勿用于商业或非法目的。pip19.0于2019年1月22日发布。其功能列表中最值得注意的是它现在支持PEP-517,默认情况下,如果项目根目录中有pyproject.toml。该PEP于2015年创建,并于2017年接受。虽然pip实施它花了一段时间,但这次发布及其后续问题表明很多人根本不熟悉它。如果您想了解Python打包生态系统的现状以及未来可能如何发展,请继续阅读。我们希望,尽管前面提到的PythonEnhancementProposal(译注:即PEP,关于PEP的介绍,请阅读本文),今天可能会引起一些不愉快,但从长远来看,对我们是有益的。我大约三年前加入了Python开源社区(虽然已经使用它8年了)。从早期开始,我就听说Python打包有一点黑盒的名声。它有很多未知的内容,人们通常只是复制其他项目的构建配置文件并使用它。为了更好地理解这个黑盒并对其进行改进,我成为了virtualenv和tox项目的维护者,偶尔也会为setuptools和pip做出贡献。我希望对这个主题有详尽的(并希望是高水平的)论文,并决定将其分为三个部分。在第一篇文章中,我将概述Python打包的工作原理及其打包类型。在第二篇文章中,我将更详细地介绍包是如何安装的,以及PEP-517/518如何尝试改进它。最后,我将用另一篇文章介绍我们在介绍这些改进时所吸取的一些惨痛教训。作为免责声明,我将主要关注官方Python打包系统(即pip、setuptools,因此没有conda或特定于操作系统的打包程序)。摄影:MarcusCramer/Unsplash-人们第一次注视Python打包时的表情更具体地说,包安装过去是如何工作的,以及我们希望它在未来如何工作。为了有一个具体的例子,让我介绍一下我很棒的示例库:pugs。这个库相当简单:它只生成一个名为pugs的包,其中只包含一个名为logic的模块。关于哈巴狗,你猜对了,逻辑是用来生成随机报价的。这是一个简单的示例结构,作为源代码树(在gaborbernat/pugs[2]中可用):pugs-project├──README.rst├──setup.cfg├──setup.py├──LICENSE.txt├──src│└──哈巴狗│├──__init__.py│└──logic.py├──tests│├──test_init.py│└──test_logic.py├──tox.ini└──azure-pipelines.yml这里有四种独特的内容:我们的pugs包可以在用户机器的解释器上使用,什么意思?理想情况下,一旦解释器启动,用户应该能够导入它,并调用其中的函数:业务逻辑代码(src文件夹中的内容)测试代码(tests文件夹和tox.ini)包代码和元数据(setup.py,setup.cfg,LICENSE.txt,README.rst——注意我们今天使用的是事实上的标准打包工具setuptools[3])帮助项目管理和维护的文件:持续集成(azure-pipelines.yml)版本控制(.git)项目管理(例如潜在的.github文件夹)Python3.7.2(v3.7.2:9a3ffc0492,Dec242018,02:44:43)[Clang6.0(clang-600.0.57)]ondarwinType"help”、“版权”、“出处”或“许可”以获取更多信息。>>>importpugs>>>pugs.do_tell()“一只开明的哈巴狗知道如何充分利用他必须与之共事的一切——哈巴狗的约会指南——摄影:GemmaCorrell”RyanAntooa/Unsplash——让我们开始吧,兴奋的!Python包的可用性Python如何知道什么可用,什么不可用?简答情况是,它不知道,至少不知道。相反,它将尝试加载并动态检查它是否可用。它从哪里加载?有许多可能的位置,但在大多数情况下,我们谈论的是从文件系统上的文件夹加载。这个文件夹在哪里?对于给定的模块,您可以通过打印模块的表示来查找:>>>importpugs>>>pugs您将找到文件夹的位置取决于:包的类型(三重库或标准库的内置/aka部分)它是全局的还是仅限于当前用户(参见PEP-370[4])以及它是系统Python还是虚拟环境但一般来说,对于给定的Python解释器,可以通过打印出sys.path变量的内容来找到可能目录的列表,例如在我在MacOS上:>>>importsys>>>print('\n'.join(sys.path))/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/Users/bernat/Library/Python/3.7/lib/python/site-packages/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages对于第三方包,会有一些site-packages文件夹。在上面的示例中,请注意哪些是系统范围的,哪些仅属于一个特定用户。这些包是如何放在这个文件夹中的?它一定是由某些安装程序放在那里的。下图显示了大部分情况:开发人员在文件夹(称为源代码树)中编写了一些Python代码。然后,一些工具(例如setuptools)打包源代码树以供重新分发。生成的包通过另一个工具(twine)上传到中央存储库(通常是https://pypi.org[5]),最终用户计算机可以访问该存储库。最终用户计算机使用安装程序来查找、下载和安装相关软件包。安装操作在site-packages文件夹内结束,创建正确的目录结构和元数据。Pinho/Photo--探索新事物时Python包的类型在安装时,包必须生成至少两种类型的内容以放入站点包:一个关于包内容的元数据文件夹,包含{package}-{version}.dist-info和业务逻辑文件。/Users/bgabor8/Library/Python/3.7/lib/python/site-packages/pugs├──__init__.py├──__pycache__│├──__init__.cpython-37.pyc│└──logic.cpython-37.pyc└──logic.py/Users/bgabor8/Library/Python/3.7/lib/python/site-packages/pugs-0.0.1.dist-info├──安装程序├──LICENSE.txt├──METADATA├──RECORD├──WHEEL├──top_level.txt└──zip-safe分发信息(dist-info)文件夹描述包:用于安装包的安装程序,安装过程中创建了哪些文件进程,顶级Python包是什么,该包公开了哪些条目,等等。每个文件的详细描述可以在PEP-427[6]中找到。我们如何从源码树中获取这两类内容呢?我们面前有两条截然不同的路径:从我们的源代码树生成目录结构和元数据,将其压缩到一个文件中,然后将其发布到中央包存储库。在这种情况下,安装程序必须下载包并将其解压缩到site-packages文件夹中。我们将这种类型的包称为轮包。或者,您可以创建一个包含包源的存档,构建所需的脚本和元数据以生成可安装的目录结构,并将其上传到中央存储库。这称为源分发或sdist。在这种情况下,安装程序有很多工作要做,它需要解压缩归档文件,运行构建器,然后将其复制过来。这两种方法之间的区别主要在于包的编译/构建操作发生的位置:在开发人员的计算机上还是在最终用户的计算机上。如果它发生在开发者这边(比如轮子的情况),安装过程是非常轻量级的。一切都在开发机器上完成了。用户本机操作只是简单的下载解压。在此示例中,我们使用setuptools作为构建器(从源代码树生成内容以放入site-packages文件夹)。因此,为了在用户机器上执行构建操作,我们需要确保用户在用户机器上有合适版本的setuptools(如果你使用的是40.6.0特性,你必须确保用户有那个版本或更大)。另一种需要考虑的情况是,Python提供了从自身内部访问C/C++库的能力(在需要时提供额外的性能)。此类包称为C扩展包,因为它们利用了CPython提供的C扩展API。此类扩展需要为与之交互的C/C++库和当前Python解释器的C-API库编译C/C++功能。在这些情况下,构建操作实际上涉及调用二进制编译器,而不是仅仅生成元数据和文件夹结构,就像我们的pugs库那样的纯Python包。如果在用户的计算机上构建,您需要确保在构建时可以使用正确的库和编译器。现在这是一个比较困难的工作,因为一些特定于平台的二进制文件也是通过平台打包工具分发的。这些库的缺失或版本不匹配通常会在构建时触发神秘错误,让用户感到沮丧和困惑。因此,如果可能,总是选择将包打包成一个轮子。这将完全避免用户缺少正确的构建依赖项(纯Python类型,如setuptools或二进制类型的C/C++编译器)的问题。即使这些构建依赖项很容易配置(例如,使用纯Python构建器——例如setuptools),您也可以完全避免此步骤,从而节省安装时间。话虽如此,但仍有两种情况需要提供源码分发(即使你提供了轮子):关于其内容透明度的知识:许多大型企业环境更喜欢wheels的唯一原因(他们经常将其扩展到纯Pythonwheels,主要是为了避免对纯Python和非纯Python进行分类)。您可能无法为每个可能的平台提供轮子(尤其是在使用C扩展包的情况下),在这种情况下,源代码分发允许这些平台生成自己的轮子。sourcetree、sourcedistribution和wheel的区别总结:Sourcetree——包含所有项目文件(业务逻辑、测试、打包数据、CI文件、IDE文件、SVC等),参见上面的exampleproject,例如。源码分发——包含造轮子所需要的代码文件(业务逻辑+打包数据+通常包含单元测试文件来验证构建;但不包含开发环境的内容,如CI/IDE/版本控制文件),格式:pugs-0.0.1.tar.gz。wheel——包含包的元数据和源代码文件,放在站点包文件夹中,格式:pugs-0.0.1-py2.py3-NONE-any.whl。照片由CharlesPH/Unsplash--hmmm阅读本系列的下一篇文章[7],了解安装包时会发生什么。谢谢阅读!相关链接[1]Python打包状态:https://www.bernat.tech/pep-5...[2]gaborbernat/哈巴狗:https://github.com/gaborberna...[3]设置工具:https://pypi.org/project/setu...[4]PEP-370:https://www.python.org/dev/pe...[5]https://pypi.org:https://pypi.org/[6]PEP-427:https://www.python.org/dev/pe...[7]下一篇:https://www.bernat.tech/pep-5...公众号【Python猫】,本号连载一系列优质文章,包括喵星哲学猫系列、Python进阶系列、好文书籍推荐系列、技术写作、优质英文推荐及翻译等,欢迎关注哦。