背景

开发了一个项目,需要打成pip包。

重要概念

pyproject.toml 就是“告诉 Python:这个项目叫什么、依赖什么、怎么打包、打完后生成什么”的配置文件。

步骤

1、目录结构

myproj/
  mypkg/
    __init__.py

2、准备project.toml

[project]
name = "mypkg"
version = "0.1.0"
description = "My package"
requires-python = ">=3.11"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["mypkg"]

3、准备构建工具。

python3 -m venv .pkgbuild
./.pkgbuild/bin/python -m ensurepip --upgrade
./.pkgbuild/bin/python -m pip install -U pip build hatchling -i https://pypi.tuna.tsinghua.edu.cn/simple

4、在项目根目录构建包
这里的“项目根目录”就是有 pyproject.toml 的目录

./.pkgbuild/bin/python -m build --no-isolation

最简模板

  1. 纯库包模板
    适合:别人 import mypkg,但没有命令行入口。

假设目录是:

myproj/
  pyproject.toml
  README.md
  mypkg/
    __init__.py

模板:

[project]
name = "mypkg"
version = "0.1.0"
description = "My Python package"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [
  { name = "your name" }
]
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["mypkg"]
  1. 带 CLI 的包模板
    适合:安装后能直接运行命令,比如mytool。

假设目录是:

myproj/
  pyproject.toml
  README.md
  mypkg/
    __init__.py
    cli.py

如果 cli.py 里有一个可调用入口,例如:

def main():
    print("hello")

那模板可以写成:

[project]
name = "mypkg"
version = "0.1.0"
description = "My command line tool"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [
  { name = "your name" }
]
dependencies = []

[project.scripts]
mypkg = "mypkg.cli:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["mypkg"]

这里最关键的是这句:

[project.scripts]
mypkg = "mypkg.cli:main"

意思是安装后可以直接运行 mypkg 命令,它会调用 mypkg/cli.py 里的 main()。

  1. 带资源文件的包模板
    适合:除了 Python 代码,还要把脚本、配置、jar、模板等文件一起打进包里。这个最接近你现在的。

假设目录是:

myproj/
  pyproject.toml
  README.md
  bridge/
    package.json
  softwares/
    tool.jar
  mypkg/
    __init__.py
    cli.py
    resources/
      config.json
    skills/
      demo/
        SKILL.md
        scripts/
          run.sh
          helper.py

模板:

[project]
name = "mypkg"
version = "0.1.0"
description = "My package with bundled resources"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [
  { name = "your name" }
]
dependencies = []

[project.scripts]
mypkg = "mypkg.cli:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["mypkg"]

[tool.hatch.build]
include = [
  "mypkg/**/*.py",
  "mypkg/**/*.md",
  "mypkg/**/*.sh",
  "mypkg/**/*.json",
]

[tool.hatch.build.targets.sdist]
include = [
  "mypkg/",
  "bridge/",
  "README.md",
]

artifacts = [
  "softwares/**",
]

[tool.hatch.build.targets.wheel.force-include]
"bridge" = "mypkg/bridge"
"softwares" = "mypkg/softwares"

这里最值得你记住的是:

include:选进正常资源
sdist.include:源码包里带什么
artifacts:专门处理像 softwares/ 这种可能被 .gitignore 忽略、但仍然要打包的内容
force-include:把包目录外的目录塞进最终 wheel

标签: none

评论已关闭