Python打包及发布

前言

用于 =Python程序打包发布= 的模块有多个,如 =distutils=, =distribute=, =setuptools= 等,这些模块之间还有关联,到底用哪个比较好,一时还不好决定。

由于Python哲学是 =做一件事情只有一个方法=, 因此总是会出现新的模块代替旧模块,以追求这个最好的 =方法=.

也许,这就是为什么Python软件包层出不穷,乃至出现了不向后兼容的Python3;打包发布Python程序的时候要考虑到这些兼容性问题。

打包模块对比

参考 =StackOverFlow= 上问题 Differences between distribute, distutils, setuptools and distutils2?

提问:

1
2
3
4
5
我准备为Python 3发布一个开源库[[http://sympy.org/][SymPy]]. 为了在Python 3环境建立此模块,则需要运行 =2to3= 来自动转换,必须使用distribute模块。但根据当前系统的文档,却应该使用distutils模块。
不幸的是,我并不了解distutils,distribute,setuptools这些模块之间的具体差别,这些模块彼此关系错综复杂,阅读完文档也并不是确定能否完全兼容。
有谁能解释下这些模块的区别吗? 我应该使用哪个?哪个是最流行的解决方案?

Flimm的回答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
到201409为止,关于此问题的所有回答都已经是1年前的了,当你查看Python打包问题时,一定要确认回答的时间,不要被过时的信息所误导.
托管在 =Readthedocs= 上的 [Python Packaging User Guide](https://python-packaging-user-guide.readthedocs.org/en/latest/index.html) 值得一看,每一页都会显示一个 =最近核对时间= 信息,因此你可以确定手册的新旧程度以及是否全面。Python 3.4的官方文档也会链接到这个网站,足以增加可信度。
*工具模块总结*:
这是到201409为止的Python打包工具的总结:
- =Distutils=: 是Python打包的标准工具,属于Python 2和Python 3.0到3.4的 =标准库= 之中;主要用于简单地Python软件发布,但功能较少,可以在setup.py中导入
- =Setuptools=: 为了突破Distutils的限制而开发的,目前还不在标准库中;提供了命令行工具 =easy_install= ,同样可以在setup.py中导入,还可以通过pkg_resources来定位本地安装的软件包信息。可以作为Distutils的补丁,也可以和pip很好地配合工作;最新版本是201408更新的。
- =Distribute=: 由Setuptools衍生出来并使用了相同的名字空间,如果安装了Distribute,导入setuptools其实会导入Distribute安装的软件;但Distribute被合并进了从Setuptools 0.7,就 =不应该再继续使用Distribute= 了。
- =Distutils2=: 目标是融合Distutils,Setuptools,Distribute的长处并被包含进Python标准库。但事实上,已经是一个废弃的项目,最近的一次更新还是201203,而在Pypi的主页上已经确认此项目 =胎死腹中= 。
- =Distlib=: 目标是实现一个上面几个工具的子集,但只包含符合PEP定义的部分。这个软件包应该有望加入Python标准库,但目前人处于开发当中,不推荐用户使用。
- =Bento=: 是一个从零开始,用于替换Distutils,Setuptools,Distribute,Distutils2的打包解决方案。它的核心开发成员也是numpy/scipy的核心成员,因此对打包系统的non-simple用例也能属性;第一次更新是200910,最新一次更新是201408,但作者并没有相应地更新其Pypi页面。虽处于活跃开发中,但还不成熟,也没有Setuptools使用广泛。
*建议*:
最终结论是,在这些选项中我 =推荐Setuptools= ,如果你的需求十分简单则使用 =Distutils=. =Setuptools可以和Virtualenv,Pip很好地配合= ,这两个工具我也极力推荐。
顺便提一下,建议使用Virtualenv 1.10或更高版本,因为这是Setuptools/Distribute合并后发布的第一个版本,可以在Python 2/3中更好地工作。

工具推荐

来自: Tool Recommendations:

  • Installation Tool Recommendations
    • Use =pip= to install Python packages from =PyPI=.
    • Use =virtualenv=, or =pyvenv= to isolate application specific dependencies from a shared Python installation.
    • Use =pip wheel= to create a cache of wheel distributions, for the purpose of speeding up subsequent installations.
    • If you’re looking for management of fully integrated cross-platform software stacks, consider =buildout= (primarily focused on the web development community) or =Hashdist=, or =conda= (both primarily focused on the scientific community).
  • Packaging Tool Recommendations
    • Use =setuptools= to define projects and create =Source Distributions=.
    • Use the =bdist_wheel setuptools extension= available from the =wheel project= to create =wheels=. This is especially beneficial, if your project contains binary extensions.
    • Use =twine= for uploading distributions to =PyPI=.

pip对比easy_install

来自: https://packaging.python.org/en/latest/technical.html#pip-vs-easy-install

=easy_install= 发布于2004,而 =pip= 发布于2008,它们的对比是:

pip easy_install
=Installs from Wheels= Yes No
Uninstall Packages Yes (pip uninstall) No
Dependency Overrides Yes (Requirements Files) No
List Installed Packages Yes (pip list and pip freeze) No
PEP438 Support Yes No
Installation format ‘Flat’ packages with egg-info metadata Encapsulated Egg form
sys.path modification No Yes
=Installs from Eggs= No Yes
pylauncher support No Yes
Dependency ResolutionKindaKinda
Multi-version Installs No Yes

egg格式

=egg= 是一个包含所有包数据的文件包。在理想情况中,egg 是一个使用 zip 压缩的文件,其中包括了所有需要的包文件。但是在某些情况下,setuptools 会决定(或被开关告知)包不应该是 zip 压缩的。在这些情况下,egg 只是一个简单的未曾压缩的子目录,但是里面的内容是相同的。使用单一的版本可以方便地进行转换,并可以节省一点磁盘空间,但是 egg 目录从功能和组织结构上来说都是相同的; 与 Java的 =JAR文件= 类似,不过是用于Python的.

安装egg文件

如果已经有xxxx.egg文件,则安装:

1
$ easy_install xxxx.egg

如果是远程安装,则:

1
$ easy_install xxxx

卸载egg文件

无法自动删除,需要手动删除,可以查看文件 =site-packages/easy-install.pth=, 这个文件配置了所有egg文件的位置,删掉则无法引入到Python环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat /Library/Python/2.7/site-packages/easy-install.pth
import sys; sys.__plen = len(sys.path)
./ipython-1.2.0-py2.7.egg
./bpython-0.12-py2.7.egg
./Pygments-1.6-py2.7.egg
./Sphinx-1.2.1-py2.7.egg
./Jinja2-2.7.2-py2.7.egg
./docutils-0.11-py2.7.egg
./MarkupSafe-0.18-py2.7-macosx-10.9-intel.egg
./pip-1.4.1-py2.7.egg
./DPark-0.1-py2.7-macosx-10.9-intel.egg
./psutil-2.1.1-py2.7-macosx-10.9-intel.egg
./lz4-0.6.1-py2.7-macosx-10.9-intel.egg
./Cython-0.20.2-py2.7-macosx-10.9-intel.egg
./protobuf-2.5.0-py2.7.egg
./msgpack_python-0.4.2-py2.7-macosx-10.9-intel.egg
./pyzmq-14.3.1-py2.7-macosx-10.6-intel.egg
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python
./CherryPy-3.2.4-py2.7.egg
./gevent-1.0.1-py2.7-macosx-10.9-intel.egg
./greenlet-0.4.4-py2.7-macosx-10.9-intel.egg
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

制作egg文件

假设setup.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from setuptools import setup, find_packages
setup(
name = "Test",
version = "0.2.0",
keywords = ('Test', 'egg'),
description = 'a simple egg for test',
license = 'MIT License',
url = 'http://example.com',
author = 'xxxx',
author_email = 'xxxx@yyyy.com',
packages = find_packages(),
package_data = {'': ['*.*']},
include_package_data = True,
platforms = 'any',
install_requires = [],
)

打包文件:

1
2
3
4
$ python setup.py bdist_egg #生成*.egg文件,支持easy_install安装
$ python setup.py bdist_wininst #生成exe文件
$ python setup.py bdist_rpm #生成rpm文件
$ python setup.py sdist #生成*.zip/*.tar.gz文件,支持pip安装

部署到PyPI

先要将egg注册:

1
$ python setup.py register

然后将打包文件上传:

1
$ python setup.py sdist bdist_egg upload

之后就可以使用pip或easy_install安装对应压缩包了.

wheel格式

PyPA团队 开发的Python打包生态环境工具链: =pip=, =setuptools=, =virtualenv= 和 =wheel=.

wheel是用于替换egg格式,通过扩展setuptools,增加 =bdist_wheel= 功能就可以打包wheel文件。

pip可以直接安装wheel格式软件包,但无法安装egg格式软件包;如果需要安装egg格式,只能使用easy_install.

打包.whl软件包

1
2
3
$ sudo pip install wheel
$ python setup.py bdist_wheel

安装wheel软件包

1
2
3
$ pip wheel xxxx
$ pip install xxxxxx.whl

后记

没有一个真正拿得出手的Python项目作为实践,这些打包方面的知识只能学皮毛。

资料

吴羽舒 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!