Tradução automática
Este artigo foi traduzido automaticamente a partir da versão original em inglês.
uv no macOS: Gerir versões de Python, projetos e ferramentas
Arranque rápido
# Install uv
brew install uv
# For new projects (modern workflow)
uv init # create project structure
uv add pandas numpy # add dependencies
uv run train.py # run your script
# For existing projects (legacy workflow)
uv venv # create virtual environment
uv pip install -r requirements.txt # install dependencies
uv run train.py # run your script
# Run tools without installing them
uvx ruff check . # run linter
uvx black . # run formatter
# Run a single-file script with its own dependencies (no project needed)
uv run fetch.py # uv reads the inline deps and runs it
Porquê usar uv para Python no macOS?
Se já usa Python há algum tempo, provavelmente vai alternando entre pip, virtualenv, pip-tools, pyenv e poetry consoante o projeto. uv faz o que todos esses fazem, com um único binário.
Está escrito em Rust e, na minha máquina, instala pacotes cerca de 10–100x mais depressa do que a stack antiga. A maior vantagem para mim é que deixei de alternar entre ferramentas a meio de uma tarefa.
Substitui pip e pip-tools para gestão de pacotes, pyenv para instalar versões de Python, virtualenv/venv para ambientes, pipx para executar ferramentas, e poetry ou pdm para workflows de projeto.
Instalar uv
A forma mais simples de instalar uv no macOS é através do Homebrew:
brew install uv
uv deteta automaticamente a arquitetura do seu Mac (Apple Silicon ou Intel), por isso não é necessária configuração extra.
Para o manter atualizado:
brew upgrade uv
# OR
uv self update
Conceitos principais
uv cobre três casos de uso:
- Projetos — desenvolver uma aplicação ou biblioteca com dependências.
- Scripts — executar um script Python de ficheiro único com dependências inline.
- Ferramentas — executar utilitários de linha de comandos (como
ruffouhttpie) globalmente.
1. Gestão de projetos
Para projetos novos, uv usa o padrão pyproject.toml para configuração e um uv.lock multiplataforma para builds reprodutíveis.
Inicie um novo projeto:
uv init my-project
cd my-project
Isto cria um pyproject.toml, um .gitignore e um hello.py.
Adicione dependências:
# Runtime dependencies
uv add pandas requests
# Development dependencies
uv add pytest ruff --dev
Execute o seu código:
uv run hello.py
uv gere por si o ambiente virtual em .venv. Não precisa de o ativar manualmente.
2. Gerir versões de Python
uv instala e gere versões de Python por si, mantidas em ~/.cache/uv. Se tem usado pyenv para isto, pode deixar de o usar.
Instale uma versão específica:
uv python install 3.12
Fixe uma versão para o seu projeto:
uv python pin 3.11
Isto escreve um ficheiro .python-version. No próximo uv run, usa a versão fixada e descarrega-a se for necessário. A sua equipa e o CI acabam por usar a mesma versão de Python sem coordenação extra.
3. Executar ferramentas com uvx e uv tool install
uvx (um alias para uv tool run) executa ferramentas Python de linha de comandos sem as adicionar ao seu ambiente global nem às dependências do projeto.
# Run a linter
uvx ruff check .
# Run a formatter
uvx black .
# Start a temporary Jupyter server
uvx --from jupyterlab jupyter lab
Cada ferramenta corre no seu próprio ambiente temporário, por isso não há conflitos de versão com o que o seu projeto já tiver instalado.
Dois detalhes a que recorro constantemente:
- Fixar a versão inline com
@:uvx ruff@0.6.0 check ., ou forçar a mais recente comuvx ruff@latest. - O nome do comando não corresponde ao pacote? Use
--from. O pacotejupyterlabdisponibiliza o comandojupyter, por isso éuvx --from jupyterlab jupyter lab. O mesmo para--from httpie http. - Precisa de uma dependência extra para um plugin? Adicione-a com
--with:uvx --with mkdocs-material mkdocs serve.
Se usa uma ferramenta todos os dias, instale-a uma vez em vez de criar um ambiente novo sempre que a executa:
uv tool install ruff # now `ruff` is on your PATH
uv tool list # see what's installed
uv tool upgrade --all # update everything
uv tool uninstall ruff
A regra prática: uvx para execuções pontuais ou em CI, uv tool install para as ferramentas que usa diariamente.
Projetos legacy (requirements.txt)
requirements.txt teve um bom percurso. É uma lista plana de pacotes sem lockfile, sem separação entre dependências da aplicação e de desenvolvimento, e sem registo de porque é que algo foi fixado. Isso serve até ao dia em que tenta reproduzir uma build de há oito meses e descobre que "fixado" significava o que o PyPI tivesse resolvido nessa altura.
Se é responsável pelo projeto, migre-o. uv lê a sua lista existente diretamente para um pyproject.toml:
uv init --bare # minimal pyproject.toml, no scaffolding
uv add -r requirements.txt # import runtime dependencies
uv add --dev -r requirements-dev.txt # and dev ones, if you split them
Passa a ter um pyproject.toml e um verdadeiro uv.lock que fixa as versões resolvidas exatas. Confirme que tudo foi migrado com uv pip freeze, apague o antigo requirements.txt e siga em frente.
Mas talvez tenha usado o mesmo requirements.txt desde o Python 3.6 e não esteja interessado na minha opinião sobre isso. Justo. uv continua a funcionar como substituto direto de pip e venv, sem necessidade de migração:
# Create a virtual environment
uv venv
# Install dependencies
uv pip install -r requirements.txt
# Run it
uv run python app.py
Os mesmos comandos que já conhece, apenas mais rápidos. Nada no workflow antigo piora; a única diferença é que já não tem de o usar.
Scripts de ficheiro único com dependências inline
Esta foi a funcionalidade que mudou a forma como escrevo código descartável e de integração. Um script Python pode declarar as suas próprias dependências dentro do ficheiro, num bloco de comentários definido pela PEP 723. Sem pyproject.toml, sem requirements.txt, sem ambiente virtual para criar — uv run lê o bloco, cria um ambiente em cache e executa o ficheiro.
Vale a pena clarificar o que está realmente a fazer o trabalho aqui: isto não é uma funcionalidade da linguagem Python, nem uma invenção de uv. O bloco é apenas um comentário, por isso python fetch.py normal ignora-o e falha quando faltam os imports. A PEP 723 é um padrão partilhado, por isso qualquer runner compatível lê o mesmo bloco — pipx run, Hatch e PDM também suportam isto. uv é simplesmente a forma mais rápida de o usar, e é por isso que o resto desta secção usa uv run.
Aqui está tudo num único ficheiro, fetch.py:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "httpx",
# "rich",
# ]
# ///
import httpx
from rich import print
print(httpx.get("https://api.github.com/repos/astral-sh/uv").json())
Execute-o:
uv run fetch.py
Na primeira execução, resolve e instala httpx e rich num ambiente em cache; nas execuções seguintes reutiliza-o e arranca instantaneamente.
Não tem de escrever o bloco de metadados à mão. uv gera e edita-o por si:
# Create a new script with the block pre-filled
uv init --script fetch.py --python 3.12
# Add or remove dependencies
uv add --script fetch.py httpx rich
uv remove --script fetch.py rich
Para uma experiência rápida, pode até ignorar totalmente o bloco e passar as dependências na linha de comandos:
uv run --with httpx --with rich fetch.py
Porque isto é excelente para scripts de skill e automação
Uso isto muito para scripts pequenos que não justificam um projeto: uma correção pontual de dados, um helper de CI, um script de Claude Code skill, uma tarefa cron. O script é a unidade. Pode colocá-lo num gist, fazer commit para qualquer repositório ou passá-lo a um colega, e uv run é a única coisa de que ele precisa para o executar corretamente.
Torne-o executável diretamente com um shebang:
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["httpx"]
# ///
import httpx
...
chmod +x fetch.py
./fetch.py # uv handles the environment behind the scenes
O -S divide o shebang em argumentos separados para que env passe --script para uv.
Bloquear e fixar scripts
Para scripts que precisam de continuar a funcionar daqui a vários meses, tem duas opções.
Bloqueie a resolução exata ao lado do script:
uv lock --script fetch.py # writes fetch.py.lock
Ou fixe um ponto no tempo para que uv só considere pacotes lançados antes de uma determinada data — útil para reprodutibilidade sem lockfile:
# /// script
# dependencies = ["httpx"]
# [tool.uv]
# exclude-newer = "2025-04-17T00:00:00Z"
# ///
Dicas e truques que vale a pena conhecer
Mais algumas coisas que uso regularmente e que não são óbvias no arranque rápido.
Sincronizar a partir do lockfile em CI. uv sync instala exatamente o que está em uv.lock. Adicione --frozen para falhar explicitamente se o lockfile estiver desatualizado em vez de voltar a resolver silenciosamente — exatamente o que quer em builds de CI e Docker.
uv sync --frozen
Agrupe as dependências de desenvolvimento. Além de --dev, pode definir grupos de dependências com nome em pyproject.toml (docs, lint, test) e sincronizar apenas o que precisa:
uv add --group docs mkdocs-material
uv sync --only-group docs
Inspecione a árvore de dependências. uv tree mostra o que puxou o quê — e --outdated sinaliza upgrades:
uv tree
uv tree --outdated
Exporte para requirements.txt quando uma ferramenta a jusante ainda precisar desse formato:
uv export --format requirements-txt > requirements.txt
Execute um Python pontual com pacotes extra, sem projeto necessário:
uv run --with pandas --with matplotlib python
Gerir a cache quando o espaço em disco aperta ou uma build corre mal:
uv cache clean # wipe the whole cache
uv cache prune # remove only unused entries
Porque é rápido
Há três coisas que contam aqui. Está escrito em Rust, por isso não há overhead de arranque do Python em cada invocação. Faz cache global das wheels construídas — depois de numpy estar instalado num projeto, instalá-lo noutro é praticamente instantâneo (no macOS usa ligações copy-on-write). E descarrega e instala pacotes em paralelo em vez de um de cada vez.
Resumo
| Tarefa | Forma antiga | Forma com uv |
|---|---|---|
| Instalar Python | pyenv install 3.12 |
uv python install 3.12 |
| Novo projeto | mkdir proj && cd proj && python -m venv .venv |
uv init proj |
| Instalar pacote | pip install pandas && pip freeze > requirements.txt |
uv add pandas |
| Executar script | source .venv/bin/activate && python script.py |
uv run script.py |
| Script + deps | um projeto, ou um venv manual apenas para um ficheiro | bloco inline PEP 723 + uv run |
| Executar ferramenta uma vez | pipx run black |
uvx black |
| Instalar uma ferramenta | pipx install ruff |
uv tool install ruff |
| CI reprodutível | pip install -r requirements.txt |
uv sync --frozen |
Mudei o meu workflow de Python para uv pouco depois de ter saído e não voltei atrás. Se ainda está na stack antiga, experimente-o no próximo projeto — foi assim que o testei antes de migrar tudo.