[!NOTE] Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.

UV op macOS: Beheer van Python-versies, projecten en tools

Ik ben overgestapt van mijn Python workflow naar uv, omdat dit hulpmiddel de vervanging is voor de verschillende tools die ik eerder gebruikte om te wisselen tussen pip, virtuele omgevingen, pip-tools, pipx en projectbeheersoftware. Nu kan één enkel uitvoerbaar bestand het grootste deel van deze taken uitvoeren.

De workflows verschillen nog steeds van elkaar. Een project, een script voor inline-metadata, eenmalige CLI-tools en geïnstalleerde CLI-tools hebben elk hun eigen omgeving en levenscyclus. Deze gids laat de commando’s zien die ik gebruik, evenals de grenzen die tussen deze componenten bestaan.

Snel starten

# 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 .

# Run a script that declares PEP 723 dependencies
uv run fetch.py

TL;DR. Ik gebruik uv add, uv lock, uv sync, en uv run binnen projecten; PEP 723-metadata voor zelfstandige scripts; uvx voor eenmalige tools; en uv tool install voor commando’s die op hun plek moeten blijven PATH. In CI, --locked verifieert of de projectmetadata overeenkomt met uv.lock; --frozen Vertrouwt op het bestaande slot zonder de versheid te controleren.

uv installeren met één eigenaar

Homebrew is een handige installatiemethode voor macOS:

brew install uv
uv --version

Als Homebrew uv heeft geïnstalleerd, moet Homebrew deze upgraden:

brew upgrade uv

uv self update Dit is bedoeld voor de standaardinstallatiemethode van UV’s en is uitgeschakeld bij installaties via een package-manager. Laat twee installers niet concurreren om hetzelfde uitvoerbare bestand.

Handige identiteitscommando’s:

command -v uv
uv python dir
uv tool dir
uv cache dir

Gemanageerde Python-installaties, permanente hulpprogramma’s en tijdelijke cache-entiteiten hebben afzonderlijke mappen. De cache kan worden verwijderd en opnieuw aangemaakt; het vormt geen bron van waarheid.

De vier grenzen van de UV workflow

Projecten: declaraties, resolutie en omgeving

Een UV-project bevat doorgaans drie verschillende artefacten:

Invoergegevens en afgeleide toestand in een UV-project

Maak een applicatie aan en voeg runtime en de testvereisten toe:

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

De huidige sjablonen voor UV-toepassingen genereren main.py, pyproject.toml, README.md, en .python-version. Ze definiëren standaard geen build-systeem. Gebruik uv init --lib Voor een geïmpakte bibliotheek met een src het opmaken en de compilatie van backend.

uv run controleert het project, bijwerkt het lock wanneer nodig, synchroniseert de benodigde afhankelijkheden en voert de opdracht uit. De eerste projectoperatie genereert .venv en uv.lock indien nodig; uv init Het creëert zelf uitsluitend de projectbestanden.

Voer de commits in, niet de omgeving

Committen pyproject.toml, uv.lockbron, en een opzettelijke .python-version. Ignoreren. .venv en de caches van de UV’s.

Het slot slaat een oplossing op voor alle ondersteunde markers en platforms; het zorgt er echter niet voor dat de native modules identiek zijn op macOS, Linux, Intel en Apple Silicon. Test elke deployment-platform.

Versheid beveiligen: --locked is niet --frozen

Als standaard kunnen projectcommando’s worden bijgewerkt uv.lock wanneer de declaraties veranderen.

Gebruik --locked om te vereisen dat het slot is bijgewerkt met de projectmetadata:

uv lock --check
uv sync --locked
uv run --locked pytest

Als pyproject.toml en uv.lock Ik ben het niet met je eens: deze commando’s falen in plaats van een nieuwe lock op te lossen. Dit zou normaal gesproken de nuttige CI-gate moeten zijn.

Gebruik --frozen Alleen wanneer je opzettelijk wilt dat de UV de bestaande lock gebruikt, zonder te controleren of deze actueel is:

uv sync --frozen

Dat kan nuttig zijn in een gecontroleerde bouwfase waarin de lock al is geverifieerd, maar het is geen detector voor verouderde locks. uv sync De standaardwaarde is ‘exact’, waardoor onnodige pakketten worden verwijderd. uv run gebruikt standaard een onnauwkeurige synchronisatie, tenzij --exact Er wordt om gevraagd.

Gemanaged Python: een versieverzoek, geen universele binary

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 door UV’s beheerde CPython-builds komen van de python-build-standalone project. UV kan ook systemen, Homebrew, pyenv, Conda en andere interpreters ontdekken.

.python-version Het is een versienummerverzoek dat wordt gedetecteerd door UV en andere compatibele hulpprogramma’s. requires-python in pyproject.toml Dit vormt het compatibiliteitscontract van het project. Houd beide aspecten bewust in overweging:

[project]
requires-python = ">=3.12,<3.14"

Pinnen 3.12 Het garandeert niet dat dezelfde patch-build voor altijd beschikbaar blijft, noch dat hetzelfde artefact op elke besturingssysteem wordt geleverd. Vraag om een exacte patch wanneer dit daadwerkelijk noodzakelijk is, en zorg ervoor dat de CI-exploitant expliciet de juiste interpreter selecteert en rapporteert.

Gebruik een andere Python-manager wanneer een project een distributie of bouwconfiguratie nodig heeft die uv niet biedt. uv kan die interpreter nog steeds gebruiken via --python of normale ontdekking.

Kies uit uv run, uvxen geïnstalleerde hulpprogramma’s

Het kiezen van een tijdelijk of permanente toolomgeving voor een project

Projectgerelateerde hulpmiddelen: uv run

Als pytest, mypy, een codegenerator of een ander hulpprogramma het project moet importeren of zijn gegrendelde plugins moet gebruiken, declareer dit dan in een afhankelijkheidsgroep:

uv add --group lint ruff
uv run --group lint ruff check .

Het uitvoeren van die tool uvx Dit zal het agentobject isoleren van het project en kan de geïnstalleerde pakketten of plugins die het nodig heeft verbergen.

Ad-hoc hulpmiddelen: uvx

uvx is een alias voor uv tool run. Het creëert een geïsoleerd omgeving die wordt opgeslagen in de wegwerpcache voor UV:

uvx ruff@0.12.0 check .
uvx --from jupyterlab jupyter lab
uvx --with mkdocs-material mkdocs --help

Pin de toolversie in CI of de documentatie. Een eerste oproep zonder versienummer kiest een huidige release, zodat latere oproepen de cache-toestand kunnen hergebruiken.

Persistente uitvoerbare bestanden: uv tool install

Installeer een hulpprogramma wanneer scripts die niet onder uw controle vallen zijn commando daarvan nodig hebben. PATH, of wanneer het machine-manifest het opzettelijk bezit:

uv tool install 'ruff==0.12.0'
uv tool list
uv tool upgrade ruff
uv tool uninstall ruff

Persistente hulpprogramma’s maken nog steeds gebruik van geïsoleerde omgevingen. Mutatie van deze omgevingen via pip is niet toegestaan.

Scripts: maak één bestand tot de release-eenheid

PEP 723 definieert metadata voor inline-scripts. Een compatibele uitvoerder kan de commentaarblokken lezen om een geïsoleerde omgeving op te zetten.

Anatomie van een PEP 723-script

# /// 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)

Voer metadata uit en bewerk deze met uv:

uv run fetch.py
uv add --script fetch.py rich
uv remove --script fetch.py rich

Eenvoudig python fetch.py Het negeert de commentaar-metadata. Daarom is het script afhankelijk van een compatibele runner, ook al blijft de Python-syntaxis geldig.

Voor een script dat later een resolutie moet reproduceren, maak dan een aangrenzende lock aan:

uv lock --script fetch.py
uv run --script fetch.py

Dit schrijft. fetch.py.lock. Een exclude-newer Een tijdstempel kan de mogelijke distributiedata van artefacten beperken, maar het is zwakker dan een exact vastgesteld resolutietijdpunt en garandeert niet dat het artefact nog steeds beschikbaar blijft.

Gebruik in plaats daarvan een project wanneer meerdere bestanden afhankelijkheden delen, de code als pakket kan worden geïmporteerd, tests toegang hebben moeten tot de projecttoestand, of meerdere scripts samen moeten worden verplaatst.

Vereistenbestanden: compatibiliteit, geen fouten

A requirements.txt Een bestand kan losse invoergegevens, exacte pinwaarden, hashes, beperkingen, indexen, URL’s of een gecompileerde omgeving bevatten. De reproduceerbaarheid ervan hangt af van de manier waarop het is gegenereerd en verwerkt; alleen de bestandsnaam zegt niets over de inhoud.

Gebruik de pip-compatibele interface van uv zonder migratie:

uv venv
uv pip sync requirements.txt
uv run python app.py

uv pip sync zorgt ervoor dat de omgeving overeenkomt met het bestand, terwijl uv pip install -r Het is additief.

Voor een eigen applicatie 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

Voer eerst de volledige test uit en het pad deployment voordat je oude bestanden verwijdert. Mocht een downstream-systeem nog steeds een pip-formaat verwachten, kan dit worden afgeleid uit de geverifieerde uv lock:

uv export --format requirements.txt \
  --output-file requirements.txt

Verzorg geen onderhoud. uv.lock en een handmatig bewerkte export als twee concurrerende resoluties.

Cache, indexen en grenzen van de toeleveringsketen

De UV-cache verbetert herhaalde installaties, maar blijft tijdelijk van aard:

uv cache prune
uv cache clean

Geef de voorkeur aan prune voor routinematige opruiming. clean Het verwijdert alle cache-entrieën en zorgt erop dat latere downloads en builds opnieuw uitgevoerd worden.

Een lockfile bevordert de herhaalbaarheid; het maakt afhankelijkheden echter niet betrouwbaarder. Controleer de bronnen van pakketten, de configuratie van de index, Git-revisies, de backends-processen, licenties en aanmeldgegevens. Houd de geauthenticeerde indexconfiguratie buiten de gecommitteerde bestanden, tenzij de repository alleen niet-vertrouwelijke referenties naar een goedgekeurd mechanisme voor aanmeldgegevens bevat.

Voor native pakketten dient u de deployment architectuur vast te leggen en te controleren of er beschikbare testversies zijn. Anders kan een resolver terugvallen op een bronbouw die compilers en systeembibliotheken vereist die afwezig zijn in de CI-omgeving of in productie.

Een compacte controlelijst voor het opstarten

Voor elk project:

  1. Definieer requires-python en directe afhankelijkheden daarin pyproject.toml2. Zorg ervoor dat gepubliceerde extra’s gescheiden zijn van lokale afhankelijkheidsgroepen.
  2. Voer een commit uit. uv.lock; negeren .venv en cache-toestand.
  3. Voer projectgerelateerde hulpprogramma’s uit via de projectomgeving.
  4. Gebruik uv lock --check of --locked in de CI-pipeline.
  5. Test elke doelbesturingssysteem en architectuur die door het lock-file wordt weergegeven.
  6. Exporteer compatibiliteitsformaten uitsluitend voor genoemde downstream-consumenten.
  7. Beoordeel de broncode- en credentialbeleidsregels los van het resolutieproces.

UV is het meest nuttig wanneer deze eigendomsgrenzen zichtbaar blijven. Eén binary kan ze allemaal beheren zonder ze om te zetten in één enkel omgeving. Die combinatie – minder tools, zonder te doen alsof elke workflow identiek is – is de reden waarom ik het nog steeds gebruik als mijn standaardhulpprogramma voor Python-projecten op macOS.

Referenties