构建与发布
作为项目的最后一环,分发至关重要。有良好的分发流程,便于使用。基于 Python 自带的分发机制显然是 更好的选择。
本文将以一个数据导出的项目讲述。
1. 项目准备
因为本文的重点是对打包分发,所以项目的功能开发就不作为重点。
项目源代码可以在 pythonic-project-samples 中获取。
项目采用 src
目录结构,项目描述信息都在 pyproject.toml
中定义。
2. 项目打包
2.1 打包工具
由于历史原因, Python 的打包走了很长一段路了,但和其他语言的打包工具相比,未来还是有很长一段路要走。
在 PEP-517 中,提到了当前 Python 构建系统的不足和相应的解决方案。 其主要就是解决让 Python 支持更加灵活的构建系统。 PEP-518 则提出为项目指定一个最小的构建系统。
2.1.1 setuptools
Setuptools 是当前使用最为广泛的构建工具,现在绝大多数工具
都在使用 setuptools
构建项目。它是 disutils
的增强版。
Setuptools 可以说是现在最成熟的构建工具了,支持常用特性如下:
- 支持打包资源文件
- 支持打包数据文件
- 支持 CPython 编译器
- 支持 zip 压缩选项
- 支持包命名空间
- 支持安装依赖
- 支持可选安装依赖
- 支持指定 Python 版本
- 支持注册 Setuptools 子命令
- 支持入口点(Entry Points)
由于 Setuptools 是最成熟的构建工具,所以与其它构建工具对比来看,它的缺点可能就是现在的配置仍需要定义在 setup.cfg
或者 setup.py
文件中,而不是定义在 pyproject.toml
文件中。
缺点:
- 不支持在
pyproject.toml
中定义配置 - 不支持发布,需要配合
twine
。
2.1.1.1 示例配置
pyproject.toml :
增加 setup.py
或者 setup.cfg
两种有其一即可。然后在文件中定义配置。
推荐使用 setup.cfg
。
此时你的项目结构应在是这样的:
2.1.1.2 通用方式构建
安装 PEP-517 规范的包生成器 build 和 setuptools,pip install build setuptools
。
然后开始构建 python -m build wheel
。
2.1.1.3 Setuptools 构建
此方法是在不安装 build 的情况下使用的。
如果你只是用了 setup.cfg
配置的情况下,你还需要增加一个 setup.py
文件,内容如下:
setup.py :
如果你仅使用了 setup.py
配置 Setuptools 的话,可以不需要 setup.cfg
文件。
安装依赖 pip install setuptools
,然后进行构建 python setup.py bdist_wheel
。
2.1.1.4 twine 发布
由于 setuptools 不支持发布功能,所以需要借助其他工具将包发布中央仓库。
Twine 是 Pypa 团队维护的一个将 Python 包发布到 Pypi 的工具。
安装依赖: pip install twine
。
使用 Setuptools 构建项目,构建结果默认是放在项目根目录的 ./dist
下面 。
发布项目到 Pypi :
2.1.2 flit
Flit 是一个轻量简单的 Python 构建工具,它的出现也可以说是划时代的,因为它的出现促进了新标准的发现, 如 PEP-517 和 PEP-518 。
Flit
具有如下特点:
- 简单轻量
- 支持发布
- 支持打包数据文件
- 支持子包
- 支持复制构建
- 支持安装依赖
- 支持可选安装依赖
- 支持指定 Python 版本
- 支持注册 Flit 子命令
- 支持入口点(Entry Points)
- 支持
pyproject.toml
文件定义配置
缺点:
- 不支持 CPython 编译
- 不支持 zip 压缩选项
2.1.2.1 示例配置
pyproject.toml :
[build-system]
requires = ["flit_core >=2,<4"]
build-backend = "flit_core.buildapi"
[tool.flit.metadata]
module = "foobar"
author = "Sir Robin"
author-email = "robin@camelot.uk"
home-page = "https://github.com/sirrobin/foobar"
2.1.2.2 通用方式构建
安装 PEP-517 规范的包生成器 build 和 flit ,pip install build flit
。
然后开始构建 python -m build wheel
。
2.1.2.3 flit 构建
此方法是在不安装 build 的情况下使用的。
安装依赖: pip install flit
,然后进行构建 flit build --format wheel
。
2.1.2.4 flit 发布
flit
的发布命令会自行先构建 wheel
和 sdist
包,然后上传到 Pypi 或者其他仓库。
2.1.3 poetry
python-poetry 是一个更高级的工具。它是一个构建工具的同时也是一个依赖管理工具。 在构建上,同样遵循了 PEP-517 规范,在依赖管理上,有点类似于 Pipenv 。
python-poetry 具有如下特点:
- 支持环境管理
- 支持发布
- 支持 shell 插件,如
bash
、Fish
、Zsh
- 支持打包数据文件
- 支持注册 poetry 子命令
- 支持 Setuptools 的入口点(Entry Points)
- 支持包命名空间
- 支持安装依赖
- 支持可选安装依赖
- 支持在
pyproject.toml
中定义配置
缺点:
- 不支持 CPython 编译
- 不支持 zip 压缩选项
2.1.3.1 示例配置
[build-system]
requires = ["poetry_core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["Sébastien Eustace <sebastien@eustace.io>"]
[tool.poetry.dependencies]
python = "^3.10"
[tool.poetry.dev-dependencies]
pytest = "^3.4"
2.2 打包构建(poetry)
现阶段选用 poetry
作为构建工具。
为项目指定所需要使用的构建工具。创建 pyproject.toml
文件,增加如下内容:
[tool.poetry]
name = "file2mongo"
version = "0.1.0"
description = "File data to MongoDB"
readme = "README.md"
authors = ["demo <demo@example.com>"]
license = "MIT"
classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.10",
]
[tool.poetry.dependencies]
python = "^3.10"
dynaconf = "^3.1.9"
click = "^8.1.3"
pymongo = "^4.3.3"
[tool.poetry.dev-dependencies]
pylint = "^2.14.5"
isort = "^5.10.1"
pytest = "^7.1.2"
mkdocs = "^1.3.1"
mkdocs-material = "^8.4.1"
[tool.poetry.plugins."scripts"]
file2mongo = "file2mongo.cmdline:main"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
2.2.1 项目基本信息
tool.poetry 是项目基本描述信息,有项目名称,版本号,作者相关信息等。
为了让别人更精准的获取你的包的信息,应该尽量包含如下:
name
: 项目名称。必需字段version
: 版本号。必需字段description
: 项目简短描述。必需字段license
: 许可证。可选字段,建议添加author
: 项目作者。必需字段maintainers
: 维护者。这是一个维护者列表,应该与作者区分开来。 可能包含一个电子邮件,格式为name <email>
。可选字段readme
: 项目的 README 文件或相对应的路径或路径列表。可选字段homepage
: 项目网站的 URL。可选字段keywords
: 项目关键字,有助于模糊搜索匹配。可选字段
2.2.2 options
此节点内容虽然为可选,但为了项目的完整性,有些内容还是需要的。
tool.poetry.dependencies
: 项目使用过程中依赖的包tool.poetry.scripts
: 安装包时将安装的脚本或可执行文件tool.poetry.extras
:可选依赖项,增强包,但不是必需的,可选依赖项的集群。tool.poetry.plugins
: 插件,可通过importlib.metadata
导入tool.poetry.urls
: 自定义 url,发布 pypi 后展示build-system
: 构建系统引用部分
2.2.2.1 入口点 EntryPoints
Entry-points 可以很方便的注册命令行脚本,或者提供一种插件加载机制。
注册命令行 :
例如,要创建名为 foo
的控制台脚本,pyproject.toml
文件添加如下示例:
2.2.3 构建
当配置完成后,就可以开始构建了。
运行命令:
运行完成后,会在项目根目录的 ./dist
中生成两个分发文件。一个是 .tar.gz
结尾的源码压缩包,一个是 .whl
结尾的二进制包。
3 分发
打包后的文件可以通过分发手段给其他人使用。
3.1 手动分发
手动分发,即自己管理这些软件包,如通过复制、 ftp
或者网络发送等方式。
使用时,下载所需要的版本分发包,然后使用 Pip 安装 pip install foo.whl
即可。
3.2 使用仓库分发
Python 所用公开包都存放在 Pypi ,当我们使用 pip install requests
的时候,默认会从 Pypi 中查找最新版本的分发包,找到了就先下载到本地,然后安装到环境中。除了官方仓库,还支持私有仓库。
要发布到 Pypi ,首先需要注册账号,如果是要测试,则可以使用测试仓库Test-Pypi 。对于私有仓库,可以参考具体文档poetry-publish,但使用方法基本一致, 只需要替换一下仓库地址。
上传到 Test-Pypi :
填写用户名和密码即可上传。
上传到 Pypi :