uv na macOS: zarządzanie wersjami Pythona, projektami i narzędziami
Tłumaczenie automatyczne
Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.
Ten przewodnik jest dla programistów Pythona na macOS, którzy przechodzą na uv z pip, venv, pip-tools, pyenv lub pipx. uv uruchamia cztery rodzaje pracy w osobnych środowiskach: projekt, skrypt w jednym pliku, jednorazowe uruchomienie CLI przez uvx oraz CLI zainstalowane w PATH. Wszystkie cztery mogą korzystać z wersji Pythona, które instaluje uv. Poznasz polecenia dla każdego z nich i dowiesz się, jak wybrać właściwe.
Przeniosłem swój własny workflow Pythona na uv. Jeden plik wykonywalny obsługuje teraz pracę, którą wcześniej dzieliłem między te narzędzia.
Szybki start
# Install uv with Homebrew
brew install uv
# Start a project
uv init example-app
cd example-app
uv add httpx
uv run python main.py
# Run an isolated CLI without installing it permanently
uvx ruff check .
Diagram pokazuje cztery workflow, co każdy z nich przechowuje i zarządzane instalacje Pythona, które współdzielą.
Instalacja i aktualizacja uv
Homebrew to wygodny sposób instalacji na macOS. Obsługiwane metody opisuje przewodnik instalacji uv:
brew install uv
uv --version
Jeśli uv zainstalował Homebrew, Homebrew powinien go też aktualizować:
brew upgrade uv
uv self update służy do samodzielnej metody instalacji uv i jest wyłączone w instalacjach przez menedżery pakietów. Aktualizuj uv tym samym narzędziem, którym go zainstalowano.
Aby sprawdzić, gdzie znajdują się uv, jego instalacje Pythona, narzędzia i cache:
command -v uv
uv python dir
uv tool dir
uv cache dir
Zarządzane instalacje Pythona, trwałe narzędzia i jednorazowe wpisy cache mają osobne katalogi. Cache można usunąć i odbudować. Nie jest źródłem prawdy. Na macOS uv klonuje pakiety z cache do każdego środowiska (copy-on-write) zamiast je kopiować. Usunięcie i odbudowanie .venv wykorzystuje cache i nie pobiera pakietów ponownie.
Projekty: deklaracje, rozwiązywanie zależności i środowisko
Projekt uv ma zwykle trzy części:
pyproject.tomldeklaruje metadane projektu i bezpośrednie wymagania.uv.lockprzechowuje wieloplatformowe rozwiązanie zależności uv..venvto lokalne zainstalowane środowisko, które powinno dać się w każdej chwili usunąć.
Diagram pokazuje, które pliki commitujesz, a które uv z nich odbudowuje.
Utwórz aplikację i dodaj wymagania runtime oraz testowe:
uv init forecast-app
cd forecast-app
uv add httpx
uv add --group test pytest
uv run python main.py
uv run --group test pytest
Obecne szablony aplikacji uv tworzą main.py, pyproject.toml, README.md i .python-version. Domyślnie nie definiują systemu budowania. Dla pakietowanej biblioteki z układem src i backendem budowania użyj uv init --lib.
uv run sprawdza projekt, w razie potrzeby aktualizuje plik lock, synchronizuje wymagane zależności i uruchamia polecenie. Ten cykl opisuje dokumentacja układu projektu i synchronizacji uv. Pierwsza operacja na projekcie tworzy w razie potrzeby .venv i uv.lock. Samo uv init tworzy tylko pliki projektu.
uv domyślnie instaluje grupę dev. Inne grupy, takie jak test, wymagają --group przy każdym poleceniu albo default-groups w sekcji [tool.uv]. Aby zainstalować tylko jedną grupę, na przykład w zadaniu CI dla dokumentacji, użyj uv sync --only-group docs.
Grupy pozostają lokalne i nigdy nie są publikowane. Opublikowany extra działa inaczej: uv add --optional cli rich dodaje extra, które użytkownicy instalują jako forecast-app[cli].
Aby używać projektu w notatnikach Jupyter w VS Code, uruchom uv add --dev ipykernel i wybierz .venv jako kernel. Zobacz przewodnik uv po Jupyterze.
Commituj dane wejściowe, nie środowisko
Commituj pyproject.toml, uv.lock, kod źródłowy i celowo ustawiony .python-version. Ignoruj .venv i cache uv.
Członek zespołu, który sklonuje repozytorium, jednym poleceniem dostaje środowisko zgodne z plikiem lock:
git clone https://github.com/example/forecast-app.git
cd forecast-app
uv sync --locked
Aby sprawdzić, dlaczego pakiet jest zainstalowany, i przenieść plik lock na nowsze wersje:
uv tree # show the dependency graph
uv tree --outdated # show newer versions where they exist
uv lock --upgrade-package httpx # move one package, keep the rest
uv lock --upgrade # re-resolve everything
Commituj zmieniony uv.lock razem ze zmianą, która go wymagała.
Plik lock zapisuje rozwiązanie zależności dla obsługiwanych markerów i platform. Nie sprawia, że natywne wheele są identyczne na macOS, Linuksie, Intelu i Apple Silicon. Testuj każdą platformę wdrożeniową.
Część tego uv potrafi wymusić. required-environments w sekcji [tool.uv] sprawia, że rozwiązywanie zależności kończy się błędem, gdy pakiet bez dystrybucji źródłowej nie ma wheela dla wymienionej platformy:
[tool.uv]
required-environments = [
"sys_platform == 'darwin' and platform_machine == 'arm64'",
"sys_platform == 'linux' and platform_machine == 'x86_64'",
]
no-build-package zabrania budowania ze źródeł dla wskazanych pakietów, więc brakujący wheel powoduje błąd instalacji zamiast uruchomienia kompilatora. Jeśli wdrażasz też PyTorch na Linuksie z CUDA, skonfiguruj indeks według przewodnika uv po PyTorch.
Aktualność pliku lock: --locked to nie --frozen
Domyślnie polecenia projektu mogą aktualizować uv.lock, gdy zmieniają się deklaracje. Flagi aktualności i dokładności opisuje dokumentacja uv o blokowaniu i synchronizacji.
Użyj --locked, aby wymagać, by plik lock był zgodny z metadanymi projektu:
uv lock --check
uv sync --locked --group test
uv run --locked --group test pytest
Jeśli pyproject.toml i uv.lock się nie zgadzają, te polecenia kończą się błędem zamiast tworzyć nowy plik lock. Używaj ich w CI, aby nieaktualny plik lock przerywał build.
Używaj --frozen tylko wtedy, gdy celowo chcesz, by uv użył istniejącego pliku lock bez sprawdzania, czy jest aktualny:
uv sync --frozen
Może to być przydatne w kontrolowanym etapie builda, w którym plik lock został już sprawdzony, ale nie wykrywa to nieaktualnego pliku lock.
Diagram pokazuje, co robi każdy tryb, gdy pyproject.toml się zmienił, a uv.lock nie.
Dokładność to ustawienie niezależne od aktualności. uv sync jest domyślnie dokładne i usuwa zbędne pakiety. uv run domyślnie używa niedokładnej synchronizacji, chyba że podasz --exact. Diagram śledzi jeden ręcznie zainstalowany pakiet przez każde z poleceń.
Instalacja i przypinanie wersji Pythona
uv potrafi pobierać dystrybucje Pythona i nimi zarządzać:
uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12
Zarządzane buildy CPython w uv pochodzą z projektu python-build-standalone. uv potrafi też znaleźć interpretery systemowe, z Homebrew, pyenv, Condy i inne. Obsługiwane źródła i sposób wyszukiwania opisuje dokumentacja uv o wersjach Pythona.
.python-version to żądanie wersji, które odczytuje uv i inne zgodne narzędzia. uv python pin zapisuje ten plik, a uv init go tworzy. requires-python w pyproject.toml to kontrakt zgodności projektu. Ustawiaj oba świadomie:
[project]
requires-python = ">=3.12,<3.14"
uv bierze żądaną wersję najpierw z --python, potem z .python-version, a na końcu z requires-python.
Przypięcie 3.12 nie gwarantuje na zawsze tego samego buildu z poprawkami ani tego samego artefaktu na każdym systemie operacyjnym. Jeśli potrzebujesz dokładnej wersji poprawki, podaj ją. W CI wybierz interpreter i wypisz go, przez uv run --python 3.12.7 python -VV albo ustawiając UV_PYTHON=3.12.7 dla zadania.
Użyj innego menedżera Pythona, gdy projekt potrzebuje dystrybucji lub konfiguracji budowania, której uv nie dostarcza. uv nadal może korzystać z takiego interpretera przez --python lub zwykłe wyszukiwanie.
Wybór między uv run, uvx a zainstalowanymi narzędziami
Wybierz gałąź według tego, czy narzędzie musi importować twój projekt, pozostać w PATH, czy ani jedno, ani drugie.
Narzędzia powiązane z projektem: uv run
Jeśli pytest, mypy, generator kodu lub inne narzędzie musi importować projekt albo używać jego pluginów w wersjach z pliku lock, zadeklaruj je w grupie zależności:
uv add --group lint ruff
uv run --group lint ruff check .
Uruchomienie takiego narzędzia przez uvx odizolowałoby je od projektu i mogłoby ukryć zainstalowany pakiet lub pluginy, których potrzebuje.
Narzędzia doraźne: uvx
uvx to alias dla uv tool run. Tworzy izolowane środowisko przechowywane w jednorazowym cache uv. Ten cache i cykl życia trwałych narzędzi opisuje dokumentacja narzędzi uv:
uvx ruff@0.12.0 check .
uvx ruff@latest check .
uvx --from jupyterlab jupyter lab
uvx --from httpie http --version
uvx --with mkdocs-material mkdocs --help
W CI i dokumentacji przypinaj wersję narzędzia. Pierwsze wywołanie bez wersji wybiera bieżące wydanie, a kolejne wywołania mogą używać stanu z cache. @latest żąda najnowszego wydania zamiast tego z cache. Użyj --from, gdy nazwa pakietu różni się od nazwy polecenia, jak w przypadku jupyterlab i httpie.
Trwałe pliki wykonywalne: uv tool install
Zainstaluj narzędzie, gdy skrypty, nad którymi nie masz kontroli, potrzebują jego polecenia w PATH albo gdy ma nim zarządzać manifest konfiguracji twojej maszyny:
uv tool install ruff
uv tool list
uv tool upgrade ruff
uv tool upgrade --all
uv tool uninstall ruff
Trwałe narzędzia też używają izolowanych środowisk. Nie modyfikuj tych środowisk ręcznie przez pip.
Skrypty w jednym pliku z PEP 723
PEP 723 definiuje metadane skryptu inline. Zgodny runner potrafi odczytać blok komentarza i zbudować izolowane środowisko. Format metadanych i działanie runnera opisują przewodnik uv po skryptach oraz PEP 723.
Diagram pokazuje dwie części takiego pliku i to, co uv run robi z każdą z nich.
uv może napisać blok metadanych za ciebie:
uv init --script fetch.py --python 3.12
Gotowy skrypt wygląda tak:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "httpx>=0.27,<1",
# ]
# ///
import httpx
response = httpx.get("https://example.com", timeout=10)
response.raise_for_status()
print(response.status_code)
Uruchamiaj skrypt i edytuj metadane przez uv:
uv run fetch.py
uv add --script fetch.py rich
uv remove --script fetch.py rich
Zwykłe python fetch.py ignoruje metadane w komentarzu. Skrypt zależy więc od zgodnego runnera, choć składnia Pythona pozostaje poprawna. uv to jeden z runnerów. pipx run, Hatch i PDM też odczytują ten blok.
Aby uruchamiać skrypt jako ./fetch.py, dodaj shebang, który wywołuje uv:
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["httpx"]
# ///
import httpx
chmod +x fetch.py
./fetch.py
Flaga -S sprawia, że env dzieli linię na osobne argumenty, więc --script trafia do uv.
Do szybkiego eksperymentu podaj zależności w linii poleceń zamiast pisać metadane. Druga linia uruchamia REPL Pythona z dostępnym pandas:
uv run --with httpx scratch.py
uv run --with pandas python
Dla skryptu, który ma później odtworzyć to samo rozwiązanie zależności, utwórz obok niego plik lock:
uv lock --script fetch.py
uv run --script fetch.py
To zapisuje fetch.py.lock. Znacznik czasu exclude-newer w bloku metadanych sprawia, że uv ignoruje wersje pakietów opublikowane po tej dacie:
# /// script
# dependencies = ["httpx"]
# [tool.uv]
# exclude-newer = "2025-04-17T00:00:00Z"
# ///
Daje to słabszą gwarancję niż plik lock. Nie przypina dokładnych wersji i nie przywróci pliku, który indeks później usunie.
Zamiast skryptu użyj projektu, gdy kilka plików współdzieli zależności, kod da się importować jako pakiet, testy potrzebują stanu projektu lub kilka skryptów musi zmieniać się razem.
Istniejące projekty z requirements.txt
Plik requirements.txt może zawierać luźne wymagania, dokładnie przypięte wersje, hashe, ograniczenia, indeksy, adresy URL lub eksport wymagań wygenerowany przez resolver. Jego powtarzalność zależy od tego, jak go wygenerowano i jak się go używa. Sama nazwa pliku nic o tym nie mówi.
Masz dwie opcje: zachować format pip i uruchamiać go przez uv pip albo, dla własnej aplikacji, przejść na uv.lock.
Używaj interfejsu uv zgodnego z pip bez migracji:
uv venv
uv pip sync requirements.txt
uv run python app.py
uv pip sync dopasowuje środowisko do pliku. uv pip install -r tylko dodaje pakiety.
W przypadku aplikacji, którą sam utrzymujesz, przydatna może być migracja etapami:
uv init --bare
uv add -r requirements.in
uv add --group test -r requirements-test.in
uv lock
uv sync --locked
Zanim usuniesz stare pliki, uruchom pełne testy i całą ścieżkę wdrożenia. Jeśli system zależny od projektu nadal oczekuje formatu pip, wygeneruj go ze sprawdzonego pliku lock uv za pomocą polecenia export uv:
uv export --format requirements.txt \
--output-file requirements.txt
Nie utrzymuj uv.lock i ręcznie edytowanego eksportu jako dwóch konkurencyjnych rozwiązań zależności.
Cache i prywatne indeksy
Cache uv przyspiesza powtarzane instalacje, ale nadal można go usunąć:
uv cache prune
uv cache clean
Do rutynowego sprzątania wybieraj prune. clean usuwa wszystkie wpisy cache i wymusza ponowne pobieranie i budowanie.
Plik lock poprawia powtarzalność. Nie sprawia, że zależności stają się godne zaufania.
Dla prywatnego indeksu umieść jego nazwę i adres URL w pyproject.toml, a dane uwierzytelniające trzymaj poza plikiem:
[[tool.uv.index]]
name = "internal"
url = "https://pypi.example.com/simple"
Przekazuj dane uwierzytelniające przez UV_INDEX_INTERNAL_USERNAME i UV_INDEX_INTERNAL_PASSWORD albo przez keyring. uv tworzy nazwy zmiennych z nazwy indeksu. Zobacz dokumentację uv o uwierzytelnianiu w indeksach.
Stare polecenia i ich odpowiedniki w uv
Jeśli przechodzisz ze starszych narzędzi, ta tabela przypisuje każdemu znanemu poleceniu polecenie uv, które wykonuje to samo zadanie.
| Zadanie | Wcześniej | uv |
|---|---|---|
| Instalacja Pythona | pyenv install 3.12 | uv python install 3.12 |
| Nowy projekt i środowisko | mkdir proj && cd proj && python -m venv .venv | uv init proj |
| Dodanie pakietu | pip install pandas && pip freeze > requirements.txt | uv add pandas |
| Przypięcie wersji | pip-compile requirements.in | uv lock |
| Aktualizacja jednego pakietu | pip-compile --upgrade-package httpx | uv lock --upgrade-package httpx |
| Uruchomienie w środowisku | source .venv/bin/activate && python app.py | uv run app.py |
| Skrypt z zależnościami | ręczne venv dla jednego pliku | blok PEP 723 + uv run |
| Jednorazowe uruchomienie narzędzia | pipx run black | uvx black |
| Instalacja narzędzia | pipx install ruff | uv tool install ruff |
| Powtarzalna instalacja w CI | pip install -r requirements.txt | uv sync --locked |
Krótka lista kontrolna
Dla każdego projektu:
- Zdefiniuj
requires-pythoni bezpośrednie zależności wpyproject.toml. - Oddziel publikowane extras (
--optional) od lokalnych grup zależności (--group). - Commituj
uv.lock. Ignoruj.venvi stan cache. - Uruchamiaj narzędzia powiązane z projektem w środowisku projektu.
- W CI używaj
uv lock --checklub--locked. - Testuj każdy docelowy system operacyjny i architekturę, które obejmuje plik lock.
- Eksportuj formaty zgodności tylko dla konkretnych systemów, które ich potrzebują.
- Trzymaj dane uwierzytelniające indeksu poza commitowanymi plikami. Przekazuj je przez zmienne środowiskowe lub keyring.
Używam uv jako domyślnego narzędzia do Pythona na macOS, bo jeden plik binarny obsługuje wszystkie te zadania i trzyma ich środowiska osobno.