Skip to content

Python 打包发布

创建 Python 项目

项目结构

假如包名为 expkg,则项目结构形如:

sh
working_dir/
├── CHANGELOG.md
├── LICENSE
├── README.md
├── pyproject.toml
├── src/
   └── expkg/
       ├── __init__.py
       └── example.py
└── tests/

pyproject.toml

pyproject.toml 形如:

toml
[project]
name = "expkg"
version = "0.0.1"
authors = [
    { name="<author>" },
]
description = "This is an example package."
readme = "README.md"
requires-python = ">=3.6"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]
dependencies = [ ]

[project.urls]
Homepage = "https://github.com/<author>/expkg"
Issues = "https://github.com/<author>/expkg/issues"
Changelog = "https://github.com/<author>/expkg/blob/main/CHANGELOG.md"

LICENSE

以 MIT 为例,LICENSE 文件形如:

txt
Copyright (c) 2024 <author>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

打包项目

安装依赖

安装和升级 pipbuildtwine

sh
pip install --upgrade pip build twine

构建包

sh
python -m build

若成功,输出形如:

sh
Successfully built expkg-0.0.1.tar.gz and expkg-0.0.1-py3-none-any.whl

会新建下面高亮的文件夹和文件:

sh
working_dir/
├── dist/
   ├── expkg-0.0.1-py3-none-any.whl
   └── expkg-0.0.1.tar.gz
├── src/
   ├── expkg.egg-info/
   ├── expkg/
   └── ...
└── ...

上传 PyPI

创建账户

注册TestPyPi PyPi

  • 需要验证邮箱,并配置 2FA 认证
  • 需保存 Recovery codes
  • 生成新的 API token

国内用户可能需要代理以正常显示 reCaptcha。

配置 twine 的 token

在用户 home 目录下创建 .pypirc,添加内容如下:

sh
[testpypi]
  username = __token__
  password = pypi-...

[pypi]
  username = __token__
  password = pypi-...

使用 twine 上传包

sh
# TestPyPI
twine upload --repository testpypi dist/*
# PyPI
twine upload dist/*
twine upload dist/* --skip-existing

开发和测试包

安装包

本地安装(适用于开发过程中):

sh
# run in expkg root path
pip install -e .

从 PyPI 安装:

sh
# TestPyPI
pip install --index-url https://test.pypi.org/simple/ --no-deps expkg
# PyPI
pip install --no-deps expkg
# pip install --no-deps --upgrade -i https://pypi.python.org/simple/ expkg

测试包

sh
python
>>> from expkg import example
>>> example.hello()

一键构建和上传

sh
python -m build && twine upload dist/* --skip-existing
sh
# pip install -e .
pip install --upgrade expkg --no-cache-dir

利用 GitHub Actions 自动发布

.github/workflows 中创建 publish_pypi.yml,内容如下:

yml
name: Build package and publish to PyPI
on:
  push:
    paths:
      - "pyproject.toml"
  workflow_dispatch:

concurrency:
  group: pypi
  cancel-in-progress: true

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.9"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip build twine

      - name: Build and publish
        run: |
          python -m build
          python -m twine upload dist/* --skip-existing
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}