pypilog

本文是 Python application 的打包和发布的下篇(上篇请见此处),主要介绍 MANIFEST.in 和某些打包参数,并利用该文件和这些参数为 packagedemo 添砖加瓦。

回顾上篇的 packagedemo,它的非常功能简单,只包含一个仅有 2 行代码的 main.py 文件。实际情况下,复杂些的 application 可能要求以下功能。

  • CLI: 提供命令行入口
  • Data file: 数据文件
  • Dependency: 依赖其它的 package

CLI

现在往 packagedemo 添加一个名为 packagedemo_cli 的 CLI,执行 packagedemo_cli 后,直接调用 main.py 的 main 函数,新增如下文件和目录。

packagedemo
├── ...
└── bin
    └── packagedemo_cli

文件 packagedemo_cli 的内容如下:

#!/usr/bin/python
from packagedemo import main

main.main()

并为 packagedemo_cli 设置可执行权限:

$ chmod 755 packagedemo_cli

更新 setup.py:

setuptools.setup(
    ...
    scripts=['bin/packagedemo_cli'],
    ...
)

安装后,测试如下:

$ which packagedemo_cli
/usr/local/bin/packagedemo_cli

$ packagedemo_cli
A demo for python package.

除此方法以外,还可以利用 entry_points 中的 console_points 配置 CLI,详情请见 Command Line Scripts


Data File

有些 python application 会依赖一些非 *.py 数据文件,比如 image, documentation 和 data tables 等,我们把这些文件统称为 data file,所以打包时需将这些文件包含在内。现在往 packagedemo 添加 data 目录和相关文件,如下:

packagedemo
├── ...
└── data
    └── data.json

在上篇为空文件的 MANIFEST.in 终于派上用场,更新如下:

$ cat MANIFEST.in
include data/data.json

更新 setup.py:

setuptools.setup(
    ...
    include_package_data=True,
    ...
)

Dependency and Others

随着 packagedemo 功能越来越丰富,不免会依赖其它的 package,所以需要往 setup.py 中写入所依赖的 package 名称。假定 packagedemo 依赖 wsgiref 这个 package,并且要求其 version >=0.1.2,那么需往 setup.py 增添如下的参数:

setuptools.setup(
    ...
    install_requires=['wsgiref>=0.1.2'],
    ...
)

最后一个被介绍的参数是 classifiers,它包含 package 的成熟度,类型,以及支持的平台等信息。

setuptools.setup(
    ...
    classifiers=[
        # How mature is this project? Common values are
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stable
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Build Tools',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: MIT License',

        # Specify the Python versions you support here. In particular, ensure
        # that you indicate whether you support Python 2, Python 3 or both.
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
    ],
    ...
)

Summary of Python packaging tools

Python 有多种打包工具,如 setuptools, distutils 等等,stackoverflow 有篇名为 differences-between-distribute-distutils-setuptools-and-distutils2 的帖子对这些打包工具做了详细的对比,原文如下:

Here’s a summary of the Python packaging landscape in September 2014:

  • Distutils is still the standard tool for packaging in Python. It is included in the standard library (Python 2 and Python 3.0 to 3.4). It is useful for simple Python distributions, but lacks features. It introduces the distutils Python package that can be imported in your setup.py script.

  • Setuptools was developed to overcome Distutils’ limitations, and is not included in the standard library. It introduced a command-line utility called easy_install. It also introduced the setuptools Python package that can be imported in your setup.py script, and the pkg_resources Python package that can be imported in your code to locate data files installed with a distribution. One of its gotchas is that it monkey-patches the distutils Python package. It should work well with pip. The latest version was released in August 2014.

  • Distribute was a fork of Setuptools. It shared the same namespace, so if you had Distribute installed, import setuptools would actually import the package distributed with Distribute. Distribute was merged back into Setuptools 0.7, so you don’t need to use Distribute any more. In fact, the version on Pypi is just a compatibility layer that installs Setuptools.

  • Distutils2 was an attempt to take the best of Distutils, Setuptools and Distribute and become the standard tool included in Python’s standard library. The idea was that Distutils2 would be distributed for old Python versions, and that Distutils2 would be renamed to packaging for Python 3.3, which would include it in its standard library. These plans did not go as intended, however, and currently, Distutils2 is an abandoned project. The latest release was in March 2012, and its Pypi home page has finally been updated to reflect its death.

  • Distlib is a tool that aims to implement a subset of the previous tools’ functionality, but only functionality that is very well-defined in accepted PEPs. It should hopefully be included eventually in the Python standard library. It is still being developed and is not recommended for end-users yet.

  • Bento is a packaging solution designed to replace Distutils, Setuptools, Distribute and Distutils2, written from the ground up. Its primary developer is also a core developer of numpy/scipy, so he’s familiar with non-simple use-cases for packaging systems. Its first commit was in October 2009, and the latest commit as of writing was in August 2014, although the authors are not updating its Pypi page correspondingly. It’s in active development but it is not mature yet, and it is not as widely known as Setuptools yet.

关于选择哪种工具,大神 flimm 推荐 setuptools:

So in conclusion, out of all these options, I would recommend Setuptools, unless your requirements are very basic and you only need Distutils. Setuptools works very well with Virtualenv and Pip, tools that I highly recommend.

虽然 python package 能满足多数 application 的需求,但是随着项目的越来越繁杂,RPM 或者 Debian 会是更好的包管理方式,它们的功能更为强大丰富。