uv op macOS: Python-versies, projecten en tools beheren
Automatische vertaling
Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.
Deze gids is bedoeld voor Python-ontwikkelaars op macOS die van pip, venv, pip-tools, pyenv of pipx overstappen naar uv. uv ondersteunt vier soorten werk: een project, een script in één bestand, een eenmalige CLI-uitvoering met uvx en een CLI die op PATH is geïnstalleerd. Alle vier kunnen de Python-versies gebruiken die uv installeert. Je leert de opdrachten voor elk en hoe je ertussen kiest.
Ik heb mijn eigen Python-workflow omgezet naar uv. Eén uitvoerbaar bestand doet nu het werk dat ik vroeger over die tools verdeelde.
Snel starten
# Install uv with Homebrew
brew install uv
# Start a project
uv init --no-package example-app
cd example-app
uv add httpx
uv run python main.py
# Prints "Hello from example-app!"
# Run an isolated CLI without installing it permanently
uvx ruff check .
De figuur toont waar elk van de vier workflows zijn omgeving bewaart, wat je per workflow bewaart en de beheerde Python-installaties die ze delen.
uv installeren en updaten
Homebrew is een handige manier om uv op macOS te installeren. In de installatiegids van uv staan de ondersteunde methoden:
brew install uv
uv --version
Als Homebrew uv heeft geïnstalleerd, upgrade je het ook met Homebrew:
brew upgrade uv
uv self update is bedoeld voor de standalone installatiemethode van uv en is uitgeschakeld bij installaties via een package manager. Upgrade uv met dezelfde tool waarmee je het hebt geïnstalleerd.
Zo zie je waar uv, de Python-installaties, de tools en de cache staan:
command -v uv
uv python dir
uv tool dir
uv cache dir
Beheerde Python-installaties, blijvend geïnstalleerde tools en verwijderbare cache-items hebben aparte mappen. Je kunt de cache verwijderen en opnieuw opbouwen. Hij is geen gezaghebbende gegevensbron. Op macOS kloont uv pakketten vanuit de cache naar elke omgeving (copy-on-write), in plaats van ze te kopiëren. Bij het opnieuw opbouwen van .venv hergebruikt uv benodigde artefacten die nog in de cache staan.
Projecten: declaraties, resolutie en omgeving
Een uv-project bestaat normaal uit drie delen:
pyproject.tomldeclareert de projectmetadata en de directe vereisten.uv.lockbevat de cross-platform resolutie van uv..venvis de lokaal geïnstalleerde omgeving en moet wegwerpbaar zijn.
De figuur sorteert de projectbestanden op wie ze schrijft en of git ze bewaart.
Maak een applicatie aan en voeg vereisten voor uitvoering en tests toe:
uv init --no-package forecast-app
cd forecast-app
uv add httpx
uv add --group test pytest
uv run python main.py
uv run --group test pytest --version
De toepassing toont Hello from forecast-app!; de laatste opdracht controleert of pytest is geïnstalleerd. Zodra je tests hebt, voer je ze uit met uv run --group test pytest.
De template --no-package maakt main.py, pyproject.toml, README.md en .python-version zonder buildsysteem. Sinds uv 0.12 maakt gewoon uv init een toepassing als package met een src-indeling en een build-backend. Gebruik uv init --lib voor een bibliotheek als package. Zie de gids voor het maken van projecten met uv.
uv run controleert het project, werkt de lock bij als dat nodig is, synchroniseert de vereiste afhankelijkheden en voert de opdracht uit. Zie de documentatie van uv over projectlayout en sync voor deze lifecycle. De eerste projectoperatie maakt .venv en uv.lock aan waar nodig. uv init zelf maakt alleen de projectbestanden aan.
uv installeert de groep dev standaard. Andere groepen, zoals test, hebben bij elke opdracht --group nodig, of default-groups onder [tool.uv]. Gebruik uv sync --only-group docs om één groep los te installeren, bijvoorbeeld in een docs-job in CI.
Groepen blijven lokaal en worden nooit gepubliceerd. Een gepubliceerde extra is iets anders: uv add --optional cli rich voegt een extra toe die gebruikers installeren als forecast-app[cli].
Om het project in Jupyter-notebooks in VS Code te gebruiken, voer je uv add --dev ipykernel uit en selecteer je .venv als kernel. Zie de Jupyter-gids van uv.
Commit de invoer, niet de omgeving
Commit pyproject.toml, uv.lock, de broncode en een bewust gekozen .python-version. Negeer .venv en de caches van uv.
Een teamgenoot die de repository kloont, krijgt de omgeving met vastgelegde versies met één opdracht:
git clone https://github.com/example/forecast-app.git
cd forecast-app
uv sync --locked
Zo zie je waarom een pakket geïnstalleerd is en zet je de lock op nieuwere versies:
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
Commit de gewijzigde uv.lock samen met de wijziging die dat nodig maakte.
De lock legt een resolutie vast over de ondersteunde markers en platforms heen. Hij maakt native wheels niet identiek op macOS, Linux, Intel en Apple Silicon. Test elk platform waarop je deployt.
uv kan een deel hiervan afdwingen. Met required-environments onder [tool.uv] mislukt de resolutie als een pakket zonder brondistributie geen wheel heeft voor een van de genoemde platforms:
[tool.uv]
required-environments = [
"sys_platform == 'darwin' and platform_machine == 'arm64'",
"sys_platform == 'linux' and platform_machine == 'x86_64'",
]
no-build-package verbiedt bouwen uit broncode voor de genoemde pakketten, zodat een ontbrekende wheel de installatie laat mislukken in plaats van een compiler te starten. Deploy je ook PyTorch op Linux met CUDA, volg dan de PyTorch-gids van uv voor de index-configuratie.
Actualiteit van de lock: --locked is niet --frozen
Standaard mogen projectopdrachten uv.lock bijwerken als de declaraties veranderen. Zie de documentatie van uv over locking en syncing voor de flags voor actualiteit en exactheid.
Gebruik --locked om te eisen dat de lock actueel is ten opzichte van de projectmetadata:
uv lock --check
uv sync --locked --group test
uv run --locked --group test pytest
Als pyproject.toml en uv.lock niet overeenkomen, mislukken deze opdrachten in plaats van nieuwe versies vast te leggen. Gebruik ze in CI, zodat een verouderde lock de build laat mislukken.
Gebruik --frozen alleen als je bewust wilt dat uv de bestaande lock gebruikt zonder te controleren of die actueel is:
uv sync --frozen
Dat kan nuttig zijn in een gecontroleerde build-stap waarin de lock al gevalideerd is, maar het detecteert geen verouderde lock.
De figuur volgt één verouderd project door vier opdrachten: rich is met de hand aan pyproject.toml toegevoegd en uv.lock is niet bijgewerkt.
Exactheid staat los van actualiteit. uv sync is standaard exact en verwijdert overbodige pakketten. uv run gebruikt standaard een niet-exacte sync, tenzij je --exact opgeeft. De figuur volgt één met de hand geïnstalleerd pakket door uv sync, uv run en uv run --exact.
Python-versies installeren en pinnen
uv kan Python-distributies downloaden en beheren:
uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12
De beheerde CPython-builds van uv komen uit het project python-build-standalone. uv kan ook interpreters van het systeem, Homebrew, pyenv, Conda en andere bronnen vinden. Zie de documentatie van uv over Python-versies voor de ondersteunde bronnen en het zoekgedrag.
.python-version is een versieverzoek dat uv en andere compatibele tools vinden. uv python pin schrijft dit bestand en uv init maakt er een aan. requires-python in pyproject.toml is het compatibiliteitscontract van het project. Kies beide bewust:
[project]
requires-python = ">=3.12,<3.14"
uv neemt het versieverzoek eerst uit --python, dan uit .python-version en dan uit requires-python.
Het pinnen van 3.12 garandeert niet voor altijd dezelfde patch-build, en ook niet hetzelfde artifact op elk besturingssysteem. Vraag een exacte patchversie aan als je die nodig hebt. Selecteer in CI de interpreter en print hem, met uv run --python 3.12.7 python -VV of door UV_PYTHON=3.12.7 voor de job in te stellen.
Gebruik een andere Python-manager als een project een distributie of buildconfiguratie nodig heeft die uv niet levert. uv kan die interpreter dan nog steeds gebruiken via --python of de normale zoekvolgorde.
Kiezen tussen uv run, uvx en geïnstalleerde tools
Kies op basis van de vraag of de tool de geïnstalleerde pakketten van het project nodig heeft, op PATH moet blijven of onafhankelijk kan draaien. De figuur toont welke afhankelijkheden beschikbaar zijn en hoe lang elke omgeving bestaat.
Tools die aan het project gekoppeld zijn: uv run
Als pytest, mypy, een codegenerator of een andere tool het project moet importeren of de gelockte plugins ervan moet gebruiken, declareer die tool dan in een afhankelijkhedengroep:
uv add --group lint ruff
uv run --group lint ruff check .
uvx installeert niet automatisch het pakket of de afhankelijkheden van het project. Een tool kan nog steeds lokale bronbestanden importeren als zijn importgedrag dat toestaat; gebruik uv run wanneer hij het geïnstalleerde project of de afhankelijkheden daarvan nodig heeft.
Ad-hoc tools: uvx
uvx is een alias voor uv tool run. Het hergebruikt een compatibele tool die met uv tool install is geïnstalleerd; anders gebruikt het een geïsoleerde omgeving in de verwijderbare uv-cache. De documentatie voor uv-tools beschrijft deze cache en de levensduur van blijvend geïnstalleerde tools:
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
Leg de toolversie vast in CI of de documentatie. Zonder geïnstalleerde tool kiest de eerste aanroep zonder versie de nieuwste beschikbare release; latere aanroepen kunnen de cachestatus hergebruiken. @latest negeert een geïnstalleerde versie en vernieuwt de cache voor de nieuwste release. Gebruik --from als de pakketnaam verschilt van de opdrachtnaam, zoals bij jupyterlab en httpie.
Blijvend beschikbare uitvoerbare bestanden: uv tool install
Installeer een tool wanneer scripts buiten jouw beheer de opdracht op PATH nodig hebben, of wanneer het setup-manifest van je machine de tool moet beheren:
uv tool install ruff
uv tool list
uv tool upgrade ruff
uv tool upgrade --all
uv tool uninstall ruff
Als de installatie waarschuwt dat de map met uitvoerbare bestanden niet op PATH staat, voer je uv tool update-shell uit en start je je shell opnieuw voordat je de opdracht gebruikt. Zie de documentatie voor uitvoerbare toolbestanden van uv.
Persistente tools gebruiken nog steeds geïsoleerde omgevingen. Pas die omgevingen niet met de hand aan met pip.
Scripts van één bestand met PEP 723
PEP 723 definieert inline scriptmetadata. Een compatibele runner kan het commentaarblok lezen en een geïsoleerde omgeving opbouwen. Zie de scriptgids van uv en PEP 723 voor het metadataformaat en het gedrag van de runner.
De figuur markeert het metadatablok in fetch.py en toont wat uv run en gewone python met het bestand doen.
uv kan het metadatablok voor je schrijven:
uv init --script fetch.py --python 3.12
Een afgerond script ziet er zo uit:
# /// 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)
Draai het script en bewerk de metadata met uv:
uv run fetch.py
uv add --script fetch.py rich
uv remove --script fetch.py rich
Een gewone python fetch.py negeert de metadata in het commentaar. Het script is daardoor afhankelijk van een compatibele runner, ook al blijft de Python-syntax geldig. uv is één runner. pipx run, Hatch en PDM lezen het blok ook.
Om het script als ./fetch.py te draaien, voeg je een shebang toe die uv aanroept:
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["httpx"]
# ///
import httpx
chmod +x fetch.py
./fetch.py
De flag -S laat env de regel opsplitsen in losse argumenten, zodat --script bij uv aankomt.
Voor een snel experiment geef je afhankelijkheden op de opdrachtregel mee in plaats van metadata te schrijven. De tweede regel start een Python-REPL waarin pandas beschikbaar is:
uv run --with httpx scratch.py
uv run --with pandas python
Maak voor een script dat later dezelfde resolutie moet reproduceren een lock ernaast aan:
uv lock --script fetch.py
uv run --script fetch.py
Dit schrijft fetch.py.lock. Met een exclude-newer-tijdstempel in het metadatablok negeert uv packageversies die na die datum zijn gepubliceerd:
# /// script
# dependencies = ["httpx"]
# [tool.uv]
# exclude-newer = "2025-04-17T00:00:00Z"
# ///
Dit is zwakker dan een lock. Het pint geen exacte versies en kan geen bestand terughalen dat de index later verwijdert.
Gebruik in plaats daarvan een project als meerdere bestanden afhankelijkheden delen, de code als package importeerbaar is, tests projectstatus nodig hebben of meerdere scripts samen moeten meebewegen.
Bestaande projecten met requirements.txt
Een requirements.txt-bestand kan niet-vastgelegde vereisten, exacte pins, hashes, constraints, indexes, URL’s of een door een resolver gegenereerde requirements-export bevatten. Hoe reproduceerbaar het is, hangt af van hoe het is gemaakt en gebruikt. De bestandsnaam alleen zegt niets.
Je hebt twee opties: het pip-formaat behouden en uitvoeren met uv pip, of, voor een applicatie die van jou is, migreren naar uv.lock.
Gebruik voor een volledig opgelost bestand met directe en transitieve afhankelijkheden de pip-compatibele interface van uv zonder te migreren:
uv venv
uv pip sync requirements.txt
.venv/bin/python app.py
Voer hier de geïnstalleerde interpreter rechtstreeks uit. Als er een pyproject.toml aanwezig is, kan uv run de vereisten ervan vóór uitvoering vastleggen en synchroniseren, waardoor het de zojuist geïnstalleerde pakketten vervangt. Zie de scriptgids van uv.
uv pip sync laat de omgeving overeenkomen met een volledig opgelost bestand. Als requirements.txt alleen directe vereisten bevat, gebruik je uv pip install -r requirements.txt om hun afhankelijkheden op te lossen en te installeren. uv pip install -r voegt pakketten toe. Zie de pip-lockinggids van uv.
Voor een applicatie die je zelf beheert, kan een gefaseerde migratie nuttig zijn:
uv init --bare
uv add -r requirements.in
uv add --group test -r requirements-test.in
uv lock
uv sync --locked
Doorloop het volledige test- en deploymentpad voordat je oude bestanden verwijdert. Als een downstream systeem nog het pip-formaat verwacht, leid het dan af van de gevalideerde uv-lock met het export-command van uv:
uv export --format requirements.txt \
--output-file requirements.txt
Onderhoud uv.lock en een met de hand bewerkte export niet als twee concurrerende resoluties.
Cache en privé-indexen
De cache van uv versnelt herhaalde installaties, maar blijft wegwerpbaar:
uv cache prune
uv cache clean
Gebruik bij voorkeur prune voor routinematig opruimen. clean verwijdert alle cache-items en dwingt latere downloads en builds af.
Een lockfile maakt installaties beter herhaalbaar. Het maakt afhankelijkheden niet betrouwbaar.
Zet voor een privé-index de naam en URL in pyproject.toml en houd de inloggegevens buiten het bestand:
[[tool.uv.index]]
name = "internal"
url = "https://pypi.example.com/simple"
Geef de inloggegevens mee via UV_INDEX_INTERNAL_USERNAME en UV_INDEX_INTERNAL_PASSWORD, of via keyring. uv leidt de namen van de variabelen af van de indexnaam. Zie de documentatie van uv over index-authenticatie.
Oude opdrachten en hun uv-equivalenten
Stap je over van de oudere tools, dan koppelt deze tabel elke bekende opdracht aan de uv-opdracht die hetzelfde doet.
| Taak | Voorheen | uv |
|---|---|---|
| Python installeren | pyenv install 3.12 | uv python install 3.12 |
| Nieuw project en omgeving | mkdir proj && cd proj && python -m venv .venv | uv init proj && cd proj && uv sync |
| Een pakket toevoegen | pip install pandas && pip freeze > requirements.txt | uv add pandas |
| Pins compileren | pip-compile requirements.in | uv lock |
| Eén pakket bijwerken | pip-compile --upgrade-package httpx | uv lock --upgrade-package httpx |
| Draaien in de omgeving | source .venv/bin/activate && python app.py | uv run app.py |
| Script met afhankelijkheden | een handmatige venv voor één bestand | PEP 723-blok + uv run |
| Een tool één keer draaien | pipx run black | uvx black |
| Een tool installeren | pipx install ruff | uv tool install ruff |
| Reproduceerbare installatie in CI | pip install -r requirements.txt | uv sync --locked |
Een compacte checklist voor het dagelijks gebruik
Per project:
- Definieer
requires-pythonen de directe afhankelijkheden inpyproject.toml. - Houd gepubliceerde extras (
--optional) gescheiden van lokale afhankelijkhedengroepen (--group). - Commit
uv.lock. Negeer.venven de cachestatus. - Draai tools die aan het project gekoppeld zijn via de projectomgeving.
- Gebruik
uv lock --checkof--lockedin CI. - Test elk doel-OS en elke architectuur die de lock dekt.
- Exporteer compatibiliteitsformaten alleen voor benoemde downstream gebruikers.
- Houd inloggegevens voor indexen buiten gecommitte bestanden. Geef ze mee via omgevingsvariabelen of keyring.
Ik gebruik uv als mijn standaard Python-tool op macOS, omdat één uitvoerbaar bestand deze taken afhandelt en project- en toolafhankelijkheden gescheiden houdt.