依赖脚本运行
当脚本需要其他包时,这些包必须安装到脚本运行的环境中。uv偏好按需创建环境,而不是使用手动管理依赖的长期虚拟环境。
例如,以下脚本需要rich
包:
import time
from rich.progress import track
for i in track(range(20), description="For example:"):
time.sleep(0.05)
不指定依赖直接执行会失败:
$ uv run --no-project example.py
Traceback (most recent call last):
File "/Users/astral/example.py", line 2, in <module>
from rich.progress import track
ModuleNotFoundError: No module named 'rich'
使用--with
选项请求依赖:
uv run --with rich example.py
如需特定版本,可以添加约束:
uv run --with "rich>=10.0" example.py
多个依赖可以重复使用--with
选项。
创建Python脚本
Python最近添加了内联脚本元数据(inline script metadata)的标准格式,允许选择Python版本和定义依赖。使用uv init --script
初始化带内联元数据的脚本:
uv init --script hello.py
声明脚本依赖
内联元数据格式允许在脚本本身中声明依赖。uv支持为你添加和更新内联脚本元数据。使用uv add --script
声明脚本依赖:
uv add --script example.py requests rich
这会在脚本顶部添加使用TOML格式的script
部分:
# /// script
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
import requests
from rich.pretty import pprint
resp = requests.get("https://peps.python.org/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])
uv会自动创建包含运行脚本所需依赖的环境:
$ uv run example.py
[
│ ('1', 'PEP Purpose and Guidelines'),
│ ('2', 'Procedure for Adding New Modules'),
│ ('3', 'Guidelines for Handling Bug Reports'),
│ ...
]
重要:使用内联脚本元数据时,即使在项目中使用uv run
,项目的依赖也会被忽略,无需--no-project
标志。
uv也尊重Python版本要求:
# /// script
# requires-python = ">=3.12"
# dependencies = []
# ///
# 使用Python 3.12新增的语法
type Point = tuple[float, float]
print(Point)
注意:即使为空,也必须提供dependencies
字段。
uv run
会搜索并使用所需的Python版本。如果未安装,Python版本会自动下载。
使用shebang创建可执行文件
可以添加shebang使脚本无需使用uv run
即可执行——这样便于运行PATH中或当前文件夹的脚本。
例如,创建名为greet
的文件:
#!/usr/bin/env uv run
print("Hello world")
确保脚本可执行(如chmod +x greet
),然后运行:
./greet
这种情况下也支持依赖声明:
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///
import httpx
print(httpx.get("https://example.com"))
使用替代包索引
如果要使用替代包索引(package index)解析依赖,可以使用--index
选项:
uv run --with httpx --index https://pypi.example.com/simple/ script.py
如果需要认证访问包索引,请参考包索引文档。
锁定依赖
uv支持使用uv.lock
文件格式为PEP 723脚本锁定依赖。与项目不同,脚本必须使用uv lock
显式锁定:
uv lock --script example.py
运行uv lock --script
会在脚本旁边创建.lock
文件(如example.py.lock
)。
锁定后,后续的uv run --script
、uv add --script
、uv export --script
和uv tree --script
操作会重用锁定的依赖,必要时更新锁文件。
提高可重现性
除了锁定依赖,uv还支持在内联脚本元数据的tool.uv
部分使用exclude-newer
字段,限制uv只考虑特定日期前发布的发行版。这有助于提高脚本在后续运行时的可重现性。
日期必须指定为RFC 3339时间戳(如2006-12-02T02:07:43Z
):
# /// script
# dependencies = [
# "requests",
# ]
# [tool.uv]
# exclude-newer = "2023-10-16T00:00:00Z"
# ///
import requests
print(requests.__version__)
使用不同Python版本
uv允许在每次脚本调用时请求任意Python版本:
uv run --python 3.11 script.py
uv run --python python3.12 script.py
使用GUI脚本
在Windows上,uv会使用pythonw
运行以.pyw
扩展名结尾的脚本:
from tkinter import Tk, ttk
root = Tk()
root.title("uv")
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World").grid(column=0, row=0)
root.mainloop()
带依赖的GUI脚本同样可以工作:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout
app = QApplication(sys.argv)
widget = QWidget()
grid = QGridLayout()
text_label = QLabel()
text_label.setText("Hello World!")
grid.addWidget(text_label)
widget.setLayout(grid)
widget.setGeometry(100, 100, 200, 50)
widget.setWindowTitle("uv")
widget.show()
sys.exit(app.exec_())