使用 uv 管理 Python 环境
要管理Python环境,你可以使用多种工具完成,如果使用pyenv来安装不同版本的Python、venv或者pipenv管理虚拟环境、诗歌管理专案,这些工具都可以单独做好,不过使用起来就是分开的工具,而uv则提供单一工具来完成上述所有工作,而且速度快、简单易用。
安装紫外线
uv本身并不需要 Python,所以不建议用 pip 或者 pipx 安装,这样都会跟特定的 Python 环境绑在一起,Windows 上就直接透过 PowerSehll 安装即可:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
或者透过勺子等软件管理工具安装:
scoop install uv
本文均以 Windows 平台在 PowerShell 下操作示范,如果是其他平台,请自行替换成对应的指令。
使用 uv 管理多版本 Python
使用uv python list
可以显示可安装以及已安装的Python版本:
# uv python list
cpython-3.13.1+freethreaded-windows-x86_64-none <download available>
cpython-3.13.1-windows-x86_64-none <download available>
cpython-3.12.8-windows-x86_64-none <download available>
cpython-3.11.11-windows-x86_64-none <download available>
cpython-3.10.16-windows-x86_64-none <download available>
cpython-3.9.21-windows-x86_64-none <download available>
cpython-3.8.20-windows-x86_64-none <download available>
cpython-3.7.9-windows-x86_64-none <download available>
pypy-3.10.14-windows-x86_64-none <download available>
pypy-3.9.19-windows-x86_64-none <download available>
pypy-3.8.16-windows-x86_64-none <download available>
pypy-3.7.13-windows-x86_64-none <download available>
如果要安装最新版本,可以使用uv python install
:
# uv python install
Installed Python 3.13.1 in 5.89s
+ cpython-3.13.1-windows-x86_64-none
查看安装结果:
# uv python list
cpython-3.13.1+freethreaded-windows-x86_64-none <download available>
cpython-3.13.1-windows-x86_64-none C:\Users\meebo\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\python.exe
cpython-3.12.8-windows-x86_64-none <download available>
cpython-3.11.11-windows-x86_64-none <download available>
cpython-3.10.16-windows-x86_64-none <download available>
cpython-3.9.21-windows-x86_64-none <download available>
cpython-3.8.20-windows-x86_64-none <download available>
cpython-3.7.9-windows-x86_64-none <download available>
pypy-3.10.14-windows-x86_64-none <download available>
pypy-3.9.19-windows-x86_64-none <download available>
pypy-3.8.16-windows-x86_64-none <download available>
pypy-3.7.13-windows-x86_64-none <download available>
安装版本会显示安装路径。已你也可以通过uv python dir
指令找到Python的安装路径:
# uv python dir
C:\Users\meebo\AppData\Roaming\uv\python
如果已经安装过Python,除非额外指定版本,否则就无法安装:
# uv python install
Python is already installed. Use `uv python install <request>` to install another version.
指定安装特定的版本:
# uv python install 3.10
Installed Python 3.10.16 in 9.78s
+ cpython-3.10.16-windows-x86_64-none
它会自行寻找符合的版本。
要删除已经安装的Python,必须使用uv python uninstall
:
# uv python uninstall 3.10
Searching for Python versions matching: Python 3.10
Uninstalled Python 3.10.16 in 1.52s
- cpython-3.10.16-windows-x86_64-none
删除时一定要指定版本,它同样会搜索相同的版本。
使用uv python list
时列出次版本号的最新修订版本,例如 3.10.16,如果希望所有的版本修订,可以加上--all-versions
选项,实际上你也可以只安装同一个版本号的其他修订版本,例如:
# uv python install 3.10.8
Installed Python 3.10.8 in 7.59s
+ cpython-3.10.8-windows-x86_64-none
如果简单指定次版本号删除Python,即可删除所有与该次版本号一致的修订版本,例如:
# uv python uninstall 3.10
Searching for Python versions matching: Python 3.10
Uninstalled 2 versions in 1.02s
- cpython-3.10.8-windows-x86_64-none
- cpython-3.10.16-windows-x86_64-none
安装Python时也可以同时指定多个版本:
# uv python install 3.10 3.11
Installed 2 versions in 8.71s
+ cpython-3.10.16-windows-x86_64-none
+ cpython-3.11.11-windows-x86_64-none
移除时也一样:
# uv python uninstall 3.10 3.11
Searching for Python versions matching: Python 3.10
Searching for Python versions matching: Python 3.11
Uninstalled 2 versions in 2.67s
- cpython-3.10.16-windows-x86_64-none
- cpython-3.11.11-windows-x86_64-none
使用 uv 替代 python/pip 工具
要注意的是,uv 管理的 Python 环境并不能直接透过python
指令执行必须,透过 uv 来执行。以底下这个 Python 程序为例:
# cat .\show_version.py
import sys
print(sys.version)
如果要刚刚通过 uv 安装的 Python 执行,指令为uv run
:
# uv run .\show_version.py
3.13.1 (main, Dec 19 2024, 14:38:48) [MSC v.1942 64 bit (AMD64)]
uv 会找到它所可以的Python环境来执行,基本上的顺序如下:
- 目前资料夹下的.python-version档内设定的版本。
- 目前启用的虚拟环境。
- 目前数据夹下的.venv 数据夹内设定的虚拟环境。
- uv自己安装的Python。
- 系统环境变量设置Python环境。
你也可以在执行时--python
跨越引数指定Python版本:
# uv run --python 3.10 .\show_version.py
3.10.16 (main, Dec 19 2024, 14:31:40) [MSC v.1942 64 bit (AMD64)]
如果指定的版本不存在,uv会自动安装一致的Python,因此你可以看到上述例子,虽然之前删除了3.10版本,但仍然可以执行。
你也可以从标准输入直接送入执行,例如:
# echo 'print("hello world!")' | uv run -
hello world!
如果安装了多个Python版本,uv默认会选择最新的版本,你可以通过uv python list --only-installed
查看已安装的版本:
# uv python list --only-installed
cpython-3.13.1-windows-x86_64-none C:\Users\meebo\AppData\Roaming\uv\python\cpython-3.13.1-windows-x86_64-none\python.exe
cpython-3.10.16-windows-x86_64-none C:\Users\meebo\AppData\Roaming\uv\python\cpython-3.10.16-windows-x86_64-none\python.exe
如果程序没有指定版本,执行Python时可以使用比较新的3.13:
# uv run .\show_version.py
3.13.1 (main, Dec 19 2024, 14:38:48) [MSC v.1942 64 bit (AMD64)]
如果想要设置uv默认使用的Python版本,可以使用uv python pin
,例如:
# uv python pin 3.10
Pinned `.python-version` to `3.10`
设置程序之后,如果再次执行Python,就会改用刚才指定的版本:
# uv run .\show_version.py
3.10.16 (main, Dec 19 2024, 14:31:40) [MSC v.1942 64 bit (AMD64)]
这个设置实际上会在当前数据夹下创建一个 .python-version 文件,并在其中记录指定的版本:
# cat .\.python-version
3.10
这个文件只对所在的资料夹有效,如果离开这个资料夹,就没有效果了。uv 并没有提供取消指定默认版本的指令,如果要取消,就只要把 .python-version 文件删除:
# rm .\.python-version
# uv run .\show_version.py
3.13.1 (main, Dec 19 2024, 14:38:48) [MSC v.1942 64 bit (AMD64)]
指定执行时需要的套件
如果您的程序需要其他套件才能执行,例如以下使用cowsay
套件的程序:
# cat .\cow.py
from cowsay import cow
cow('hello, world')
直接执行当然不行:
# uv run .\cow.py
Traceback (most recent call last):
File "C:\Users\meebo\code\python\test\cow.py", line 1, in <module>
from cowsay import cow
ModuleNotFoundError: No module named 'cowsay'
uv 提供了便捷的方式,您可以利用--with
选项指定套件:
# uv run --with cowsay .\cow.py
Installed 1 package in 13ms
____________
| hello, world |
============
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
uv 会建立一个临时的虚拟环境,即时下载安装指定的套件:
如果想知道这个虚拟环境建置在哪里,可以据悉uv cache dir
:
# uv cache dir
C:\Users\meebo\AppData\Local\uv\cache
以--with
指定套件时将以一致的虚拟环境执行,如果只是简单执行程序,没有使用--with
选项,仍然会找不到套件:
# uv run .\cow.py
Traceback (most recent call last):
File "C:\Users\meebo\code\python\test\cow.py", line 1, in <module>
from cowsay import cow
ModuleNotFoundError: No module named 'cowsay'
虚拟环境会和指定的套件捆绑在一起,如果执行使用相同套件的程序,例如:
# cat cow2.py
from cowsay import cow
cow('Hello, Python')
就会沿着已经建立的虚拟环境,不会重新安装套件:
# uv run --with cowsay .\cow2.py
_____________
| Hello, Python |
=============
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
你也可以使用uv cache clean
临时建立的虚拟环境来清除:
# uv cache clean
Clearing cache at: C:\Users\meebo\AppData\Local\uv\cache
Removed 1166 files (13.2MiB)
这时若程序再重新执行特定需要套件的,就会重新建立虚拟环境,并且安装套件:
# uv run --with cowsay .\cow.py
Installed 1 package in 13ms
____________
| hello, world |
============
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
如果需要多个套件,例如以下这个同时需要cowsay和rich套件的程序:
# cat .\cow_rich.py
from cowsay import cow
cow('hello, rich')
from rich import print
print('hello, cow')
执行时就可以用逗号隔开指定需要的套件:
# uv run --with cowsay,rich .\cow_rich.py
Installed 5 packages in 112ms
___________
| hello, rich |
===========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
hello, cow
或者也可以重复使用--with
选项:
# uv run --with cowsay --with rich .\cow_rich.py
Installed 5 packages in 90ms
___________
| hello, rich |
===========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
hello, cow
你也可以同时指定套件的版本(由于<
是转向的符号,为避免 PowerShell 解译错误,记住加上备用的单引号将套件名称与版本条件包起来):
# uv run --with 'cowsay>6,<7,rich' .\cow_rich.py
___________
| hello, rich |
===========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
hello, cow
最后再清理临时建立的虚拟环境:
# uv cache clean
Clearing cache at: C:\Users\meebo\AppData\Local\uv\cache
Removed 1202 files (13.5MiB)
管理虚拟环境
使用--with
虽然很方便,但是如果没有解密处理,可能会积累一大堆临时的虚拟环境因此,最好还是针对自己的需求创建虚拟环境。uv提供有uv venv
指令可以创建虚拟环境,首先将当前数据夹下的.venv资料夹中创建的虚拟环境,例如底下以指定3.10版本的Python创建虚拟环境:
# uv venv --python 3.10
Using CPython 3.10.16
Creating virtual environment at: .venv
Activate with: .venv\Scripts\activate
创建完成后如果执行Python程序,就会自动以当前数据夹中的虚拟环境执行:
# uv run .\show_version.py
3.10.16 (main, Dec 19 2024, 14:31:40) [MSC v.1942 64 bit (AMD64)]
你也可以指定虚拟环境的数据夹名称,例如底下建立3.13版本的虚拟环境:
# uv venv p313
Using CPython 3.13.1
Creating virtual environment at: p313
Activate with: p313\Scripts\activate
uv 默认并不会采用名称不是 .venv 的虚拟环境,您可以使用--python
指定要使用的虚拟环境:
# uv run --python p313 .\show_version.py
3.13.1 (main, Dec 19 2024, 14:38:48) [MSC v.1942 64 bit (AMD64)]
如果要删除虚拟环境,只要把虚拟环境的数据夹删除即可:
# rm -r -fo .\p313\
管理套件
uv 提供有uv pip
指令,能够让你使用跟pip
相内容的介面管理套件,uv pip
会依循uv run
的方式找到 Python 执行环境,因此,若当前数据夹有 .venv 虚拟环境,操作的对象就是虚拟环境,或者也可以使用--python
指定环境执行。
例如,我们可以在刚刚建立的虚拟环境中安装cowsay套件:
# uv pip install cowsay
Resolved 1 package in 302ms
Installed 1 package in 70ms
+ cowsay==6.1
就可以执行前面看过的cow.py:
# uv run .\cow.py
____________
| hello, world |
============
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
要注意的是,uv pip
维持与pip
的一致性,由于没有额外的相依关系可以参考,所以删除套件依赖信息时并不意味着不再需要的套件也一并删除。例如以下先安装需要依赖其他套件的丰富:
# uv pip install rich
Resolved 5 packages in 369ms
Prepared 1 package in 61ms
Installed 5 packages in 146ms
+ markdown-it-py==3.0.0
+ mdurl==0.1.2
+ pygments==2.19.1
+ rich==13.9.4
+ typing-extensions==4.12.2
我们可以使用uv pip tree
指令来查看目前的套件依赖关系:
# uv pip tree
cowsay v6.1
rich v13.9.4
├── markdown-it-py v3.0.0
│ └── mdurl v0.1.2
├── pygments v2.19.1
└── typing-extensions v4.12.2
你可以看到 rich 直接依赖三个套件,其中一个套件又会依赖另一个套件,如果我们删除 rich 套件:
# uv pip uninstall rich
Uninstalled 1 package in 27ms
- rich==13.9.4
重新重新观察目前的依赖关系:
# uv pip tree
cowsay v6.1
markdown-it-py v3.0.0
└── mdurl v0.1.2
pygments v2.19.1
typing-extensions v4.12.2
就会看到丰富套件的相依套件都还在,并不会因为没有其他套件需要用到而一并被删除。
要特别说明的是,uv pip
指令的速度比pip
要快,即使是这一点,也要使用魔鬼uv pip
女郎pip
。
使用 uv 管理 Python 专案
前面的使用很方便,不过有两个主要的问题:
- 没有记录以及快速重复 Python 执行环境的方法,如果需要在另一个环境执行同样的 Python 程序,就必须自己手动建立 Python 执行环境。
- 继承不再需要的增补套件,就像刚才看到的那样,在删除套件的过程中,即使某些套件不再需要其他套件,也不会被删除。
要解决上述问题,就必须改用专案的形式来管理。
只管理单一码档的专案
说到专案,好像很复杂,不过uv提供了一种最简单的专案形式,只不过是单个程序码档的专案,uv把专案相关资料写入Python程序原始码中,特别适用于设计一些小工具。
比如说,有一个程序需要使用 Python 3.13 以上的版本执行,就可以利用uv init
创建这个程序档:
# uv init --script cow3.py --python 3.13
Initialized script at `cow3.py`
如果观察该文件的内容:
# cat cow3.py
# /// script
# requires-python = ">=3.13"
# dependencies = []
# ///
def main() -> None:
print("Hello from cow3.py!")
if __name__ == "__main__":
main()
就会看到程序码开头有一段特殊格式的注释解,这是给uv看的锐数据(元数据),标明了所需要的Python环境。
为专案加入套件
我们可以进一步使用uv add
指定所需的套件:
# uv add --script cow3.py cowsay rich
Updated `cow3.py`
uv同样会修改原始码:
# cat cow3.py
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "cowsay",
# "rich",
# ]
# ///
def main() -> None:
print("Hello from cow3.py!")
if __name__ == "__main__":
main()
您可以在注解中的dependencies
表格中看到刚刚指定的套件。接着我们修改程序码,以便确认可以使用指定的套件:
# cat cow3.py
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "cowsay",
# "rich",
# ]
# ///
from cowsay import cow
from rich import print
def main() -> None:
cow('hello, uv')
print('hello, rich')
if __name__ == "__main__":
main()
执行看看:
# uv run cow3.py
Reading inline script metadata from `cow3.py`
Installed 5 packages in 106ms
_________
| hello, uv |
=========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
hello, rich
你可以看到 uv 会先读取记录在程序原始码内注解的精确数据,为该程序建立一个临时的虚拟环境,然后根据需求安装所需的套件,最后正确执行。如果指定的 Python 版本尚未安装,uv 也会自动下载安装一致的版本。
利用这样的方式,只要将该文件复制到其他安装有 uv 的地方,就可以自动创建相关的Python环境执行了。
删除套件
如果要删除套件,只需使用uv remove
指令即可,例如:
# uv remove --script cow3.py rich
Updated `cow3.py`
就可以看到原始码中的注解也修改了:
# cat cow3.py
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "cowsay",
# ]
# ///
from cowsay import cow
from rich import print
def main() -> None:
cow('hello, uv')
print('hello, rich')
if __name__ == "__main__":
main()
重新执行就会出错,因为码中会用到的丰富的程序套件已经被我们删除了:
# uv run .\cow3.py
Reading inline script metadata from `cow3.py`
Traceback (most recent call last):
File "C:\Users\meebo\code\python\test\cow3.py", line 9, in <module>
from rich import print
ModuleNotFoundError: No module named 'rich'
管理以资料夹为基础的专案
使用文件作为专案虽然很方便,不过大多数情况下专案都没有这么简单,因此 uv 提供另一种以数据夹为基础的专案形式,同样是在使用过的uv init
指令建立之前使用,例如:
# uv init test_uv
Initialized project `test-uv` at `C:\Users\meebo\code\python\test\test_uv`
它会查找您提供的专案名称,帮助建立数据夹:
# cd test_uv
# ls
Directory: C:\Users\meebo\code\python\test\test_uv
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2025/1/7 下午 05:21 109 .gitignore
-a--- 2025/1/7 下午 05:21 5 .python-version
-a--- 2025/1/7 下午 05:21 85 hello.py
-a--- 2025/1/7 下午 05:21 153 pyproject.toml
-a--- 2025/1/7 下午 05:21 0 README.md
进入资料夹你会发现,uv还帮你建立了许多档案:
-
.gitignore:uv会帮你把专案建立成git存储库,并且帮你写好.gitignore文件,避免Python执行过程产生的临时文档等也提交到存储库内:
# cat .\.gitignore # Python-generated files __pycache__/ *.py[oc] build/ dist/ wheels/ *.egg-info # Virtual environments .venv
-
.python-version:记录这个专案使用的Python版本:
# cat .\.python-version 3.13
-
hello.py:计划档:默认会帮助建立一个主计划档,内容如下:
# cat .\hello.py def main(): print("Hello from test-uv!") if __name__ == "__main__": main()
-
pyproject.toml:这个专案的锐度数据,其实就是前面单一程序档形式的专案在原始码注解的内容:
# cat .\pyproject.toml [project] name = "test-uv" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.13" dependencies = []
之后增减所需套件时,可以把相关资讯记录在此档案中。
-
README.ME:空的markdown档,前期让你撰写专案说明用。
如果需要,在创建专案时也可以使用--python
指定想要使用的 Python 版本。
执行专案内的计划
要执行专案内的程序代码,同样是使用uv run
:
# uv run hello.py
Using CPython 3.13.1
Creating virtual environment at: .venv
Hello from test-uv!
第一次执行时,uv会引用专案内的设置,建立虚拟环境,放在.venv数据夹内,之后所有的操作都是利用这个虚拟环境:
# ls
Directory: C:\Users\meebo\code\python\test\test_uv
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2025/1/7 下午 05:37 .venv
-a--- 2025/1/7 下午 05:21 109 .gitignore
-a--- 2025/1/7 下午 05:21 5 .python-version
-a--- 2025/1/7 下午 05:21 85 hello.py
-a--- 2025/1/7 下午 05:21 153 pyproject.toml
-a--- 2025/1/7 下午 05:21 0 README.md
-a--- 2025/1/7 下午 05:37 114 uv.lock
另外,还要增加uv.lock
档:
# cat .\uv.lock
version = 1
requires-python = ">=3.13"
[[package]]
name = "test-uv"
version = "0.1.0"
source = { virtual = "." }
该文件会由 uv 管理,引用 pyproject.toml 内部记录的套件推导出所有相依套件的版本与关系。
安装套件
要在专案内安装与删除套件,都和前面单一程序码档的操作一样,只是记录数据的位置修改成独立的文件,而不是在原始码内的注解,例如:
# uv add cowsay rich
Resolved 6 packages in 380ms
Prepared 5 packages in 598ms
Installed 5 packages in 101ms
+ cowsay==6.1
+ markdown-it-py==3.0.0
+ mdurl==0.1.2
+ pygments==2.19.1
+ rich==13.9.4
此时 pyproject.toml 档内就会记录刚刚加入的套件以及对应的版本:
# cat .\pyproject.toml
[project]
name = "test-uv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"cowsay>=6.1",
"rich>=13.9.4",
]
但如果查看 uv.lock 档,就会看到所有安装的相依套件信息:
# cat .\uv.lock
version = 1
requires-python = ">=3.13"
[[package]]
name = "cowsay"
version = "6.1"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f1/13/63c0a02c44024ee16f664e0b36eefeb22d54e93531630bd99e237986f534/cowsay-6.1-py3-none-any.whl", hash = "sha256:274b1e6fc1b966d53976333eb90ac94cb07a450a700b455af9fbdf882244b30a", size = 25560 },
]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
]
[[package]]
name = "pygments"
version = "2.19.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
]
[[package]]
name = "rich"
version = "13.9.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
]
[[package]]
name = "test-uv"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "cowsay" },
{ name = "rich" },
]
[package.metadata]
requires-dist = [
{ name = "cowsay", specifier = ">=6.1" },
{ name = "rich", specifier = ">=13.9.4" },
]
在修改文件最下方可以看到此专案依赖cowsay 与 rich 两个套件,而 rich 又依赖 markdown-it-py 以及 pygments 两个套件。如果往上找,就会看到 markdwon-it-py 又依赖 mdurl 套件,所以刚刚执行程序的时候就会看到一共安装了 5 个套件。uv.lock 是依赖 pyproject.toml 自动产生的内容,我们不应该是它的内容。
如果你想了解专案中套件的关系,也可以使用uv tree
指令:
# uv tree
Resolved 6 packages in 2ms
test-uv v0.1.0
├── cowsay v6.1
└── rich v13.9.4
├── markdown-it-py v3.0.0
│ └── mdurl v0.1.2
└── pygments v2.19.1
就可以树状结构图刚才看到从uv.lock档中解析出来的关系。
更新套件
如果要更新特定套件,可以使用uv lock --upgrade-package
指令:
# uv lock --upgrade-package cowsay
Resolved 6 packages in 385ms
如果要更新所有套件,则可以uv lock --upgrade
:
# uv lock --upgrade
Resolved 18 packages in 304ms
更新套件都会遵循 pyproject.toml 档内的限制,安装符合条件的版本。
执行套件提供的指令
在专案中,uv run
除了可以执行程序码档之外,也可以执行套件所提供的指令,例如以下先安装httpie套件:
# uv add httpie
Resolved 19 packages in 3.65s
Prepared 13 packages in 13.89s
Installed 13 packages in 224ms
+ certifi==2024.12.14
+ charset-normalizer==3.4.1
+ colorama==0.4.6
+ defusedxml==0.7.1
+ httpie==3.2.4
+ idna==3.10
+ multidict==6.1.0
+ pip==24.3.1
+ pysocks==1.7.1
+ requests==2.32.3
+ requests-toolbelt==1.0.0
+ setuptools==75.7.0
+ urllib3==2.3.0
然后,就可以执行该套件提供的http
指令了:
# uv run http -p=b GET https://flagtech.github.io/flag.txt
FLAG
______ _ _____
| ____| | /\ / ____|
| |__ | | / \ | | __
| __| | | / /\ \| | |_ |
| | | |____ / ____ \ |__| |
|_| |______/_/ \_\_____|
删除套件
如果要删除套件,同样是用uv remove
指令,例如:
# uv remove cowsay
Resolved 18 packages in 20ms
Uninstalled 1 package in 4ms
- cowsay==6.1
手动修改 pyproject.toml 文件
你也可以自己手动修改 pyproject.toml 文件,例如现在的 pyproject.toml 文件内容如下:
# cat .\pyproject.toml
[project]
name = "test-uv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"httpie>=3.2.4",
"rich>=13.9.4",
]
如果把其中有依赖关系的表格中的httpie那一行删除:
# cat .\pyproject.toml
[project]
name = "test-uv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"rich>=13.9.4",
]
这个时候必须执行uv lock
指令,让 uv.lock 文件的内容与 pyproject.toml 文件一致:
# uv lock
Resolved 5 packages in 12ms
Removed certifi v2024.12.14
Removed charset-normalizer v3.4.1
Removed colorama v0.4.6
Removed defusedxml v0.7.1
Removed httpie v3.2.4
Removed idna v3.10
Removed multidict v6.1.0
Removed pip v24.3.1
Removed pysocks v1.7.1
Removed requests v2.32.3
Removed requests-toolbelt v1.0.0
Removed setuptools v75.7.0
Removed urllib3 v2.3.0
这里会看到 uv.lock 档的更新情况,你可以看到它移除了 httpie 及其依赖的套件,不过要注意的是,这只是纸上作业,了 uv.lock 档的内容而已,实际上这些套件都没有移除,你可以透过uv pip list
来查看目前安装的套件:
# uv pip list
Package Version
------------------ ----------
certifi 2024.12.14
charset-normalizer 3.4.1
colorama 0.4.6
defusedxml 0.7.1
httpie 3.2.4
idna 3.10
markdown-it-py 3.0.0
mdurl 0.1.2
multidict 6.1.0
pip 24.3.1
pygments 2.19.1
pysocks 1.7.1
requests 2.32.3
requests-toolbelt 1.0.0
rich 13.9.4
setuptools 75.7.0
urllib3 2.3.0
要按照 uv.lock 内容增删套件,就必须再执行uv sync
让实际的 Python 环境与 uv.lock 档的内容一致:
# uv sync
Resolved 5 packages in 1ms
Uninstalled 13 packages in 395ms
- certifi==2024.12.14
- charset-normalizer==3.4.1
- colorama==0.4.6
- defusedxml==0.7.1
- httpie==3.2.4
- idna==3.10
- multidict==6.1.0
- pip==24.3.1
- pysocks==1.7.1
- requests==2.32.3
- requests-toolbelt==1.0.0
- setuptools==75.7.0
- urllib3==2.3.0
到这里,才真正删除了 httpie 及其依赖的套件,如果再次使用uv pip list
检测视:
# uv pip list
Package Version
-------------- -------
markdown-it-py 3.0.0
mdurl 0.1.2
pygments 2.19.1
rich 13.9.4
可以看httpie相关的套件真的都不见了。这也和严重使用uv pip
或pip
管理套件不一样的地方,以专案形式管理时,删除套件时会循uv.lock档中推导出的依赖关系,把已经没有套件依赖的套件一并移除,只留下需要的套件。
复制专案
利用这样的方式,只需将专案资料夹复制到其他安装有ux的地方,重新执行专案就会自动建置Python环境安装套件,不需要手动辛苦建立了。
使用套件提供的工具指令
有些套件提供了可以直接执行的指令,例如刚才的cowsay套件就提供了cowsay
可以在终端机执行的指令,如果只是想使用这些指令,uv提供的有uvx
指令可以不用先建立专案或者Python执行环境,就直接执行这些指令,例如可以:
# uvx cowsay -t 'hello, uv'
Installed 1 package in 16ms
_________
| hello, uv |
=========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
uvx
同样会根据套件建立临时的虚拟环境,并安装必要的套件。实际上uvx
指令是uv tool run
的快捷指令,你也可以这样执行:
# uv tool run cowsay -t 'hello, uv'
_________
| hello, uv |
=========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
如果要执行的指令与套件不同名称,就必须--from
指定套件名称。举例来说,如果想要使用前面看过的 httpie 套件提供的http
指令获取特定网址的内容,就可以这样下指令:
# uvx --from httpie http -p=b GET https://flagtech.github.io/flag.txt
Installed 17 packages in 291ms
FLAG
______ _ _____
| ____| | /\ / ____|
| |__ | | / \ | | __
| __| | | / /\ \| | |_ |
| | | |____ / ____ \ |__| |
|_| |______/_/ \_\_____|
你可以看到它会先安装--from
选项指定的套件,然后再执行指令。
将套件提供的指令安装到系统上
如果某个套件中的指令很好用,你也可以uv tool install
把它安装到系统上,例如刚才 httpie 套件中的http
指令,就很适合安装起来替代curl
使用:
# uv tool install httpie
Resolved 17 packages in 560ms
Installed 17 packages in 224ms
+ certifi==2024.12.14
+ charset-normalizer==3.4.1
+ colorama==0.4.6
+ defusedxml==0.7.1
+ httpie==3.2.4
+ idna==3.10
+ markdown-it-py==3.0.0
+ mdurl==0.1.2
+ multidict==6.1.0
+ pip==24.3.1
+ pygments==2.19.1
+ pysocks==1.7.1
+ requests==2.32.3
+ requests-toolbelt==1.0.0
+ rich==13.9.4
+ setuptools==75.7.0
+ urllib3==2.3.0
Installed 3 executables: http.exe, httpie.exe, https.exe
uv 会建立一个独立的虚拟环境来安装套件,接着就可以直接执行套件中的指令:
# http -p=b GET https://flagtech.github.io/flag.txt
FLAG
______ _ _____
| ____| | /\ / ____|
| |__ | | / \ | | __
| __| | | / /\ \| | |_ |
| | | |____ / ____ \ |__| |
|_| |______/_/ \_\_____|
如果想知道实际安装的路径,可以通过uv tool dir
指令:
# uv tool dir
C:\Users\meebo\AppData\Roaming\uv\tools
若有需要,也可以通过以下uv tool upgrade
更新这些指令的版本:
# uv tool upgrade httpie
Nothing to upgrade
往后如果不再需要这个套件的指令,也可以删除删除uv tool uninstall
:
# uv tool uninstall httpie
Uninstalled 3 executables: http.exe, httpie.exe, https.exe
本文介绍了 uv 的几种使用方式,应该可以让大家了解使用 uv 来管理 Python 环境的好处,不但执行速度快,也可以在太古中使用不同多种工具的麻烦。
文章来源:https://dev.to/codemee/shi-yong-uv-guan-li-python-huan-jing-53hg