Python setup.py 安装包详解
Python安装包在不同系统有不同的安装方式,其底层依赖setup.py实现,本文详细介绍setuptools的实现原理和使用指南。
打包工具介绍
distutils: Python 官方开发的标准库distribute utils,Python 打包工具的始祖,核心配置文件setup.cfg/setup.pysetuptools:distutils的升级版本,主流实现distribute: 是setuptools的分支版本,关系比较密切。
本文重点介绍 setuptools 的使用。
安装
pip2 install setuptools
# or
pip3 install setuptools
# or
pip3 install setuptools==39.2.0help
常用命令
# install everything from build directory
python3 setup.py install
# create a source distribution
python3 setup.py sdist
# create an RPM distribution
python3 setup.py bdist_rpm
# create an "egg" distribution
python3 setup.py bdist_egg
# create an executable installer for MS Windows, 必须在 Windows 上执行
python3 setup.py bdist_wininst包格式
- 源码包:以压缩格式存在,一般为
tar.gz,安装时需要根据不同平台编译。包一般比较大。 - 二进制包:已经编译,一般以
eggs、wheels/whl形式存在,安装速度比源码快。- egg(.egg): 由 setuptools 在 2004 年引入,本质上是一个包含了项目代码以及元数据(一个名为egg-info的子目录)的zip压缩包
- wheels(.whl): 由 PEP427 在 2012 年定义,Wheel 格式的包中包含一个名为
.dist-info的子目录,目标是替代 egg
区别
Wheel 和 Egg 的主要区别:
- Egg 既是一种分发格式,也是一种运行时安装的格式,并且是可以被直接 import
- Egg 格式的包需要使用 easy_install 进行安装,
- Wheel 有一个官方的 PEP427 来定义,而 Egg 没有 PEP 定义
- Wheel 是一种分发格式,即打包格式。
- Wheel 文件不会包含 .pyc 文件
- Wheel 使用和 PEP376 兼容的 .dist-info 目录,而 Egg 使用 .egg-info 目录
- Wheel 有着更丰富的命名规则
- Wheel 是有版本的。每个 Wheel 文件都包含 wheel 规范的版本和打包的实现
- Wheel 在内部被 sysconfig path type 管理,因此转向其他格式也更容易
- Wheel 可以使用 pip 安装(tgz的也可以)
.whl文件有一点与.egg文件相似:实际上它们都是.zip文件。可以将.whl文件名扩展改为.zip,就可以使用zip应用程序打开它
配置
以 Pecan 使用介绍 为例
setup.py
# -*- coding: utf-8 -*-
try:
from setuptools import setup, find_packages
except ImportError:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages
setup(
name='test_pecan',
version='0.1',
description='',
author='',
author_email='',
install_requires=[
"pecan",
],
test_suite='test_pecan',
zip_safe=False,
include_package_data=True,
packages=find_packages(exclude=['ez_setup'])
)setup 函数参数:
- classifiers: 包的分类信息
- packages: 告诉Distutils需要处理那些包(包含__init__.py的文件夹)
- package_dir: 告诉Distutils哪些目录下的文件被映射到哪个源码包。一个例子:
package_dir = {'': 'lib'},表示root package中的模块都在lib目录中 - ext_modules: 是一个包含Extension实例的列表,Extension的定义也有一些参数
- ext_package: 定义extension的相对路径
- requires: 定义依赖哪些模块
- provides: 定义可以为哪些模块提供依赖
- scripts: 指定python源码文件,可以从命令行执行。在安装时指定–install-script
- package_data: 通常包含与包实现相关的一些数据文件或类似于readme的文件。如果没有提供模板,会被添加到MANIFEST文件中
- exclude_package_data 不打包的文件
- data_files: 静态文件,如配置文件、service文件等
cmdclass={'my_command': XXXCommand}用来指定用户自定义的命令类XXXCommand用户自定义命令类,继承自distutils.core.Command类,用来执行一些特定的任务- 当执行
python setup.py my_command时,将会调用XXXCommand类的run()方法来执行任务
setup(...,
data_files=[
('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
('config', ['cfg/data.cfg']),
('/etc/init.d', ['init-script'])]
)规定了哪些文件被安装到哪些目录中。如果目录名是相对路径,则是相对于 sys.prefix 或 sys.exec_prefix 的路径
setup.cfg
[nosetests]
match=^test
where=test_pecan
nocapture=1
cover-package=test_pecan
cover-erase=1MANIFEST.in
MANIFEST.in 用来控制文件的分发,如下例:
include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build作用如下:
- 第一行:所有根目录下的以
txt为后缀名的文件,都会分发 - 第二行:根目录下的
examples目录 和txt、py文件都会分发 - 第三行:路径匹配上
examples/sample?/build不会分发
MANIFEST.in 和 setup.py 同级的目录下,setuptools 时会自动读取该文件
PBR
pbr 是 setuptools 的辅助工具,最初由 OpenStack 开发(https://launchpad.net/pbr)。pbr 工作运行时会读取和过滤 setup.cfg 中的数据解析后给 setup.py 作为参数。包含如下功能:
- 从 git 中获取
Version、AUTHORS and ChangeLog信息 - Sphinx Autodoc。pbr 会扫描 project,找到所有模块,生成 stub files
- 读取
requirements.txt,生成 setup 函数需要的xxx.egg-info/requires.txt
setup.py
import setuptools
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
pbr=True)setup.cfg
参考:https://opendev.org/openstack/octavia/src/branch/master/setup.cfg
说明:
- packages: 指定需要包含的包,功能类似于 setuptools.find_packages
- data_files: 指定目的目录和源文件路径
- entry_points: 入口,会放到
/usr/local/bin/目录下
扩展 setup.cfg 版本信息(python3 setup.py sdist)会在目标文件中自动生成:
...
[egg_info]
tag_build =
tag_date = 0
...指定版本打包
基于 pbr 的打包,指定 tag 版本会显示为软件包的版本,示例:
- git 打 tag
git tag v1.0.0
git checkout v1.0.0- 打 source 包,打包后可以在
dist/目录下找到对应的压缩包
# 默认,下面示例采用该方式
python3 setup.py sdist
# 指定包格式,查看指的到包格式:python2 setup.py bdist --help-formats
python3 setup.py sdist --formats=gztar,zip
# 指定用户
python3 setup.py sdist --owner=root --group=root
# egg 包
python3 setup.py bdist_egg
# rpm 包,更多参考:https://www.xiexianbin.cn/tags/rpmbuild/index.html
yum install rpm-build make gcc -y
python3 setup.py bdist_rpm --help
python3 setup.py bdist_rpm --release=1- 查看包的格式
$ cd dist/ && tar -zxvf *.tar.gz
$ tree .
...
├── MANIFEST.in
├── PKG-INFO # 包版本信息,为 v1.0.0
├── README.rst
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.txt
└── tox.ini- 安装
easy_install xxx.tar.gz制作 whl
bdist_wheel 命令默认不存在,需要安装如下包后,才能使用:
$ pip3 install wheel check-wheel-contents制作包
$ python3 setup.py bdist_wheel
$ ls dist/
xxx-py3-none-any.whlwhl 包本质
$ file xxx-py3-none-any.whl
xxx-py3-none-any.whl: Zip archive data, at least v2.0 to extract, compression method=deflate
# 解压
tar -zxvf xxx-py3-none-any.whl使用 setup.py 安装包
# 正式安装
python3 setup.py install
# 开发模式安装,软链接方式实现
python3 setup.py develop与pip区别
python setup.py install和pip install都是用来安装python包的,实际上,pip提供了更多的特性,更易于使用。体现在以下几个方面:
- pip 会自动下载依赖,而如果使用 setup.py,则需要手动搜索和下载
- pip 会自动管理包的信息,使卸载/更新更加方便和容易,使用pip uninstall即可。而使用setup.py,必须手动删除,有时容易出错
- pip 提供了对 virtualenv 更好的整合
其他
Babel 语言包
Babel是Python的一个国际化工具包,提供了对distutils或setuptools的支持,包含一些命令。
- compile_catalog
类似于msgfmt工具,takes a message catalog from a PO file and compiles it to a binary MO file.
$ ./setup.py compile_catalog --directory foobar/locale --locale pt_BR
running compile_catalog
compiling catalog to foobar/locale/pt_BR/LC_MESSAGES/messages.mo- extract_messages
类似于xgettext,it can extract localizable messages from a variety of difference source files, and generate a PO (portable object) template file from the collected messages.
$ ./setup.py extract_messages --output-file foobar/locale/messages.pot
running extract_messages
extracting messages from foobar/__init__.py
extracting messages from foobar/core.py
...
writing PO template file to foobar/locale/messages.pot- update_catalog
类似于msgmerge,it updates an existing translations catalog based on a PO template file (POT).