0%

开发Python库并发布到PyPI指南

PyPI

PyPI(英语:Python Package Index,简称PyPI)是一个用于存储Python写成的软件包的软件存储库,我们平时用pip安装的库就是来自于PyPI

而且,通过PyPI我们可以把自己写的库代码分享给别人,这也是开源的乐趣之一。

用到的库代码

1
2
3
4
5
├── MANIFEST.in
├── README.md
├── dingtalk_log_handler
│   ├── __init__.py
├── setup.py

整体代码结构,其中dingtalk_log_handler是我写的一个用于发日志到钉钉群的库,也是这次要发布的库。

先看下库的主体代码dingtalk_log_handler/__init__.py, 由于功能比较简单,逻辑就都写在__init__.py里了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64
# 其他import略去

__author__ = 'ruan.lj'
__version__ = '0.0.2'
__all__ = (
'OAPI_DOMAIN',
'DingTalkHandler',
)

OAPI_DOMAIN = 'oapi.dingtalk.com' # dingtalk open api domain

class DingdingApiError(RuntimeError):
pass

class DingTalkHandler(logging.Handler):
"""Handler for logging message to dingtalk"""
pass
# 略去逻辑代码

编写 setup.py

setup.py指引了打包工具如何打包我们的库,功能与类似Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from setuptools import setup, find_packages
from dingtalk_log_handler import __author__, __version__

# read the contents of your README file
from os import path
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()

setup(
name='dingtalk-log-handler',
version=__version__,
author=__author__,
author_email='xxx@foxmail.com',
description='log handler for send message to dingtalk',
long_description=long_description,
long_description_content_type='text/markdown',
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Topic :: Software Development :: Libraries',
'Programming Language :: Python :: 3',
# 省略一下
],
packages=find_packages(),
python_requires='>=3.5',
install_requires=[],
project_urls={
'Source': 'https://github.com/ruanima/dingtalk-log-handler',
},
)

具体打包的功能由setuptools.setup函数实现,我们只需要修改对应的参数即可

这些参数影响打包的行为,以及在PyPI页面上显示的信息

主要的参数说明,详细信息参考文档

  • name: 库名,也就是pip install xxx时的名称
  • version: 版本,我们这里是复用了库代码里的版本号
  • author: 作者,同上
  • author_email: 作者邮箱
  • description: 库说明,在pip search xxx的时候可以看到
  • long_description: 库详细说明,显示在PyPI完整上,我们这里从README.md文件中读取具体内容
  • long_description: 库详细说明的格式,这里使用markdown
  • classifiers: 库的类别信息,所有可选值参考
  • packages: 库包含的python包,通过find_packages自动添加
  • py_modules: 库包含的顶级Python模块,我们这里没有
  • python_requires: 支持的Python版本
  • install_requires: 依赖的其他库,格式与pip freeze输出的格式相同
  • project_urls: 项目的一些链接信息,可选值列表

编写 MANIFEST.in

打包时默认只会包含包代码和一些必要的文件,见列表
如果要包含其他资源文件,必须编写MANIFEST.in来说明说明

MANIFEST.in

1
2
3
4
5
include README.md
recursive-include dingtalk_log_handler *
global-exclude __pycache__
global-exclude tmp
global-exclude *.py[co]

语法和shell的通配符语法类似

  • include <pattern> <pattern2> ...: 包含项目根目录匹配通配符的文件
  • recursive-include <dir-pattern> <pattern> <pattern2> ...: 递归地包含指定目录匹配通配符的文件
  • global-exclude <pattern> <pattern2> ...: 递归地排除匹配通配符的文件

打包

执行: python3 setup.py sdist bdist_wheel

输出文件

1
2
3
dist
├── dingtalk-log-handler-0.0.2.tar.gz
└── dingtalk_log_handler-0.0.2-py3-none-any.whl

上传

我们可以通过PyPI的测试站点 来练习库文件的上传,并测试效果

  1. 注册账户
  2. 安装上传工具:pip install twine -U
  3. 上传文件:twine upload --repository testpypi dist/*

熟悉流程之后,就可以换成正式站点,指定正式仓库(—repository pypi)上传文件

这样全世界的人都能看到你的库了。

效果

可以在这里找到我这次上传的库

可以看到 setup.py 文件里的很多信息会对应体现在PyPI网页上

参考

  1. https://packaging.python.org/guides/distributing-packages-using-setuptools
  2. https://packaging.python.org/guides/using-manifest-in/