3.4.2 创建项目

原文链接: https://docs.astral.sh/uv/concepts/projects/init/

3.4.2 创建项目

uv 支持用 uv init 创建项目。

创建项目时,uv 支持两种基本模板:应用和库。默认情况下 uv 会创建应用项目。使用 --lib 标志可以改为创建库项目。

在两种情况下,uv 都倾向于定义构建系统,并把源文件放在专用的 src/<project_name>/ 目录中。定义构建系统可以使用各种 Python 打包特性,例如添加命令行入口点,并避免 Python 导入系统中常见的困惑。可以通过 --no-package 或 --bare 选项禁用构建系统。

注意

在 v0.12 之前,uv 默认不为应用定义构建系统。

目标目录

uv 会在工作目录中创建项目;如果提供了名称,则在目标目录中创建,例如 uv init foo。可以用 --directory 选项修改工作目录,目标目录路径会相对于指定的工作目录解释。如果目标目录中已有项目(即已存在 pyproject.toml),uv 会报错退出。

应用

应用项目适合 Web 服务器、脚本和命令行接口。

应用是 uv init 的默认目标,也可以用 --app 标志显式指定:

1
$ uv init example-app

源代码位于 src 目录中,其中包含模块目录和 __init__.py 文件:

1
2
3
4
5
6
7
8
$ tree example-app
example-app/
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_app
        └── __init__.py

由于定义了构建系统,项目会被安装到环境中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# pyproject.toml
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-app = "example_app:main"

[build-system]
requires = ["uv_build>=0.12.19,<0.13"]
build-backend = "uv_build"

提示

可以用 --build-backend 选项请求替代的构建系统。

其中包含一个命令定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# pyproject.toml
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-app = "example_app:main"

[build-system]
requires = ["uv_build>=0.12.19,<0.13"]
build-backend = "uv_build"

该命令可以用 uv run 执行:

1
2
3
$ cd example-app
$ uv run example-app
Hello from example-app!

库

库为其他项目提供函数和对象。库的用途是被构建和分发,例如上传到 PyPI。

使用 --lib 标志可以创建库:

1
$ uv init --lib example-lib

注意

库始终需要是打包的项目。

其中包含 py.typed 标记,用于告知使用者可以从该库读取类型信息:

1
2
3
4
5
6
7
8
9
$ tree example-lib
example-lib/
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_lib
        ├── py.typed
        └── __init__.py

注意

开发库时 src 布局尤其有价值。它确保库与项目根目录中的任何 python 调用隔离,并使分发出去的库代码与项目其余源码良好分离。

由于定义了构建系统,项目会被安装到环境中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# pyproject.toml
[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[build-system]
requires = ["uv_build>=0.12.19,<0.13"]
build-backend = "uv_build"

提示

可以把 --build-backend 与 hatchling、uv_build、flit-core、pdm-backend、setuptools、maturin 或 scikit-build-core 搭配使用,以选择不同的构建后端模板。如果你想创建带扩展模块的库,则必须使用替代后端。

创建的模块定义了一个简单的 API 函数:

1
2
3
# __init__.py
def hello() -> str:
    return "Hello from example-lib!"

你可以用 uv run 导入并执行它:

1
2
3
$ cd example-lib
$ uv run python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!

带扩展模块的项目

大多数 Python 项目是“纯 Python”的,也就是说它们不定义 C、C++、FORTRAN 或 Rust 等其他语言的模块。不过,带扩展模块的项目常用于性能敏感的代码。

创建带扩展模块的项目需要选择替代构建系统。uv 支持用以下支持扩展模块的构建系统创建项目:

用 --build-backend 标志指定构建系统:

1
$ uv init --build-backend maturin example-ext

注意

使用 --build-backend 隐含 --package。

除了典型的 Python 项目文件之外,该项目还包含 Cargo.toml 和 lib.rs 文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ tree example-ext
example-ext/
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
    ├── lib.rs
    └── example_ext
        ├── __init__.py
        └── _core.pyi

注意

如果使用 scikit-build-core,你会看到 CMake 配置和一个 main.cpp 文件。

Rust 库定义了一个简单的函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// src/lib.rs
use pyo3::prelude::*;

#[pymodule]
mod _core {
    use pyo3::prelude::*;

    #[pyfunction]
    fn hello_from_bin() -> String {
        "Hello from example-ext!".to_string()
    }
}

Python 模块导入它:

1
2
3
4
5
6
# src/example_ext/__init__.py
from example_ext._core import hello_from_bin


def main() -> None:
    print(hello_from_bin())

该命令可以用 uv run 执行:

1
2
3
$ cd example-ext
$ uv run example-ext
Hello from example-ext!

重要

使用 maturin 或 scikit-build-core 创建项目时,uv 会把 tool.uv.cache-keys 配置为包含常见源文件类型。要强制重新构建(例如修改了 cache-keys 之外的文件,或未使用 cache-keys 时),请使用 --reinstall。

创建不带构建系统的项目

虽然定义构建系统通常能带来更好的体验,但在某些情况下,省略它并直接在顶层目录定义 Python 模块会更简单。

使用 --no-package 标志禁用构建系统:

1
$ uv init --no-package example-app

该项目包含 pyproject.toml、示例文件(main.py)、readme 和 Python 版本固定文件(.python-version)。

1
2
3
4
5
6
$ tree example-app
example-app/
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

pyproject.toml 包含基本元数据。它不包含构建系统,也不是包,不会被安装到环境中:

1
2
3
4
5
6
7
8
# pyproject.toml
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

示例文件定义了一个带有一些标准样板代码的 main 函数:

1
2
3
4
5
6
7
# main.py
def main():
    print("Hello from example-app!")


if __name__ == "__main__":
    main()

Python 文件可以用 uv run 执行:

1
2
3
$ cd example-app
$ uv run main.py
Hello from example-app!

创建最小项目

如果你只想创建 pyproject.toml,请使用 --bare 选项:

1
$ uv init example-bare --bare

uv 会跳过创建 Python 版本固定文件、README 以及任何源码目录或文件。此外,uv 不会初始化版本控制系统(即 git)。

1
2
3
$ tree example-bare
example-bare
└── pyproject.toml

uv 也不会向 pyproject.toml 添加额外元数据,例如 description 或 authors。

1
2
3
4
5
[project]
name = "example-bare"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []

--bare 选项可以与其他选项(例如 --lib 或 --build-backend)一起使用 —— 在这些情况下 uv 仍会配置构建系统,但不会创建预期的文件结构。

使用 --bare 时,仍可以选择启用额外特性:

1
$ uv init example-bare --bare --description "Hello world" --author-from git --vcs git --pin-python
最后修改 September 25, 2026: 更新 (221c74c33)