概述
我们都知道,Python 最强大的优势之一就是拥有着强大的生态支持。在软件开发的各个领域中,你往往都能找到对应需求的 Python 第三方库来满足的你的需求,从而帮助你实现项目的快速开发。而这些丰富而又强大的第三方库其实就是不同开发者开发的 Pip 包了(Python库)。
在本文中,我们将从一个 helloworld 项目开始,并不断丰富,演示如果从零开始制作一个属于自己的 Python 库。同时,在这一过程中,我们也会针对 pip 包制作过程中的一些核心功能点进行展开说明讲解。
QuickStart
首先,我们以一个非常简单的项目 HelloWorld 项目为例来进行演示。
在本地创建一个如下的目录:
/packaging_tutorial
/helloworld_pkg
__init__.py
在创建完成上述目录结构后,后续我们所有的操作都将会在 packaging_tutorial 目录下执行。
编写项目代码
首先,我们来编辑一下 helloworldpkg/_init.py 文件,修改如下:
name = "helloworld_pkg"
可以看到,在这个 HelloWorld 的项目包中,我们仅仅提供了一个变量 name ,它对应的值为 helloworld_pkg 。
接下来,我们将围绕这个如此简单的功能,来演示一下如何将上述文件转化为一个 pip 包。
创建包依赖文件
接下来,我们需要做的就是创建一个Pip包必需的文件并将我们的项目代码转化为一个包。
需要在 packaging_tutorial 目录下依次创建:setup.py、setup.cfg、LICENSE 和 README.md 文件。
其中:
- LICENSE 表示开源许可证,这告诉用户安装你的软件包可以使用您的软件包的条款。此处不多做介绍,可以自行搜索了解。
- README.md 中是一个 markdown 的说明文档,主要用于描述你的 Python 包的基本功能和相关使用介绍,你可以根据项目功能自行编写,此处也不再展开。
接下来,我们来重点说明一下 setup.py 和 setup.cfg 文件,setup.py 是 Pip 包构建过程中的核心文件,是 setuptools 的构建脚本,它描述了整个 Pip 包构建的依赖、部署等相关过程,而 setup.cfg 则是 setup.py 依赖的配置文件,其中一些基本配置可以直接在 setup.cfg 中编写,并在 setup.py 中加载对应配置即可。
setup.py
我们先从一个最简单的 setup.py 开始看起:
import setuptools
setuptools.setup()
在一个最简单的 setup.py 文件只需要两行代码即可,首先引入 setuptools ,然后执行 setuptools.setup() 函数,通过加载默认的 setup.cfg 配置文件来执行对应的打包操作。
setup.cfg
同样,我们还是从一个最基本的 setup.cfg 配置文件开始看起:
[metadata]
name = helloworld-pkg-0912
version = 0.1.0
author = Wangzhe0912
author_email = wangzhe0912@tju.edu.cn
description = Wangzhe0912 HelloWorld Demo
long_description = file: README.md
long_description_content_type = text/markdown
url = https://www.missshi.cn/helloworld-pkg-0912
license = MIT
classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
可以看到,在 setup.cfg 中,至少应该包含一个 metadata 块。
在 metadata 块中,应该包含如下字段:
- name:第三方库的名称,需要保证全平台的唯一性,否则会导致名称冲突,可以包含字母、数字和-号。
- version:版本号。
- author:包作者。
- author_email:包作者的邮箱地址。
- description:关于该第三方库的简短描述。
- long_description:关于该第三方库的完整描述,可以是文件格式,例如:file: README.md。
- long_description_content_type:说明第三方库完整描述文件的格式。
- url:关于第三方包相关介绍的地址。
- license:开源许可协议说明。
classifiers:其他一些描述性的元信息,例如支持哪些 Python 版本等。
制作依赖包
帮我们准备好制作包需要的所有依赖和包的文件后,下一步就可以开始制作依赖包了。
首先,确保你本地已经安装了最新版本的 setuptools 和 wheel 包:python3 -m pip install --user --upgrade setuptools wheel
接下来,可以进入 packaging_tutorial 目录下执行如下命令:
python3 setup.py sdist bdist_wheel
执行完成后,你将会看到如下几个新增的目录:
helloworld_pkg_0912.egg-info
- build
- dist
其中,我们重点关注 disk 目录,其中应该包含了如下两个文件:
- helloworld-pkg-0912-0.1.0.tar.gz 制作好的 tgz 格式的压缩包。
- helloworld_pkg_0912-0.1.0-py3-none-any.whl 制作好的 whl 格式的压缩包。
上传到 pypi 仓库
下面,我们就可以把制作好的部署包上传到 Python Package Index了!
出于我们当前的包仅仅是学习的考虑,没有什么实际的价值,因此,我们可以将我们制作好的部署包发布到 Test Pypi 的源上,没不是正式的 Pypi 的源。当然,二者的发布流程基本一致,当你的包真正能够产生实际价值的时候,就可以把你的包发布到正式 PyPI 源了。
首先,你需要一个 Test Pypi 的账号,可以在该地址进行注册:https://test.pypi.org/account/register/ 。
你需要填写相关的信息并且完成邮箱验证后,才能正常上传自己的包。
下面,你需要通过安装 twine 来用于上传你自己的第三方包,安装方式也很简单:
python3 -m pip install --user --upgrade twine
安装完成后,你可以再次进入 packaging_tutorial 目录,通过运行 Twine 来上传我们制作好的 dist 目录下的包:
python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
# Uploading distributions to https://test.pypi.org/legacy/
# Enter your username: wangzhe0912
# Enter your password:
# Uploading helloworld_pkg_0912-0.1.0-py3-none-any.whl
# 100%|█████████████████████████████████████████████████████████████████████████████████████████████| 5.68k/5.68k [00:02<00:00, 2.33kB/s]
# Uploading helloworld-pkg-0912-0.1.0.tar.gz
# 100%|█████████████████████████████████████████████████████████████████████████████████████████████| 5.36k/5.36k [00:01<00:00, 3.31kB/s]
# View at:
# https://test.pypi.org/project/helloworld-pkg-0912/0.1.0/
输入上述命令后,系统会交互式的提示输入Test PyPI注册的用户名和密码。命令完成后,您应该看到与此类似上述的输出提示包上传成功。
访问对应的 url:https://test.pypi.org/project/helloworld-pkg-0912/0.1.0/
你就已经可以看到你自己的包已经成功上传了。
安装验证一下吧
QuickStart的最后一步了!我们来安装一下我们刚刚上传的部署包并且验证一下看看吧:
pip3 install -i https://test.pypi.org/simple/ helloworld-pkg-0912==0.1.0
然后进入 Python 交互式命令行看看:
import helloworld_pkg
print(helloworld_pkg.name)
# helloworld_pkg
可以看到,我们的安装包已经成功安装并且能够正常使用了!