Python application 的打包和发布——(上)
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 Distributions(sdist): 即源码包
- 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 代码,并且支持 python 2 和 3
- Pure python wheel: 纯 python 代码,不同时支持 python2 和 3
- Platform wheel: 非纯 python 代码
采用如下命令可编译成 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...