pypilog

Packaging and Distributing Projects 介绍了 python application 打包和发布的规范,只有满足这种规范的 package 才能被最为常用的包管理工具 pip 所管理。setuptools 是常用的打包工具,其文档 Building and Distributing Packages with Setuptools 同样详细的阐述打包规范。本文以名为 packagedemo 的 application 为例(官网例子请见 PyPA sample project),展示如何编写一个标准的 package,期间主要涉及三个步骤:

  • Configure: packagedemo 的文件和目录组织
  • Package: 打包 packagedemo
  • Distribute: 把打包后的 packagedemo 发布到 Pypi 中

Configuring your Project

编写 packagedemo 时,需要注意两方面的规范:

  • 文件目录组织:包含目录组织规范、某些必需的文件
  • setup.py:打包的参数信息

Initial Files

我们以 packagedemo 为例,这是一个非常简单的 application,其目录结构及文件名称如下所示:

packagedemo
├── setup.py
├── setup.cfg
├── README.rst
├── MANIFEST.in
└── packagedemo
    ├── __init__.py
    └── main.py

从上可知,packagedemo 的根目录必须包含四个基本文件:

  • setup.py: 最为重要的文件,包含了打包的参数和基本信息,详细介绍请见下节
  • setup.cfg: setup.py 的配置文件,其格式为 INI
  • README.rst: reStructuredText 格式的文件,用于介绍项目
  • MANIFEST.in: 记录某些需要被打包但未被 setup.py 包含的文件,其格式和规范请见 The MANIFEST.in template

setup.py 文件内容请见下节。

setup.cfg 和 MANIFEST.in 在本例中均为空文件。

README.rst 文件的内容如下:

$ cat README.rst
===========
packagedemo
===========

This project provides a demo for packaging and distributing python application.

packagedemo/__init__.py 为空文件,packagedemo/main.py 文件的内容如下:

$ cat packagedemo/main.py
def main():
    print("A demo for python package.")

Setup.py

setup.py 有两个非常重要的函数:

  • setup(): 该函数囊括了打包的参数和信息
  • 打包命令的入口: python setup.py –help 可以查看可用的命令

本例 setup.py 文件的内容如下:

import os

import setuptools


setuptools.setup(
    name='packagedemo',
    version='2015.09.1',
    keywords='demo',
    description='A demo for python packaging.',
    long_description=open(
        os.path.join(
            os.path.dirname(__file__),
            'README.rst'
        )
    ).read(),
    author='vanderliang',
    author_email='vanderliang@gmail.com',
    
    url='https://github.com/DeliangFan/packagedemo',
    packages=setuptools.find_packages(),
    license='MIT'
)
  • name: 即项目名称,本例为 packagedemo
  • version: 即版本号,关于版本号的取法请见 Choosing a versioning scheme
  • keywords: 描述项目的关键字
  • description: 项目简介
  • long_description: 项目详细介绍
  • author: 作者名称
  • author_email: 作者邮箱
  • url: 项目的 homepage
  • packages: 项目包括的 python package,setuptools.find_packages() 可自动找出包含的 package
  • license: 如 MIT, APACHE, GNU 等

本例暂未用到如下参数,这些参数的使用请见下篇

  • classifiers:
  • install_requires:
  • package_data:
  • data_files:
  • scripts:
  • entry_points
  • console_scripts:

Build your Package

采用 pip 可安装 source distribution(sdist) 和 wheels 这两种格式 python package,如果二者同时存在,pip 优选选择 wheel。

Source Distribution

采用如下命令即可编译成 source distribution:

$ python setup.py sdist
running sdist
running egg_info
creating packagedemo.egg-info
writing packagedemo.egg-info/PKG-INFO
...
creating dist
Creating tar archive
removing 'packagedemo-2015.09.1' (and everything under it)

$ ls dist/
packagedemo-2015.09.1.tar.gz

Wheel

根据 application 包含的代码类型以及其所支持的 python 版本, wheel 格式可细分为三种

采用如下命令可编译成 universal wheel

$ python setup.py bdist_wheel --universal
running bdist_wheel
running build
installing to build/bdist.macosx-10.10-intel/wheel
......
running install_scripts
creating build/bdist.macosx-10.10-intel/wheel/packagedemo-2015.09.1.dist-info/WHEEL

$ ls dist
packagedemo-2015.09.1-py2-none-any.whl

采用如下命令可编译成非 universal wheel(即 pure python wheel 或 platform wheel):

$ python setup.py bdist_wheel
running bdist_wheel
running build
installing to build/bdist.macosx-10.10-intel/wheel
......
running install_scripts
creating build/bdist.macosx-10.10-intel/wheel/packagedemo-2015.09.1.dist-info/WHEEL

$ ls dist
packagedemo-2015.09.1-py2.py3-none-any.whl

Others

Python application 还可以被编译成其它类型的 package,如 rpm, egg 等,只是这些类型的 package 不被 pip 支持。

+---------------+--------------------------------------------------------+
| bdist         | create a built (binary) distribution                   |
| bdist_dumb    | create a "dumb" built distribution                     |
| bdist_rpm     | create an RPM distribution                             |
| bdist_wininst | create an executable installer for MS Windows          |
| bdist_egg     | create an "egg" distribution                           |
+---------------+--------------------------------------------------------+

Uploading your Project to PyPI

安装 twine,用于上传打包好的 package 至 Pypi:

$ pip install twine

1 . 在 Pypi 创建一个账户。

2 . 把 packagedemo.egg-info/PKG-INFO 上传至 Pypi submit,用于注册该项目。

$ cat packagedemo.egg-info/PKG-INFO
Metadata-Version: 1.0
Name: packagedemo
Version: 2015.09.1
Summary: A demo for python packaging.
Home-page: https://github.com/DeliangFan/packagedemo
Author: vanderliang
Author-email: vanderliang@gmail.com
License: MIT
Description: ===========
        packagedemo
        ===========

        This project provides a demo for packaging and distributing python application.

Keywords: demo
Platform: UNKNOWN

3 . 上传至 Pypi:

创建如下配置文件 ~/.pypirc:

[distutils]
index-servers=pypi

[pypi]
repository = https://pypi.python.org/pypi
username = <username>
password = <password>

上传 package:

$ twine upload dist/*
Uploading distributions to https://pypi.python.org/pypi
Uploading packagedemo-2015.09.1-py2-none-any.whl
Uploading packagedemo-2015.09.1-py2.py3-none-any.whl
Uploading packagedemo-2015.09.1.tar.gz

Test

$ pip install packagedemo
Downloading/unpacking packagedemo
  Downloading packagedemo-2015.09.1-py2.py3-none-any.whl
Installing collected packages: packagedemo
Successfully installed packagedemo
Cleaning up...

packagedemo