uv no macOS: gerir versões de Python, projetos e ferramentas

Tradução automática

Este artigo foi traduzido automaticamente a partir da versão original em inglês.

Este guia destina-se a programadores Python no macOS que passam de pip, venv, pip-tools, pyenv ou pipx para uv. O uv suporta quatro tipos de trabalho: um projeto, um script num único ficheiro, uma execução pontual de uma CLI com uvx e uma CLI instalada no PATH. Os quatro podem usar as versões de Python que o uv instala. Aprenderá os comandos de cada um e como escolher entre eles.

Mudei o meu próprio fluxo de trabalho em Python para o uv. Um único executável cobre agora o trabalho que antes repartia por essas ferramentas.

Início rápido

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

A figura mostra onde cada um dos quatro fluxos de trabalho guarda o seu ambiente, o que guarda em cada caso e as instalações de Python geridas que partilham.

Quatro fluxos de trabalho do uv e as suas zonas de armazenamento: a .venv do projeto junto de pyproject.toml e uv.lock, ambientes de scripts e uvx na cache descartável do uv, um ambiente de ferramenta instalada que o uvx pode reutilizar no diretório de ferramentas, e instalações geridas de Python para os quatro. Os comandos instalados precisam do diretório de executáveis no PATHQuatro fluxos de trabalho do uv e as suas zonas de armazenamento: a .venv do projeto junto de pyproject.toml e uv.lock, ambientes de scripts e uvx na cache descartável do uv, um ambiente de ferramenta instalada que o uvx pode reutilizar no diretório de ferramentas, e instalações geridas de Python para os quatro. Os comandos instalados precisam do diretório de executáveis no PATH

Instalar e atualizar o uv

O Homebrew é uma forma prática de instalar no macOS. Consulte o guia de instalação do uv para ver os métodos suportados:

brew install uv
uv --version

Se foi o Homebrew a instalar o uv, deve ser o Homebrew a atualizá-lo:

brew upgrade uv

uv self update serve para o método de instalação autónomo do uv e está desativado nas instalações feitas por gestores de pacotes. Atualize o uv com a mesma ferramenta que o instalou.

Para ver onde ficam o uv, as suas instalações de Python, as suas ferramentas e a sua cache:

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

As instalações geridas de Python, as ferramentas persistentes e as entradas descartáveis da cache têm diretórios separados. A cache pode ser apagada e reconstruída. Não é uma fonte de referência. No macOS, o uv clona pacotes da cache para cada ambiente (cópia na escrita), em vez de os copiar. Ao reconstruir a .venv, reutiliza os artefactos necessários que ainda estejam na cache.

Projetos: declarações, resolução e ambiente

Um projeto uv tem normalmente três partes:

  • pyproject.toml declara os metadados do projeto e os requisitos diretos.
  • uv.lock guarda a resolução multiplataforma do uv.
  • .venv é o ambiente instalado localmente e deve ser descartável.

A figura separa os ficheiros do projeto por quem os escreve e por o git os guardar ou não.

Edita pyproject.toml, .python-version e o código-fonte; uv lock escreve uv.lock; os quatro entram no commit. uv sync cria o .venv a partir de uv.lock, com os pacotes clonados da cache do uv, e ambos ficam fora do gitEdita pyproject.toml, .python-version e o código-fonte; uv lock escreve uv.lock; os quatro entram no commit. uv sync cria o .venv a partir de uv.lock, com os pacotes clonados da cache do uv, e ambos ficam fora do git

Crie uma aplicação e adicione requisitos de execução e de teste:

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

A aplicação apresenta Hello from forecast-app!; o último comando verifica se o pytest está instalado. Quando tiver testes, execute-os com uv run --group test pytest.

O modelo --no-package cria main.py, pyproject.toml, README.md e .python-version sem um sistema de construção. Desde o uv 0.12, um simples uv init cria uma aplicação empacotada com uma estrutura src e um backend de construção. Use uv init --lib para uma biblioteca empacotada. Consulte o guia de criação de projetos do uv.

uv run verifica o projeto, atualiza o lock quando é preciso, sincroniza as dependências necessárias e executa o comando. Consulte a documentação do uv sobre estrutura de projetos e sincronização para ver este ciclo de vida. A primeira operação no projeto cria .venv e uv.lock conforme necessário. O próprio uv init só cria os ficheiros do projeto.

O uv instala o grupo dev por omissão. Outros grupos, como test, precisam de --group em cada comando, ou de default-groups em [tool.uv]. Para instalar apenas um grupo, por exemplo numa tarefa de CI para a documentação, use uv sync --only-group docs.

Os grupos ficam locais e nunca são publicados. Um extra publicado é diferente: uv add --optional cli rich adiciona um extra que os utilizadores instalam como forecast-app[cli].

Para usar o projeto em notebooks Jupyter no VS Code, execute uv add --dev ipykernel e selecione .venv como kernel. Consulte o guia do uv para Jupyter.

Faça commit das entradas, não do ambiente

Faça commit de pyproject.toml, uv.lock, do código-fonte e de um .python-version intencional. Ignore .venv e as caches do uv.

Um colega que clone o repositório obtém o ambiente bloqueado com um só comando:

git clone https://github.com/example/forecast-app.git
cd forecast-app
uv sync --locked

Para ver porque está instalado um pacote e para mover o lock para versões mais recentes:

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

Faça commit do uv.lock alterado junto com a alteração que o exigiu.

O lock regista uma resolução para os marcadores e plataformas suportados. Não torna as wheels nativas idênticas entre macOS, Linux, Intel e Apple Silicon. Teste todas as plataformas de implementação.

O uv consegue impor parte disto. required-environments em [tool.uv] faz a resolução falhar quando um pacote sem distribuição de código-fonte não tem wheel para uma plataforma da lista:

[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'arm64'",
    "sys_platform == 'linux' and platform_machine == 'x86_64'",
]

no-build-package proíbe builds a partir do código-fonte para os pacotes indicados, pelo que uma wheel em falta faz a instalação falhar em vez de iniciar um compilador. Se também implementar PyTorch em Linux com CUDA, siga o guia do uv para PyTorch para configurar o índice.

Atualidade do lock: --locked não é --frozen

Por omissão, os comandos de projeto podem atualizar uv.lock quando as declarações mudam. Consulte a documentação do uv sobre lock e sincronização para ver as flags de atualidade e de exatidão.

Use --locked para exigir que o lock esteja atualizado em relação aos metadados do projeto:

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

Se pyproject.toml e uv.lock não estiverem de acordo, estes comandos falham em vez de resolverem um novo lock. Use-os em CI para que um lock desatualizado faça falhar o build.

Use --frozen apenas quando quiser intencionalmente que o uv use o lock existente sem verificar se está atualizado:

uv sync --frozen

Isto pode ser útil numa fase de build controlada em que o lock já foi validado, mas não deteta locks desatualizados.

A figura acompanha um projeto desatualizado ao longo de quatro comandos: rich foi adicionado à mão a pyproject.toml e uv.lock não foi atualizado.

Com rich em pyproject.toml mas não em uv.lock: uv sync reescreve o lock e instala rich, uv sync --locked e uv lock --check falham, e uv sync --frozen instala httpx sem rich enquanto o CI continua verdeCom rich em pyproject.toml mas não em uv.lock: uv sync reescreve o lock e instala rich, uv sync --locked e uv lock --check falham, e uv sync --frozen instala httpx sem rich enquanto o CI continua verde

A exatidão é uma definição separada da atualidade. uv sync é exato por omissão e remove pacotes a mais. uv run usa uma sincronização não exata por omissão, a menos que se peça --exact. A figura acompanha um pacote instalado à mão ao longo de uv sync, uv run e uv run --exact.

Um .venv com httpx, ipykernel e um extra-pkg instalado à mão: uv sync e uv run --exact removem extra-pkg, uv run mantém-noUm .venv com httpx, ipykernel e um extra-pkg instalado à mão: uv sync e uv run --exact removem extra-pkg, uv run mantém-no

Instalar e fixar versões de Python

O uv consegue descarregar e gerir distribuições de Python:

uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12

As builds de CPython geridas pelo uv vêm do projeto python-build-standalone. O uv também consegue descobrir interpretadores do sistema, do Homebrew, do pyenv, do Conda e outros. Consulte a documentação do uv sobre versões de Python para ver as fontes suportadas e o comportamento da descoberta.

.python-version é um pedido de versão que o uv e outras ferramentas compatíveis descobrem. uv python pin escreve este ficheiro e uv init cria um. requires-python em pyproject.toml é o contrato de compatibilidade do projeto. Escolha ambos de forma deliberada:

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

O uv toma o pedido de versão primeiro de --python, depois de .python-version e por fim de requires-python.

Fixar 3.12 não garante a mesma build de patch para sempre nem o mesmo artefacto em todos os sistemas operativos. Peça um patch exato quando precisar de um. Em CI, selecione o interpretador e imprima-o, com uv run --python 3.12.7 python -VV ou definindo UV_PYTHON=3.12.7 para a tarefa.

Use outro gestor de Python quando um projeto precisar de uma distribuição ou configuração de build que o uv não fornece. O uv continua a poder usar esse interpretador através de --python ou da descoberta normal.

Escolher entre uv run, uvx e ferramentas instaladas

Escolha consoante a ferramenta precisa dos pacotes instalados do projeto, tem de permanecer no PATH ou pode funcionar de forma independente. A figura mostra as dependências disponíveis e quanto tempo dura cada ambiente.

O uv run usa a .venv do projeto e as suas dependências fixadas; o uvx usa um ambiente separado de uma ferramenta em cache ou instalada, sem instalar automaticamente as dependências do projeto; o uv tool install mantém um ambiente no diretório de ferramentas e disponibiliza o comando depois de configurar o PATHO uv run usa a .venv do projeto e as suas dependências fixadas; o uvx usa um ambiente separado de uma ferramenta em cache ou instalada, sem instalar automaticamente as dependências do projeto; o uv tool install mantém um ambiente no diretório de ferramentas e disponibiliza o comando depois de configurar o PATH

Ferramentas ligadas ao projeto: uv run

Se o pytest, o mypy, um gerador de código ou outra ferramenta tiver de importar o projeto ou usar os seus plugins bloqueados no lock, declare-a num grupo de dependências:

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

O uvx não instala automaticamente o pacote nem as dependências do projeto. Uma ferramenta pode continuar a importar ficheiros de código-fonte locais se o seu funcionamento o permitir; use uv run quando precisar do projeto instalado ou das suas dependências.

Ferramentas pontuais: uvx

O uvx é um alias de uv tool run. Reutiliza uma ferramenta compatível instalada com uv tool install; caso contrário, usa um ambiente isolado guardado na cache descartável do uv. A documentação das ferramentas do uv descreve esta cache e o ciclo de vida das ferramentas persistentes:

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

Fixe a versão da ferramenta no CI ou na documentação. Sem uma ferramenta instalada, a primeira chamada sem versão seleciona a versão mais recente disponível; as chamadas seguintes podem reutilizar o estado da cache. O @latest ignora uma versão instalada e atualiza a cache para a versão mais recente. Use --from quando o nome do pacote difere do nome do comando, como acontece com jupyterlab e httpie.

Executáveis persistentes: uv tool install

Instale uma ferramenta quando scripts que não controla precisarem do seu comando no PATH, ou quando o manifesto de configuração da sua máquina a deva gerir:

uv tool install ruff
uv tool list
uv tool upgrade ruff
uv tool upgrade --all
uv tool uninstall ruff

Se a instalação avisar que o diretório de executáveis não está no PATH, execute uv tool update-shell e reinicie a shell antes de usar o comando. Consulte a documentação dos executáveis das ferramentas do uv.

As ferramentas persistentes continuam a usar ambientes isolados. Não altere esses ambientes manualmente com pip.

Scripts de ficheiro único com PEP 723

O PEP 723 define metadados de script inline. Um executor compatível consegue ler o bloco de comentários e construir um ambiente isolado. Consulte o guia do uv sobre scripts e o PEP 723 para ver o formato dos metadados e o comportamento do executor.

A figura assinala o bloco de metadados em fetch.py e mostra o que uv run e o python simples fazem com o ficheiro.

fetch.py com o bloco de comentário PEP 723 realçado: uv run lê o bloco, encontra Python 3.12 ou superior, instala httpx num ambiente isolado e executa o código; python fetch.py executa apenas o códigofetch.py com o bloco de comentário PEP 723 realçado: uv run lê o bloco, encontra Python 3.12 ou superior, instala httpx num ambiente isolado e executa o código; python fetch.py executa apenas o código

O uv pode escrever o bloco de metadados por si:

uv init --script fetch.py --python 3.12

Um script terminado tem este aspeto:

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

Execute e edite os metadados com o uv:

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

Um simples python fetch.py ignora os metadados no comentário. Por isso, o script depende de um executor compatível, embora a sintaxe Python continue válida. O uv é um desses executores. pipx run, o Hatch e o PDM também leem o bloco.

Para executar o script como ./fetch.py, adicione um shebang que chame o uv:

#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["httpx"]
# ///
import httpx
chmod +x fetch.py
./fetch.py

A flag -S faz com que o env divida a linha em argumentos separados, para que --script chegue ao uv.

Para uma experiência rápida, passe as dependências na linha de comandos em vez de escrever metadados. A segunda linha abre um REPL de Python com o pandas disponível:

uv run --with httpx scratch.py
uv run --with pandas python

Para um script que tenha de reproduzir uma resolução mais tarde, crie um lock ao lado:

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

Isto escreve fetch.py.lock. Uma marca temporal exclude-newer no bloco de metadados faz o uv ignorar versões de pacotes publicadas depois dessa data:

# /// script
# dependencies = ["httpx"]
# [tool.uv]
# exclude-newer = "2025-04-17T00:00:00Z"
# ///

É mais fraco do que um lock. Não fixa versões exatas e não consegue recuperar um ficheiro que o índice remova mais tarde.

Use antes um projeto quando vários ficheiros partilham dependências, o código é importável como pacote, os testes precisam do estado do projeto ou vários scripts têm de evoluir em conjunto.

Projetos existentes com requirements.txt

Um ficheiro requirements.txt pode conter entradas soltas, versões fixadas exatas, hashes, restrições, índices, URLs ou uma exportação de requisitos gerada por um resolvedor. A sua reprodutibilidade depende de como foi produzido e consumido. O nome do ficheiro, por si só, não diz nada.

Há duas opções: manter o formato do pip e executá-lo com uv pip ou, para uma aplicação que é sua, migrar para uv.lock.

Para um ficheiro totalmente resolvido que enumere dependências diretas e transitivas, use a interface do uv compatível com pip sem migrar:

uv venv
uv pip sync requirements.txt
.venv/bin/python app.py

Execute aqui diretamente o interpretador instalado. Se existir um pyproject.toml, o uv run pode fixar e sincronizar os seus requisitos antes da execução, substituindo os pacotes que acabou de instalar. Consulte o guia de scripts do uv.

O uv pip sync faz o ambiente corresponder a um ficheiro totalmente resolvido. Se o requirements.txt contiver apenas requisitos diretos, use uv pip install -r requirements.txt para resolver e instalar as respetivas dependências. O uv pip install -r adiciona pacotes. Consulte o guia de fixação de versões do uv compatível com pip.

Para uma aplicação sua, uma migração por etapas pode ser útil:

uv init --bare
uv add -r requirements.in
uv add --group test -r requirements-test.in
uv lock
uv sync --locked

Execute todo o processo de testes e de implementação antes de apagar os ficheiros antigos. Se um sistema a jusante ainda esperar o formato do pip, gere-o a partir do lock do uv já validado com o comando de exportação do uv:

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

Não mantenha uv.lock e uma exportação editada à mão como duas resoluções concorrentes.

Cache e índices privados

A cache do uv acelera instalações repetidas, mas continua a ser descartável:

uv cache prune
uv cache clean

Prefira prune para a limpeza de rotina. clean remove todas as entradas da cache e obriga a repetir os descarregamentos e as construções mais tarde.

Um lockfile melhora a repetibilidade. Não torna as dependências fiáveis.

Para um índice privado, coloque o seu nome e URL em pyproject.toml e mantenha as credenciais fora do ficheiro:

[[tool.uv.index]]
name = "internal"
url = "https://pypi.example.com/simple"

Passe as credenciais através de UV_INDEX_INTERNAL_USERNAME e UV_INDEX_INTERNAL_PASSWORD, ou através do keyring. O uv constrói os nomes das variáveis a partir do nome do índice. Consulte a documentação do uv sobre autenticação em índices.

Comandos antigos e os seus equivalentes no uv

Se está a mudar das ferramentas antigas, esta tabela associa cada comando conhecido ao comando do uv que faz o mesmo trabalho.

TarefaAntesuv
Instalar Pythonpyenv install 3.12uv python install 3.12
Novo projeto e ambientemkdir proj && cd proj && python -m venv .venvuv init proj && cd proj && uv sync
Adicionar um pacotepip install pandas && pip freeze > requirements.txtuv add pandas
Compilar versões fixadaspip-compile requirements.inuv lock
Atualizar um pacotepip-compile --upgrade-package httpxuv lock --upgrade-package httpx
Executar no ambientesource .venv/bin/activate && python app.pyuv run app.py
Script com dependênciasum venv manual para um ficheirobloco PEP 723 + uv run
Executar uma ferramentapipx run blackuvx black
Instalar uma ferramentapipx install ruffuv tool install ruff
Instalação reprodutível (CI)pip install -r requirements.txtuv sync --locked

Uma checklist operacional compacta

Para cada projeto:

  1. Defina requires-python e as dependências diretas em pyproject.toml.
  2. Separe os extras publicados (--optional) dos grupos de dependências locais (--group).
  3. Faça commit de uv.lock. Ignore .venv e o estado da cache.
  4. Execute as ferramentas ligadas ao projeto através do ambiente do projeto.
  5. Use uv lock --check ou --locked em CI.
  6. Teste todos os sistemas operativos e arquiteturas de destino representados no lock.
  7. Exporte formatos de compatibilidade apenas para consumidores a jusante concretos.
  8. Mantenha as credenciais dos índices fora dos ficheiros no commit. Passe-as através de variáveis de ambiente ou do keyring.

Uso o uv como ferramenta Python predefinida no macOS porque um único executável cobre estas tarefas e mantém separadas as dependências dos projetos e das ferramentas.

Referências