目前最常用的打包工具为setuptools,介绍setuptools之前,我们先了解一下distutils
distutils 是python的一个标准库,是python官方开发的一个分发包工具,所有后续的打包工具,都是基于它开发的。
distutils 的核心是setup.py文件,是模块分发和安装的指导文件。
但是它无法定义包之间的依赖关系。

1. setuptools

它是distutils的升级版,扩展了很多功能,能够帮助开发者更好地创建和分发Python包,尤其是具有复杂依赖关系的包。
其通过添加一个基本的依赖系统以及许多相关功能,弥补了该缺陷。他还提供了自动包查询程序,用来自动获取包之间的依赖关系,并完成这些包的安装,大大降低了安装各种包的难度,使之更加方便。
功能亮点:

  • 利用EasyInstall自动查找、下载、安装、升级依赖包
  • 创建Python Eggs
  • 包含包目录内的数据文件
  • 自动包含包目录内的所有的包,而不用在setup.py中列举
  • 自动包含包内和发布有关的所有相关文件,而不用创建一个MANIFEST.in文件
  • 自动生成经过包装的脚本或Windows执行文件
  • 支持Pyrex,即在可以setup.py中列出.pyx文件,而最终用户无须安装Pyrex
  • 支持上传到PyPI 可以部署开发模式,使项目在sys.path中
  • 用新命令或setup()参数扩展distutils,为多个项目发布/重用扩展
  • 在项目setup()中简单声明entry points,创建可以自动发现扩展的应用和框架

2. 安装

# 一般 Python 安装会自带 setuptools,如果没有可以使用 pip 安装
$ pip install setuptools

# 更新,以下两种任选
$ python ez_setup.py –U setuptools
$ pip install -U setuptools

3. 两种打包方式

Python 包的分发可以分为源码包和二进制包两种

3.1 源码包

源码包安装的过程,是先解压,再编译,最后才安装,所以它是跨平台的,由于每次安装都要进行编译,相对二进包安装方式来说安装速度较慢。常见的格式有:zip、gztar、bztar、ztar、tar

打包命令:

python setup.py sdist --formats=gztar

–formats 可以指定打包格式,可以用逗号分隔,同时打包多个格式,如:–formats=gztar,zip
包的名称为 setup.py 中定义的 name, version以及指定的包格式

3.2 二进制包

二进制包的安装过程省去了编译的过程,直接进行解压安装,所以安装速度较源码包来说更快。由于不同平台的编译出来的包无法通用,所以在发布时,需事先编译好多个平台的包。常见格式有:egg、wheel

Egg 格式是由 setuptools 在 2004 年引入,而 Wheel 格式是由 PEP427 在 2012 年定义。Wheel 的出现是为了替代 Egg,它的本质是一个zip包,其现在被认为是 Python 的二进制包的标准格式

使用wheel打包之前,需要先安装wheel模块

# 安装
pip install wheel
# 打包
python setup.py bdist_wheel

执行成功后,目录下除了 dist 和 *.egg-info 目录外,还有一个 build 目录用于存储打包中间数据。

4. 最关键的setup.py文件如何编写

在目录 setup_demo 下新建安装文件 setup.py,然后创建包 my_demo 模拟要打包源码包:

.
├── my_demo
│ └── __init__.py
└── setup.py

setup.py文件内容如下:

from setuptools import setup

setup(
    name='App', # 应用名
    version='1.0.0', # 版本号
    author = 'web3.0'
    author_email = 'xxxx@qq.com'
    packages=['my_demo'], # 包括在安装包内的 Python 包,此处表示my_demo目录下所有文件
    description = '这是项目描述'
)

更多参数:

程序分类信息

classifiers

from setuptools import setup, find_packages

setup(
    classifiers = [
        # 发展时期,常见的如下
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stable
        'Development Status :: 3 - Alpha',

        # 开发的目标用户
        'Intended Audience :: Developers',

        # 属于什么类型
        'Topic :: Software Development :: Build Tools',

        # 许可证信息
        'License :: OSI Approved :: MIT License',

        # 目标 Python 版本
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ]
)

文件的分发

from setuptools import setup, find_packages

setup(
    name='App', # 应用名
    version='1.0.0', # 版本号
    author = 'web3.0',
    author_email = 'xxxx@qq.com',
    description = '这是项目描述',
    package_dir={'': 'src'},
    packages=find_packages('src'),
    # 安装过程中,需要安装的静态文件,如配置文件、service文件、图片等
    data_files=[
        ('', ['conf/*.conf']),
        ('/usr/lib/systemd/system/', ['bin/*.service']),
               ],

    # 希望被打包的文件
    package_data={
        '':['*.txt'],
        'bandwidth_reporter':['*.txt']
               },
    # 不打包某些文件
    exclude_package_data={
        'bandwidth_reporter':['*.txt']
               }
)
### 依赖包下载安装
```python
from setuptools import setup, find_packages

setup(
    name='App', # 应用名
    version='1.0.0', # 版本号
    author = 'web3.0',
    author_email = 'xxxx@qq.com',
    description = '这是项目描述',
    package_dir={'': 'src'},
    packages=find_packages('src'),
    # 表明当前模块依赖哪些包,install_requires 在安装模块时会自动安装依赖包
    install_requires=['docutils>=0.3'],

    # setup.py 本身要依赖的包,这通常是为一些setuptools的插件准备的配置
    # 这里列出的包,不会自动安装。
    setup_requires=['pbr'],

    # 仅在测试时需要使用的依赖,在正常发布的代码中是没有用的。
    # 在执行python setup.py test时,可以自动安装这三个库,确保测试的正常运行。
    tests_require=[
        'pytest>=3.3.1',
        'pytest-cov>=2.5.1',
    ],
    # extras_require 不会自动安装依赖包,这里仅表示该模块会依赖这些包
    # 但是这些包通常不会使用到,只有当你深度使用模块时,才会用到,这里需要你手动安装
    extras_require={
        'PDF':  ["ReportLab>=1.2", "RXP"],
        'reST': ["docutils>=0.3"],
    }
)

安装环境的限制

有些库并不是在所以的 Python 版本中都适用的,若一个库安装在一个未兼容的 Python 环境中,理论上不应该在使用时才报错,而应该在安装过程就使其失败,提示禁止安装。

这样的功能,可以使用 python_requires 来实现。

setup(
    ...
    python_requires='>=2.7, <=3',
)