以下内容是根据官方文档做的笔记。
Contents
推荐用法
在项目根目录添加 ez_setup.py 文件, 然后在 setup.py 文件的开头添加如下代码:
1 2 | from ez_setup import use_setuptools
use_setuptools()
|
这样写的话,其他人安装你的 Python 包时, 如果没有安装 setuptools 工具,该脚本就会自动下载并安装 setuptools。
当然也可以通过这个脚本来直接安装、更新 setuptools:
1 | $ sudo python ez_setup.py -U setuptools
|
基本用法
下面是一个最基本的 setup.py。
1 2 3 4 5 6 | from setuptools import setup, find_packages
setup(
name = "HelloWorld",
version = "0.1",
packages = find_packages(),
)
|
就是这里的几行代码,就可以自动查找需要打包的文件, 将当前的项目打包成 eggs,支持上传到 PyPI 。
当然如果需要上传到 PyPI ,最好再添加一些额外信息。
版本号格式
setuptools 能够支持大部分的版本号格式。
如果您不是很确定您定义的版本号是否被 setuptools 支持, 您可以使用 pkg_resources.parse_version() 来判断。
1 2 3 4 5 6 7 | >>> from pkg_resources import parse_version
>>> parse_version('1.9.a.dev') == parse_version('1.9a0dev')
True
>>> parse_version('2.1-rc2') < parse_version('2.1')
True
>>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9')
True
|
可选的 setup() 函数参数
include_package_data
如果设置为 True,setuptools 就会在项目目录里自动查找所有的数据文件
这些数据文件包括被 CVS/SVN 进行版本管理的, 或者你在 MANIFEST.in 中指定的文件。
详见 数据文件的安装 。
exclude_package_data
它的值为一个字典。
打包时排除某些文件 / 目录, 即使该文件 / 目录在 include_package_data 指定的范围内。
详见 数据文件的安装 。
package_data
它的值也为一个字典。
如果 include_package_data 值为 True,那么这个参数就没必要再用。
它提供了更细粒度的控制哪些文件该被打包。
详见 数据文件的安装 。
zip_safe
它的值为 True/False。它用来指定打出来的 ZIP 包是否能够安全的被安装, 或者直接运行。
如果你不提供该值, bdist_egg 子命令每次打包时都需要做检查。
zip 包形式能够占用更少的磁盘空间,且加载速度更快( 就一个文件,虽然要解压,但是 CPU 速度远快于磁盘速度)。
install_requires
该值为一个列表,其中每个值表示该包所依赖的包的名称。
当你在安装该包时,setuptools 会自动安装它所依赖的那些包。
详见 依赖包的声明 。
entry_points
该值为一个字典。是用来动态地发现该包所提供的服务或者插件。
详见 ` 服务和插件的动态发现 `_ 。
额外插一句,该值也可以用来 脚本的自动生成 。
extras_require
该值为一个字典。用来指定你的包所提供的额外功能所需要用来的依赖包。
详见 依赖的声明 。
setup_requires
该值为一个字符串列表。 当你在执行 setup.py 时需要安装哪些额外的包,你可以在该值里面指定。
Note
这些包默认只会下载下来,并不会进行安装。
如果需要安装请配合使用 install_requires 和 setup_requires
dependency_links
该值为一个字符串列表。 用来查找依赖包的 URLs。
namespace_packages
该值为一个字符串列表。 命名空间包是一个包含多个其它包的虚拟包。
详见 命名空间包 。
test_suite
该值为一个字符串。 用来指定测试该包用的一个测试套件。比如 nosetest 。
指定之后,就可以通过 python setup.py test 来进行测试。 详见 `test 命令 `_ 。
tests_require
该值为一个字符串或者一个字符串列表。
如果测试该包需要安装一些额外的包,请在该值内指定。
Note
这些额外的包并不会安装到系统里,默认只会下载下来。
test_loader
如果你不想用 setuptools 的默认查找测试用例的规则,而是想自己自定义, 那么,这个参数正合你意。
eager_resources
该值为一个字符串列表。
详见 ` 资源的自动扩展 `_ 。
use_2to3
在编译过程中使用 2to3 脚本来将 Python2 的代码转换成 Python3 的代码。
convert_2to3_doctests
该值为一个字符串列表。 用来指定哪些 doctest 源代码需要使用 2to3 脚本进行转换的。
use_2to3_fixers
该值为一个字符串列表。 在 2to3 的转换过程中还哪些额外的 fixers。
使用 find_packages()
针对简单的项目,你可以直接手工在 packages 参数里指定需要打包的文件。 但是针对非常大型的项目(Twisted, PEAK, Zope, Chandler, etc.), find_packages() 是派得上用场了。
find_packages() 有三个参数:
- where, 指定源目录,默认为 setup.py 脚本所在的目录。
- exclude, 类似于 exclude_package_data
- include, 类似于 include_package_data
脚本的自动生成
打包和安装脚本对于 distutils 模块来说有点棘手。
- 没有一个比较容易的指定符合各个平台(Windows、Linux,etc)约定的脚本名称。
- 你需要专门为 main 函数创建一个脚本。
setuptools 就解决如上的所有问题。它可以自动创建脚本。 在 Windows 平台甚至直接生成 exe 文件。
当然,想要 setuptools 自动完成这一切, 你需要在 entry_points 参数说明。
1 2 3 4 5 6 7 8 9 10 11 12 | setup(
# other arguments here...
entry_points = {
'console_scripts': [
'foo = my_package.some_module:main_func',
'bar = other_module:some_func',
],
'gui_scripts': [
'baz = my_package_gui.start_func',
]
}
)
|
Eggsecutable 脚本
某些情况,你可能需要让一个 egg 格式的 Python 包能够直接被执行。 那么,你只需要像下面一样做就可以了:
1 2 3 4 5 6 7 8 | setup(
# other arguments here...
entry_points = {
'setuptools.installation': [
'eggsecutable = my_package.some_module:main_func',
]
}
)
|
Note
eggsecutable 的 egg 包不能被重命名或者通过连接来执行。
数据文件的安装
setuptools 提供三种方式来定制包内的数据文件。
你需要将打开 include_package_data 参数。
1 2 3 4 5
from setuptools import setup, find_packages setup( ... include_package_data = True )
这个参数会告诉 setuptools 自动查找包内包含的数据文件, 但是自动查找是有要求的。
这些数据文件必须是在 CVS/SVN 这些版本管理工具的仓库里面受版本控制的 (当然你也可以写 setuptools 扩展来支持其它的版本管理工具), 或者在 MANIFEST.in 文件中被指定的。
如果你想有比较细粒度地控制 setuptools 打包哪些数据文件, 那么你可以使用 package_data 参数。
1 2 3 4 5 6 7 8 9 10
from setuptools import setup, find_packages setup( ... package_data = { # If any package contains *.txt or *.rst files, include them: '': ['*.txt', '*.rst'], # And include any *.msg files found in the 'hello' package, too: 'hello': ['*.msg'], } )
package_data 参数是一个字典,它的 Key 值是包内目录的名称, Value 值是一个包含通配符字符串的列表。 比如一个包的内部目录结构
setup.py src/ mypkg/ __init__.py mypkg.txt data/ somefile.dat otherdata.dat
那么它对应的 package_data 参数就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
from setuptools import setup, find_packages setup( ... packages = find_packages('src'), # include all packages under src package_dir = {'':'src'}, # tell distutils packages are under src package_data = { # If any package contains *.txt files, include them: '': ['*.txt'], # And include any *.dat files found in the 'data' subdirectory # of the 'mypkg' package, also: 'mypkg': ['data/*.dat'], } )
注意:上面两个示例中 package_data 的一个 Key 值是一个空字符串, 这个就代表会在所有的目录里查找对应的数据文件。
注意:如果你使用到了路径,请使用 / 来指定路径分隔, 即使在 Windows 平台也是这样,setuptools 会根据当前的打包平台自动识别。
注意:在 Python2.4 之后的 distutils 模块也添加对该参数的支持。 如果你指定了 include_package_data 参数,那么 package_data 将无效。
但是还有些情况,以上两个参数还是满足不了。 比如你想在你发布的 Python 包内包含 README 文件, 但是安装的时候又不希望安装它。
这时候,你就需要 exclude_package_data 参数来帮忙了。
1 2 3 4 5 6 7 8 9 10 11
from setuptools import setup, find_packages setup( ... packages = find_packages('src'), # include all packages under src package_dir = {'':'src'}, # tell distutils packages are under src include_package_data = True, # include everything in source control # ...but exclude README.txt from all packages exclude_package_data = { '': ['README.txt'] }, )
exclude_package_data 参数和 package_data 是一样的, 也是字典,在该字典里匹配到的所有文件都不会被安装。 即使这个文件符合 include_package_data 或者 package_data 参数 的要求。
注意: disutils 模块的打包流程会导致一种现象, 你之前的包有包含过某些数据文件,但之后你又删除了该数据文件。 那么这些数据文件在你的打包目录便会变成孤儿,你最好运行命令 python setup.py clean --all 来完全删除它们。
你的这个包的使用者或者其它代码贡献者通过版本管理工具追踪版本时, 他们就会知道是你做了某些改变,然后需要删除这此文件的, 那么他们也就能够放心大胆运行 python setup.py clean --all 命令了。
pkg_resources
该模块的全称为: Package Discovery and Resource Access
这个模块主要有以下几个功能:
- 提供 API 给 Python 库来让它们能够访问它们自己的资源文件
- 能让扩展的应用和框架自动发现插件
- 给 zip 格式的 eggs 包内的 C 扩展提示运行时支持
- 能够合并各种独立分发的 Python 模块,就是下文的命名空间包
- 提供 API 来管理当前 “ 工作集 ” 中的 Python 包
命名空间包
命名空间包本质算是一个虚拟包, 这个包主要将多个独立分发的包集合成一个,方便安装。 比如: peak 是一个命名空间包,它包含了一系列不同用途的子包。
那么如何创建一个命名空间包呢?
在 setup() 函数中添加 namespace_package 参数。 该参数为一个列表,然后将需要集合的包的名称写进去。
你也必须在命名空间包的 __init__.py 文件中添加 __declare_namespace() 函数的调用。