Python 打包课程
Python 的打包生态系统包含众多。 新的 Python 开发人员试图破解它可能会令人生畏,尤其是考虑到 Python 打包的快速发展。 编写 *helloworld.py* 文件并在您的计算机上运行它很简单,但是让它在其他人的计算机上运行(并以“正确”的方式执行此操作)涉及一系列术语、工具和技术。 什么是车轮文件? 什么是 distutils? 我是使用 distutils 还是 easy_install 或 pip?
为了亲自深入了解这一点,我编制了 PyCon 讲座课程、在线文档和我自己的个人笔记,以最终全面掌握 Python 打包。 以下列表是我推荐的顺序:从头开始,一直持续到您需要的满意程度。 我试着把简单/简单/快速的资源放在第一位,其余的逐渐变得更加详细和专业。
我还添加了我自己的摘要和注释,您可能会觉得有用,也可能不会。 如果您对此课程有任何意见,请给我发电子邮件或在 Twitter 上给我发消息(并关注我!)。 (请注意,这篇博文写于 2018 年 10 月。我可能每隔几个月(或几年)更新一次。)
注意:有关 distutils 模块的官方 Python 文档中的信息已过时(请注意,标题中写着“旧版”),以及安装 Python 模块(旧版)文档。 后者被安装 Python 模块取代。
Python 打包课程
- Dustin Ingram – Cheeseshop 内部:Python 打包的工作原理 – PyCon 2018 Dave Forgac 分享您的代码! 轻松打包 Python PyCon 2017 打包 python 库 – Ionel Cristian Mărieş 的博客 测试与打包 – Hynek Schlawack 的博客 Grug 着火了! Grug 造轮子! 作者:Russell Keith-Magee – PyCon Australia 2014 Glyph – 使用 Python 向用户交付软件 – PyCon 2016 Mahmoud Hashemi – BayPiggies 2017 年 9 月在 LinkedIn:打包梯度 Kenneth Reitz – Pipenv:Python 依赖管理的未来 – PyCon 2018
以下也是与包装相关的,但我一直没有时间将它们整理到本课程中:
- Glyph – 使用 Python 向用户运送软件 – PyCon 2016 Elana Hashman – Python Wheels 的黑魔法 – PyCon 2019 Dave Forgac – 从初始化到部署的 Python 打包 – PyOhio 2015 Samuel Roeca – 诗歌:“依赖管理和打包变得简单” – PyGotham 2019 Andrew T Baker 在 2017 PyCon 中部署 Python Web 应用程序的 5 种方法 2017 Katie McLaughlin – 什么是部署? – DjangoCon 2021 Chris Wilcox – 发布您的第一个 Python 包并自动化未来发布 – PyCon 2019 Caitlin Rubin – 有意部署:功能标志管理的最佳实践 – PyCon 2019 Hynek Schlawack – 如何编写部署友好的应用程序 – PyCon 2018 Asheesh Laroia:Python简化包装,面向最终用户、应用程序开发人员 – PyCon 2014 Domen Kožar – 重新思考包装、开发和部署 – PyCon 2015
1 – Dustin Ingram – Cheeseshop 内幕:Python 打包的工作原理 – PyCon 2018
链接到 YouTube 视频。
我对这次演讲的总结:关于 Python 包索引 (PyPI) 的重要历史课,它是以前的版本,以及用于获取包的 distutils/setuptools/easy_install/twine 工具。
- 历史:第一个包索引是一个名为 The Vaults of Parnassus 的网站,这是一个简单的、相当非结构化的、类似 GeoCities 的网站。 然后是 Python 1.6 中的 distutils(“分发实用程序”)给了我们
python setup.py ...
有一种“只使用 Python 代码而不是特定领域的语言或任何花哨的东西”的态度; 非常准系统。python setup.py build
成为标准的、类似于 makefile 的构建包的方式。 为了打包共享的源代码,我们使用了现在熟悉的 python setup.py sdist
(“源分布”)python setup.py bdist
(“构建发行版”)将为您的操作系统/平台打包预构建代码。 问题是,在运行之前 python setup.py bdist
,您如何将 bdist 部分的所有内容放在一起? 这在 Linux 上由包管理器(如 RPM)解决,但在 Windows/macOS/模糊平台上没有解决。 为了解决这个问题,Python Package Index 被制作成适用于所有平台的通用 Python 包管理器。 PyPI 是“Pie-pea-eye”,而不是“Pie-pie”。 “奶酪店”是 PyPI 的旧名称。setuptools
是 distutils 的猴子补丁(坏主意)以安装包依赖项。easy_install
介绍了“鸡蛋分配”。 Egg 文件只是 zip 文件,其中包含一些元数据文件。 (蟒蛇,蛇,产卵。)easy_install
无法卸载东西或告诉您已安装的软件包。pyinstall
就是为了解决这些问题而诞生的。 你可能从来没有听说过这个,因为它很快被重命名为 pip
,代表“PIP 安装包”。 Pip 忽略鸡蛋,只处理源代码分发。 Pip 开始用于安装应用程序,而不仅仅是库模块。 pip引入requirements.txt,里面包含了该包所依赖的依赖包列表(以及包的具体版本): pip install -r requirements.txt
用于安装文件中列出的所有这些依赖项。 Pip 主要依赖于从他们的网站上托管软件包的人进行安装。 这是个问题; 这个随机的人的网站可能很慢,或者可能被黑客入侵,以便在您从它安装时传播恶意软件。 因此 PyPI 开始在自己的网站上托管模块。 构建分发解决了源代码分发的问题,但 Egg 格式定义不明确,因此 Wheel 文件成为新的 Egg 文件:一种分发构建模块的方式。 Wheel 文件(以 cheese wheels 命名,参考了 cheese shop)也像 Egg 文件,因为它们只是 zip 文件,但它们从 easy_install 和 Egg 文件的错误中吸取了教训,定义更明确(参见 PEP 427)。 Twine 的出现就是为了解决这个问题 python setup.py upload
不使用 HTTPS。 这个名字来自使用麻线捆绑盒子和包裹。 这个名字真的没有多大意义。 Twine 不捆绑东西,只是使用加密的 HTTPS 上传已经捆绑的包。 PyPI 已经过时了,因此它被从头开始重写。 这是“仓库”项目,于 2011 年启动,并于 2018 年成为新的 PyPI。耶! 目前存在的问题:包装还是有点硬。 有大量的工具和历史。 阅读 https://packaging.python.org 上的 Python 打包指南和 https://github.com/pypa/sampleproject 上的示例项目(一个遵循最佳实践的不错的骨架项目)。 目前存在的问题: 包装有点太容易了; 拼写错误和垃圾邮件 PyPI。 解决方案:conda,一种与 Python 无关的打包工具。 当前问题:可重现的环境。 解决方案:来自 https://github.com/pypa/pipfile 的 pipfile 和 pipfile.lock 当前问题:setup.py 执行任意代码,这是一个安全/标准/维护问题。 当前问题:“distutils/setuptools”舞蹈; 这些是旧的/难以维护的标准库模块。 更新它们很难做到。 PEP 517 和 PEP 518 详细解决方案,这是 pyproject.toml 文件的来源。这些文件以不可知的方式指定依赖项等:distutils 和 setuptools 可以使用 pyproject.toml 文件来安装依赖项,或者其他一些工具可以使用它们。
2 – Dave Forgac 分享您的代码! 没有复杂的 Python 打包 PyCon 2017
链接到 YouTube 视频。
我对本次演讲的总结:该视频详细介绍了 setup.py 文件,但除此之外,它还很好地列出了您应该了解的内容并了解更多信息。 它还涉及您需要为一个包收集的相关内容(文档、测试、持续集成等)。 本次演讲的幻灯片可在 daveops.com/pycon2017 获取
- 您需要与其他人共享您的代码的东西:
- 打包代码文档源托管(GitHub等)测试持续集成(CI)许可证贡献指南
这是很多东西,但您可以使用 cookiecutter 为您制作所有这些东西。 术语:
- 模块(保存在文件中的 Python 代码) 导入包(存储 Python 模块的文件夹) 分发包(将您的代码捆绑到可共享/可安装文件中的文件) 源代码分发(与其他人共享的源代码,包括C 扩展的 C 源代码,这些是在下载/安装包时构建/编译的) Built Distribution(eggs 和 wheel 文件,wheel 是现代的当前版本,这些是预编译的,因此只需要在下载时解压/安装)
车轮文件的类型:
- Universal wheels(仅包含适用于 Python 2 和 3 的 Python 代码,并且可以安装在任何地方。) Pure Python wheels(仅包含 Python 代码,但仅适用于 Python 2 或 Python 3。) Platform wheels(包含编译代码的文件目标平台/操作系统)
历史(这在 Dustin Ingram 的演讲中有更多介绍)。 PyPA(Python 包装管理局)开始为 Python 生态系统中的包装创建标准。 PyPUG 是 Python Packaging User Guide,位于 https://packaging.python.org/ setup.py 只是一个 Python 文件,但不要做任何巧妙的事情或向其中添加自定义逻辑。 setup.cfg 包含 wheel 设置和各种其他设置 MANIFEST.in 将列出任何需要打包的非 Python 文件(数据文件、配置文件、文档等)。 README.rst 是将用于包的 PyPI 页面的重组文本文件(注意,不是 Markdown)。 PEP 440 涵盖了用于版本字符串的格式。 setup.py 是一个基本上只是调用的文件 setuptools.setup()
. (在 setup.py 的 setuptools.setup() 函数调用中有很多关于各种关键字参数的详细信息。)使用 piptools 管理 requirements.txt 文件。 不要使用 setup.py 自己的上传功能,而是使用 twine。 开发模式(对源代码所做的任何文件更改都不必使用 pip 重新安装): pip install -e .
3 – 打包 python 库 – Ionel Cristian Mărieş 的博客
链接到博客文章。
我对这篇博文的总结:这是关于打包库供其他 Python 软件开发人员在他们的应用程序中使用,而不是打包应用程序。 这是一个很好的列表,说明如何布局库的所有不同部分。
- 将您的 Python 模块放在 /src/packagename 中,而不是 /packagename 中。 这为您提供了“导入奇偶校验”:它强制您像用户必须安装的那样安装软件包。 否则,如果您从存储库的根目录运行 Python,
import packagename
会 import /src/packagename 就好了,但这意味着您不必像用户那样经历安装过程,并且您可能会错过他们面临的潜在错误。 不要从 setup.py 文件中导入你的包,即你的 setup.py 不应该有 import packagename
在里面。 你不想这样做,因为如果你的包导入了其他依赖项,这些依赖项可能还没有安装,这会导致分发安装错误。 拥有一个 /src 文件夹让您只需添加 graft src
到您的 MANIFEST.in 文件,这很简单。 “扁平比嵌套好”但不是数据。 不要将测试文件夹放在 src 或 packagename 文件夹中。 每当 setup.py 文件打开文件时,它都会指定一种编码。 请注意,为了与 python 2/3 兼容,它使用 io.open()
代替 open()
因为 Python 2 的 open()
没有 encoding
关键字参数。 不要使用 python setup.py test
运行你的测试; 那已经过时了。 Travis-CI 已成为签入代码后运行测试的标准。 Tox 是在本地运行测试的好方法。 Ionel 在这里有一个示例项目布局:https://github.com/ionelmc/python-nameless 使用 cookiecutter
生成这些文件(tox.ini、MANIFEST.in 等)
4 – 测试和包装 – Hynek Schlawack 的博客
链接到博客文章。
我对这篇博文的总结:这篇博文假设您已经熟悉 tox 和 coverage.py。 它的示例并没有真正牵动您的手。 尽管它确实向我介绍了 detox,它是 tox 的直接替代品(而不是附加品),可让您并行运行不同的 tox 环境测试。
将您的模块放在单独的 src 文件夹中。 这简化了您在 setup.py 中需要的内容:
setup( ... packages=find_packages(where="src"), package_dir={'': 'src'}, )
“组合覆盖率”意味着不仅仅是用一个版本的 Python 测量你的代码覆盖率,而是在你用 tox 测试的所有版本中。 如果您在 Python 3 中有 100% 的覆盖率,但在 Python 2 中覆盖率较低,那么这会影响您的整体……