uv — 快速 Python 套件與專案管理工具 是做什麼的?
概述
uv 是 Astral 公司開發的單一二進位檔,涵蓋整個 Python 工作流程:支援跨平台鎖定檔 (uv.lock) 的專案、內聯相依性的單檔指令碼、命令列工具 (uvx)、Python 直譯器安裝,以及無縫接軌的 uv pip 介面。它能在需要時自動下載 Python 本身,因此機器上只需安裝 uv 即可。
使用說明
安裝
# 套件管理器
pipx install uv
brew install uv
winget install --id=astral-sh.uv -e
Astral 也為沒有套件管理器的機器提供獨立安裝程式;安裝頁面 https://docs.astral.sh/uv/getting-started/installation/ 包含最新指令與校驗和。
uv --version
uv self update # 僅限獨立安裝程式;否則請使用套件管理器升級
若要鎖定特定版本,請將版本號放入安裝程式 URL:https://astral.sh/uv/0.12.21/install.sh。
建立專案
uv init dispatch-api # 打包應用程式:src/dispatch_api/、uv_build 後端、主控台腳本
uv init --no-package cron-jobs # 平坦佈局,包含 main.py,無建置系統
uv init --lib geo-utils # 函式庫,附帶 py.typed 標記
uv init --bare --python 3.12 # 僅 pyproject.toml,位於當前目錄
uv init 也會寫入 .python-version、README.md、.gitignore 並初始化 git。--bare 僅寫入 pyproject.toml,因此它是現有倉庫內的最佳選擇。
管理相依性
uv add 'httpx>=0.27' 'pydantic>=2.7,<3' # 執行期相依性
uv add --dev pytest ruff # 開發群組,不部署到正式環境
uv add --group docs mkdocs # 任意命名的相依群組
uv add --optional postgres 'psycopg[binary]' # 額外套件:pip install dispatch-api[postgres]
uv add -r requirements.txt # 匯入現有的 requirements 檔案
uv remove httpy
uv lock --upgrade-package pydantic # 在其限制範圍內升級一個套件
uv lock --upgrade # 升級所有套件
uv tree --outdated --depth 1 # 顯示哪些套件有新版本
第一次執行 uv add 會建立 .venv/ 與 uv.lock。每次變更都會同步更新 pyproject.toml、鎖定檔與環境。
執行與同步
uv run pytest # 必要時鎖定並同步,然後在 .venv 中執行
uv run python -m dispatch_api
uv run --with rich python -c "import rich" # 僅為此命令額外加入一個套件
uv sync # 安裝所有套件,包含開發群組
uv sync --locked # CI:若 uv.lock 與 pyproject.toml 不符則失敗
uv sync --frozen --no-dev # 正式環境:直接使用 uv.lock,略過開發群組
uv sync --extra postgres
uv lock --check # 當鎖定檔過期時回傳非零值
無需啟用虛擬環境;uv run 會自行尋找專案環境。
內聯相依性的指令碼
uv init --script fetch-rates.py --python 3.12
uv add --script fetch-rates.py 'httpx<1' rich
uv run fetch-rates.py
uv lock --script fetch-rates.py # 寫入 fetch-rates.py.lock 以達可重複執行
uv add --script 會在檔案頂端維護一個中繼資料區塊:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "httpx<1",
# "rich>=15.0.0",
# ]
# ///
加入 #!/usr/bin/env -S uv run --script 作為第一行,並執行 chmod +x 該檔案,即可直接執行。
工具
uvx ruff check . # 不安裝直接執行;uvx = uv tool run
uvx [email protected] check . # 指定版本
uvx --from 'markitdown[pdf]' markitdown q3-board-report.pdf # 命令名稱與套件名稱不同
uv tool install ruff # 永久安裝,隔離於 PATH 上
uv tool upgrade --all
uv tool list
uv tool uninstall ruff
已安裝的工具會放在 uv tool dir --bin 顯示的目錄中;若該目錄不在 PATH 上,uv 會發出警告。
Python 版本
uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12 # 寫入 .python-version
uv run --python 3.13 pytest # 使用其他直譯器的一次性執行
uv python upgrade 3.12 # 3.12 的最新修補版本
uv venv --python 3.12 # 在 .venv 建立單純的虛擬環境
版本請求可接受 3.12、3.12.3、>=3.11,<3.13、[email protected] 與 3.13t (自由執行緒)。uv 會自動下載遺失的直譯器;傳入 --no-python-downloads 可禁止此行為。
pip 相容介面
uv venv
uv pip install -r requirements.txt
uv pip compile requirements.in -o requirements.txt --universal
uv pip sync requirements.txt # 移除未列出的所有套件
uv pip install --python .venv/bin/python 'rich>=13'
CI 與 Docker
name: ci
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.12.21"
enable-cache: true
- run: uv python install
- run: uv sync --locked --all-extras --dev
- run: uv run pytest
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:0.12.21 /uv /uvx /bin/
WORKDIR /app
ENV UV_NO_DEV=1 UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
# 先安裝相依性,讓此層重複使用直到 uv.lock 變更
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "dispatch_api"]
將 .venv 加入 .dockerignore;主機環境無法在映像檔內運作。
範例
範例 1:將使用 requirements.txt 的服務遷移至具有鎖定檔的 uv 專案
需求:「我們的 dispatch-api 倉庫有 requirements.txt 與 requirements-dev.txt。將其遷移至 uv 並帶有鎖定檔,且讓測試能夠執行。」
cd dispatch-api
uv init --bare --python 3.12
uv python pin 3.12
uv add -r requirements.txt
sed '/^-r /d' requirements-dev.txt | uv add --dev -r -
uv run python -m pytest -q
uv run ruff check .
結果: pyproject.toml 列出五個執行期套件與一個 dev 群組,uv.lock 鎖定 30 個套件,且檢查通過。縮減後的輸出:
Initialized project `dispatch-api`
Pinned `.python-version` to `3.12`
+ uvicorn==0.34.0
+ pytest==8.3.4
+ ruff==0.8.6
1 passed, 1 warning in 0.12s
All checks passed!
範例 2:自包含指令碼
需求:「請撰寫一個磁碟用量報告指令碼,讓我可以複製到任何伺服器,無需設定環境即可執行。」
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["rich>=13"]
# ///
import shutil
from rich.console import Console
from rich.table import Table
usage = shutil.disk_usage("/")
table = Table(title="磁碟用量")
table.add_column("總計 GB")
table.add_column("可用 GB")
table.add_row(f"{usage.total / 1e9:.0f}", f"{usage.free / 1e9:.0f}")
Console().print(table)
chmod +x disk-report.py
./disk-report.py
結果: uv 在首次執行時建立一個帶有 rich 的快取環境,並列印表格;後續執行則立即啟動。
磁碟用量
┏━━━━━━━━━━┳━━━━━━━━━┓
┃ 總計 GB ┃ 可用 GB ┃
┡━━━━━━━━━━╇━━━━━━━━━┩
│ 3936 │ 2211 │
└──────────┴─────────┘
使用指南
- 提交
uv.lock與.python-version。 絕不手動編輯uv.lock;請修改pyproject.toml或使用uv add、uv remove與uv lock。 --locked或--frozen:--locked驗證鎖定檔,若過時則失敗,適用於 CI。--frozen跳過檢查,直接安裝檔案指定的內容。uv sync是精確的,uv run則否。uv sync會移除不在鎖定檔中的套件,包括任何透過uv pip install加入的項目。uv run只會補齊缺少的套件。uv pip透過探索決定目標: 活躍的VIRTUAL_ENV,然後是當前目錄或最近上層目錄中的.venv。從錯誤的資料夾執行會安裝到別人的環境中。在指令碼中請透過--python傳入環境路徑。- 平坦專案與 pytest: 使用
--bare或--no-package時,專案本身不會被安裝,因此uv run pytest可能因ModuleNotFoundError失敗。請使用uv run python -m pytest,或是在[tool.pytest.ini_options]下設定pythonpath = ["."]。 uv init預設採用打包的src/佈局。 對於腳本風格的專案,請傳入--no-package以產生main.py。- 實驗性命令:
uv format、uv check與uv audit會印出可能變更的警告。目前請勿將其納入管線。 - 私有索引: 在
[[tool.uv.index]]下宣告,並透過以索引名稱命名的環境變數傳遞憑證:例如對於名為internal的索引,使用UV_INDEX_INTERNAL_USERNAME與UV_INDEX_INTERNAL_PASSWORD。切勿提交這些憑證。預設的first-index策略可防止依賴混淆;請避免使用unsafe-best-match。 - 供應鏈安全:
uv run、uvx以及具有內聯中繼資料的指令碼會下載並執行套件。在執行前請審查任何來自不可信來源的指令碼的相依列表。 uv self update僅適用於透過獨立安裝程式安裝的情況。- CI 快取: 在儲存快取前執行
uv cache prune --ci以保持其精簡。 - 何時不該使用: uv 從 Python 套件索引、git 與本地路徑安裝。它不安裝 conda 套件或系統函式庫,因此對於依賴它們的技術棧請繼續使用 conda。