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.
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.tomldeclara os metadados do projeto e os requisitos diretos.uv.lockguarda 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.
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.
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.
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.
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.
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.
| Tarefa | Antes | uv |
|---|---|---|
| Instalar Python | pyenv install 3.12 | uv python install 3.12 |
| Novo projeto e ambiente | mkdir proj && cd proj && python -m venv .venv | uv init proj && cd proj && uv sync |
| Adicionar um pacote | pip install pandas && pip freeze > requirements.txt | uv add pandas |
| Compilar versões fixadas | pip-compile requirements.in | uv lock |
| Atualizar um pacote | pip-compile --upgrade-package httpx | uv lock --upgrade-package httpx |
| Executar no ambiente | source .venv/bin/activate && python app.py | uv run app.py |
| Script com dependências | um venv manual para um ficheiro | bloco PEP 723 + uv run |
| Executar uma ferramenta | pipx run black | uvx black |
| Instalar uma ferramenta | pipx install ruff | uv tool install ruff |
| Instalação reprodutível (CI) | pip install -r requirements.txt | uv sync --locked |
Uma checklist operacional compacta
Para cada projeto:
- Defina
requires-pythone as dependências diretas empyproject.toml. - Separe os extras publicados (
--optional) dos grupos de dependências locais (--group). - Faça commit de
uv.lock. Ignore.venve o estado da cache. - Execute as ferramentas ligadas ao projeto através do ambiente do projeto.
- Use
uv lock --checkou--lockedem CI. - Teste todos os sistemas operativos e arquiteturas de destino representados no lock.
- Exporte formatos de compatibilidade apenas para consumidores a jusante concretos.
- 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.