要管理 Python 環境,你可以使用多種工具達成,像是使用 pyenv 來安裝不同版本的 Python、venv 或是 pipenv 管理虛擬環境、poetry 管理專案,這些工具都可以善盡個別的工作,不過使用起來就是分開的工具,而 uv 則是提供單一工具來完成上述所有工作,並且速度快,簡單易用。
安裝 uv
uv 本身並不需要 Python,所以不建議用 pip 或是 pipx 安裝,這樣都會跟特定的 Python 環境綁在一起,Windows 上就直接透過 PowerSehll 安裝即可:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
或是透過 scoop 等軟體管理工具安裝:
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
的一致性,由於沒有額外的相依關係資訊可以參考,所以刪除套件時並不會將不再被需要的依賴套件也一併移除。例如以下先安裝需要依賴其它套件的 rich:
# 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
就會看到 rich 套件的相依套件都還在,並不會因為沒有其它套件需要用到而一併被刪除。
要特別說明的是,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 看的詮釋資料(metadata),標示了所需要的 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()
再重新執行就會出錯,因為程式碼中會用到的 rich 套件已經被我們移除了:
# 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",
]
如果把其中有 dependencies 表格中的 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 環境的好處,不但執行速度快,也可以免除過往使用多種不同工具的麻煩。
Top comments (0)