uv 的 inline script metadata 太香了
最近又玩了下 uv,感觉它在“小工具开发”这个场景里特别顺手。
uv 本质上是一个把 Python 依赖管理、虚拟环境、脚本运行这些事情揉在一起的工具。它最大的优点当然是快,但更让我喜欢的是:很多原本零碎又烦的动作,被压缩成了几个很好记的命令。
比如平时写个小脚本,常常只是想:
- 调一下接口
- 批量处理一点文件
- 验证一个第三方库
- 给自己做个顺手的小命令
这类东西通常不值得认真建个项目,但又往往会依赖 requests、httpx、rich 之类的包。以前一般要先建 venv,再装依赖,可能还要改个 .gitignore,多少有点麻烦。
这时候 uv 很方便的一个点,就是可以直接用 --with:
|
1 |
uv run --with requests demo.py |
或者:
|
1 |
uv run --with httpx --with requests foo.py |
这种方式特别适合刚开始写小工具的时候。先跑起来,先验证思路,不用一上来就准备完整项目。
不过,--with 也有个问题:依赖信息是在命令里,不在脚本里。
今天你记得怎么跑,过几天自己可能都忘了。发给别人时,也得额外告诉对方要带哪些依赖。
这时候真正的大招就来了:inline script metadata。
你可以直接把依赖用这样的格式,写到脚本头部:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# /// script # requires-python = ">=3.11" # dependencies = [ # "httpx", # "rich", # ] # /// import httpx from rich import print resp = httpx.get("https://luy.li") print(resp.status_code) |
可以看到,去掉# /// script这些包裹层之后,里面的内容,其实就是TOML的语法。
这样之后就不用再写长命令了,直接:
|
1 |
uv run foo.py |
就行。这个体验非常好。因为脚本自己就说明白了:
- 需要什么 Python 版本
- 依赖哪些包
- 应该怎么运行
更进一步,你甚至可以再加个 shebang,把它写成一个可以直接执行的脚本:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/usr/bin/env -S uv run --script # /// script # requires-python = ">=3.11" # dependencies = [ # "httpx", # "rich", # ] # /// import httpx from rich import print print(httpx.get("https://luy.li").status_code) |
这样给脚本加上执行权限(chmod +x)之后,连 uv run foo.py 都可以省掉,直接 ./foo.py 就可以跑起来了。
最后总结一下:
- 刚开始随手写个小工具,用
uv run --with ... - 觉得这个脚本值得留下来,就上
inline script metadata - 再彻底一点,可以用
#!/usr/bin/env -S uv run --script这个shebang
发表回复