打包Python项目

本教程将指导您如何打包一个简单的Python项目。它将向您展示如何添加必要的文件和结构来创建包,如何构建包以及如何将其上载到Python包索引。

一个简单的项目

本教程使用一个名为的简单项目example_pkg。如果您不熟悉Python的模块和导入包,请花几分钟时间阅读包含文件包和模块Python文档

要在本地创建此项目,请创建以下文件结构:

1
2
3
/example_pkg
/example_pkg
__init__.py

创建此结构后,您将需要在顶级文件夹中运行本教程中的所有命令 - 所以一定要确保。cd example_pkg

您还应该编辑example_pkg/__init__.py并在其中放入以下代码:

1
name = "example_pkg"

这只是为了您可以在本教程后面验证它是否正确安装。

创建包文件

现在,您将创建一些文件来打包此项目并准备分发。创建下面列出的新文件 - 您将在以下步骤中向其添加内容。

1
2
3
4
5
6
/example_pkg
/example_pkg
__init__.py
setup.py
LICENSE
README.md

创建的setup.py

setup.pysetuptools的构建脚本。它告诉setuptools你的包(例如名称和版本)以及要包含的代码文件。

打开setup.py并输入以下内容,您可以根据需要个性化值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import setuptools

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="example_pkg",
version="0.0.1",
author="Example Author",
author_email="author@example.com",
description="A small example package",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/pypa/sampleproject",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
)

setup()有几个论点。此示例包使用相对最小的集:

  • name是您的包的名称。只要包含字母,数字_和,就可以是任何名称-。它也不能在pypi.org上使用。
  • version 是包版本看 PEP 440有关版本的更多详细信息。
  • authorauthor_email用于识别包的作者。
  • description 是一个简短的,一句话的包的总结。
  • long_description是包的详细说明。这显示在Python Package Index的包详细信息包中。在这种情况下,加载长描述README.md是一种常见模式。
  • long_description_content_type告诉索引什么类型的标记用于长描述。在这种情况下,它是Markdown。
  • url是项目主页的URL。对于许多项目,这只是一个指向GitHub,GitLab,Bitbucket或类似代码托管服务的链接。
  • packages是应包含在分发包中的所有Python 导入包的列表。我们可以使用 自动发现所有包和子包,而不是手动列出每个包。在这种情况下,包列表将是example_pkg,因为它是唯一存在的包。find_packages()
  • classifiers告诉索引并一些关于你的包的其他元数据。在这种情况下,该软件包仅与Python 3兼容,根据MIT许可证进行许可,并且与操作系统无关。您应始终至少包含您的软件包所使用的Python版本,软件包可用的许可证以及您的软件包将使用的操作系统。有关分类器的完整列表,请参阅https://pypi.org/classifiers/

除了这里提到的还有很多。有关详细信息,请参阅 打包和分发项目

创建README.md

打开README.md并输入以下内容。如果您愿意,可以自定义此项。

1
2
3
4
5
# Example Package

This is a simple example package. You can use
[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

创建许可证

上传到Python Package Index的每个包都包含许可证,这一点很重要。这告诉用户安装您的软件包可以使用您的软件包的条款。有关选择许可证的帮助,请参阅 https://choosealicense.com/。选择许可证后,打开 LICENSE并输入许可证文本。例如,如果您选择了MIT许可证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Copyright (c) 2018 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

生成分发档案

下一步是为成分发包。这些是上传到包索引的档案,可以通过pip安装。

确保您拥有setuptoolswheel 安装了最新版本:

1
python3 -m pip install --user --upgrade setuptools wheel

小费

如果您在安装这些软件时遇到问题,请参阅 安装软件包教程

现在从setup.py位于的同一目录运行此命令:

1
python3 setup.py sdist bdist_wheel

此命令应输出大量文本,一旦完成,应在dist目录中生成两个文件:

1
2
3
dist/
example_pkg-0.0.1-py3-none-any.whl
example_pkg-0.0.1.tar.gz

注意

如果您遇到麻烦,请复制输出并提出有关包装问题的问题,我们会尽力为您提供帮助!

tar.gz文件是源存档,而该.whl文件是 构建的分发。较新的pip版本优先安装构建的发行版,但如果需要,将回退到源代码存档。您应该始终上传源存档并为项目兼容的平台提供构建的存档。在这种情况下,我们的示例包在任何平台上都与Python兼容,因此只需要一个构建的发行版。

上传分发档案

最后,是时候将您的包上传到Python Package Index了!

您需要做的第一件事是在Test PyPI上注册一个帐户。Test PyPI是用于测试和实验的包索引的单独实例。这对于像我们不一定想要上传到真实索引的本教程那样很棒。要注册帐户,请访问https://test.pypi.org/account/register/并完成该页面上的步骤。在您上传任何软件包之前,您还需要验证您的电子邮件地址。有关Test PyPI的更多详细信息,请参阅 使用TestPyPI

现在您已注册,您可以使用twine上传分发包。你需要安装Twine:

1
python3 -m pip install --user --upgrade twine

安装完成后,运行Twine上传所有存档dist

1
twine upload --repository-url https://test.pypi.org/legacy/ dist/*

系统将提示您输入使用Test PyPI注册的用户名和密码。命令完成后,您应该看到与此类似的输出:

1
2
3
4
5
6
7
Uploading distributions to https://test.pypi.org/legacy/
Enter your username: [your username]
Enter your password:
Uploading example_pkg-0.0.1-py3-none-any.whl
100%|█████████████████████| 4.65k/4.65k [00:01<00:00, 2.88kB/s]
Uploading example_pkg-0.0.1.tar.gz
100%|█████████████████████| 4.25k/4.25k [00:01<00:00, 3.05kB/s]

注意

如果您收到错误消息,则需要为您的包选择一个唯一的名称。一个不错的选择 。更新参数 ,删除文件夹,然后 重新生成存档The user '[your username]' isn't allowed to upload to project'example-pkg'`example_pkg_your_usernamenamesetup.pydist`

上传后,您的包应该可以在TestPyPI上查看,例如,https: //test.pypi.org/project/example-pkg

安装新上传的软件包

您可以使用pip来安装包并验证它是否有效。创建一个新的virtualenv(请参阅安装包以获取详细说明)并从TestPyPI安装包:

1
python3 -m pip install --index-url https://test.pypi.org/simple/ example_pkg

注意

如果在预览步骤中使用了不同的包名称,请example_pkg在上面的命令中使用您的包名称替换 。

pip应该从Test PyPI安装包,输出应该如下所示:

1
2
3
4
Collecting example_pkg
Downloading https://test-files.pythonhosted.org/packages/.../example_pkg-0.0.1-py3-none-any.whl
Installing collected packages: example-pkg
Successfully installed example-pkg-0.0.1

您可以通过导入模块并引用先前name放置的属性来测试它是否已正确安装__init__.py

运行Python解释器(确保你仍然在你的virtualenv中):

1
python

然后导入模块并打印出name属性。无论您给出的分发包名称是什么,这都应该是相同的 ,setup.py因为您的导入包example_pkg

>>>

1
2
3
>>> import example_pkg
>>> example_pkg.name
'example_pkg'

后续步骤

恭喜,您已经打包并分发了一个Python项目! ✨🍰✨

请记住,本教程向您展示了如何将软件包上传到Test PyPI,而测试PyPI是短暂的。偶尔删除包和帐户并不罕见。如果您想将软件包上传到真正的Python软件包索引,可以通过在https://pypi.org上注册帐户并按照相同的说明进行上传,但是,使用上传软件包并输入您的帐户凭据在真正的PyPI上注册。您可以使用真正的PyPI安装包 。twine upload dist/*`pip install your-package`

在这一点上,如果你想阅读更多关于包装的Python库,你可以做一些事情:

目录

上一主题

管理应用程序依赖项

下一个主题

指南

一些常见的包管理工具

  • distutils
  • setuptools
  • distribute
  • disutils2
  • distlib
  • pip

==创建纯 Python 或者平台 Wheels 的命令是:python setup.py bdist_wheel==

代码打包

打包你的代码,将它共享出去,让其他的开发者使用。例如,将其打包成一个库分享给其他开发者,以便他们用在自己的应用中,或者共享给开发工具,比如 ‘py.test’。

这种代码发布方式具备的优势是其成熟的工具生态系统,例如 PyPI 和 pip,这些工具使得其他的开发者很容易下载和安装你的包,无论是用于偶然的实验,还是将其集成到大型专业的系统中。

Python 代码以这种方式发布共享是一个成熟的惯例。如果你的代码不是在 PyPI 上打包的,那么别的开发者很难找到它,也很难将它集成到他们现有的程序中。他们会严重质疑这些没有在 PyPI 上打包项目的槽糕管理,甚至认为这些项目已停止维护。

类似于这种发布代码的方式的缺点是,它依赖于开发者了解如何安装它所依赖的 Python 版本,并且能够和愿意使用类似 pip 这样的工具安装你的包所需要的其他依赖。这种做法适合发布代码给其他开发人员,但是不适合发布应用程序给终端用户使用。

Python 打包指南 提供了创建和维护 Pythond 包的一个延伸的指导。

打包的替代方案

为了发布应用程序给终端用户使用,你应该 冻结你的应用程序

在 Linux 平台,你可以考虑 创建一个Linux发行版软件包 (例如 Debian or Ubuntu 系统中是一个.deb 文件)

对于 Python 开发者

如果你正在写一个开源的 Python 模块,PyPI 是一个适合它发布的地方,PyPI 的另一个名字 The Cheeseshop 更被人熟知。

Pip vs. easy_install

使用 pip。 详情 点击这里

私人 PyPI

如果你想要使用源码安装一个 Python 包,而不是使用 PyPI,(即, 你的包不对外公开),你可以通过托管一个简单的 HTTP 服务器来完成,从那些包的安装路径下运行。

从一个例子入手是最好的

比如你想安装一个包,它的名字是 MyPackage.tar.gz,假设你的目录结构使这样:

  • archive
    • MyPackage
      • MyPackage.tar.gz

代码冻结

『冻结』你的代码是指创建单个可执行文件,文件里包含所有程序代码以及 Python 解释器。

像 Dropbox、星战前夜、文明 4 和 BitTorrent 客户端都是如此。

进行这种分发的好处是你的用户不需要安装所要求的 Python 版本(或其他)即可直接运行你的应用程序。 在 Windows 上,甚至许多 Linux发行版和 OS X,系统自带的 Python 版本总是不尽如人意,此时这种分发方式就会体现其价值。

此外,终端用户软件应始终是可执行的格式。 以 .py 结尾的文件一般适用于软件工程师和系统管理员。

冻结的一个缺点是它会增加大约 2-12 MB 的发行大小。另外,如果修补了 Python 的安全漏洞, 你将需要独立负责更新分发的应用程序。

冻结的替代方案

打包你的代码 是指把你的库或工具分发给其他开发者。

Linux 下一个冻结的替代品是 Linux 分发包 (比如,对于 Debian 或 Ubuntu 是 .deb文件,而对于 Red Hat 与 SuSE 是 .rpm 文件)

冻结工具的比较

解决方案还有平台/特性支持性:

Solution Windows Linux OS X Python 3 License One-file mode Zipfile import Eggs pkg_resources support
bbFreeze yes yes yes no MIT no yes yes yes
py2exe yes no no yes MIT yes yes no no
pyInstaller yes yes yes yes GPL yes no yes no
cx_Freeze yes yes yes yes PSF no yes yes no
py2app no no yes yes MIT no yes yes yes

注意

在 Linux 下冻结 Windows 安装包,之前只有 PyInstaller 支持,不过后来也是 停止支持了

注意

所有解决方案都需要在 Windows 目标机器上安装了MS Visual C++ dll,除了 py2app 以外。只有 Pyinstaller 支持创建独立运行的绑定了dll 的 exe 文件,你需要在创建时传递参数 --onefileConfigure.py

Windows 下的解决方案

bbFreeze

前置要求是安装 Python, Setuptools 以及 pywin32 的依赖项

  1. 使用以下命令安装 bbfreeze:
1
$ pip install bbfreeze
  1. 编写最简单的示例 bb_setup.py
1
2
3
4
5
from bbfreeze import Freezer

freezer = Freezer(distdir='dist')
freezer.addScript('foobar.py', gui_only=True)
freezer()

注意

这将适用于最基本的文件脚本。 有时候你需要高级的用法,如包含或者排除某些路径,如下:
freezer = Freezer(distdir='dist', includes=['my_code'], excludes=['docs'])

  1. (可选) 包含图标
1
freezer.setIcon('my_awesome_icon.ico')
  1. 为冻结器(freezer)提供 Microsoft Visual C 运行时 DLL,我们有一般有两种方法,第一种是将Microsoft Visual Studio 路径 附加您的 sys.path 中,第二种是在脚本所在同一文件夹中放置 msvcp90.dll 文件。
  2. 开始冻结!
1
$ python bb_setup.py

py2exe

前置要求是安装了 Python on Windows

  1. 下载并且安装 http://sourceforge.net/projects/py2exe/files/py2exe/
  2. 编写 setup.py (配置选项清单):
1
2
3
4
5
6
from distutils.core import setup
import py2exe

setup(
windows=[{'script': 'foobar.py'}],
)
  1. (可选) 包含图标
  2. (可选) 单文件模式
  3. 生成 :file: .exedist 目录:
1
$ python setup.py py2exe
  1. 两种方式来提供 Microsoft Visual C 运行时 DLL。两个选项: 在目标机器全局安装 dll 或者 与 .exe 一起分发 dll

PyInstaller

前置条件是安装 Python, Setuptools 以及pywin32 依赖项.

OS X

py2app

PyInstaller

PyInstaller可用于在 Mac OS X 10.6(Snow Leopard)或更新版本上构建 Unix 可执行文件和窗口应用程序。

要安装 PyInstaller,使用 pip:

1
$ pip install pyinstaller

要创建标准的 Unix 可执行文件,使用 script.py

1
$ pyinstaller script.py

这会创建:

  • script.spec 文件, 类似于 make 文件
  • build 文件夹, 存放日志文件
  • dist 文件夹, 存放主要的可执行文件 script ,和一些依赖的Python库

script.py 会把全部内容放在同一个文件夹中。PyInstaller 将所有 script.py 用到的 Python 库放到 dist 文件夹中。所以在分发可执行文件时,会分发整个 dist 文件夹。

script.spec 文件可以编辑成 自定义构建 , 比如可以:

  • 将数据文件与可执行文件绑定在一起
  • 包含 PyInstaller 无法自动推断的运行时库( .dll.so 文件)
  • 将 Python 运行时选项添加到可执行文件中

现在:代码 script.spec 可以用 pyinstaller (而不是再次使用 script.py )运行。

1
$ pyinstaller script.spec

要创建独立的 OS X 窗口应用程序,请使用 --windowed 选项:

1
$ pyinstaller --windowed script.spec

这将在 dist 文件夹中创建一个 script.app 。请确保在 Python 代码中 使用 GUI 软件包,例如 PyQtPySide来控制应用程序的图形部分。

script.spec 有几个与 Mac OS X 应用程序捆绑有关的 选项 。 例如,要指定应用程序的图标,请使用 icon=\path\to\icon.icns 选项。

参考资料