[!NOTE] Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.

uv no macOS: Gestão de Versões, Projetos e Ferramentas Python

Mudei o meu fluxo de trabalho em Python para o uv, pois ele substituiu a necessidade de alternar entre ferramentas como pip, ambientes virtuais, pip-tools, pipx e gestores de projeto. Agora, um único executável cobre a maior parte dessas tarefas.

Os fluxos de trabalho continuam a ser diferentes. Um projeto, um script de metadata inline, uma ferramenta CLI pontual e uma CLI instalada possuem cada um o seu próprio ambiente e ciclo de vida. Este guia apresenta os comandos que utilizo e as fronteiras associadas a cada um deles.

Início rápido

# 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. Eu utilizo uv add, uv lock, uv sync, e uv run dentro de projetos; metadados PEP 723 para scripts autossuficientes; uvx para ferramentas únicas; e uv tool install para comandos que devem permanecer ativos PATH. Em CI, --locked verifica se a metadados do projeto estão em concordância com uv.lock; --frozen confia no bloqueio existente sem verificar a sua atualidade.

Instalar o uv com um único proprietário

O Homebrew é um caminho de instalação conveniente no macOS:

brew install uv
uv --version

Se o Homebrew tiver instalado o uv, o Homebrew deve atualizá-lo:

brew upgrade uv

uv self update É utilizado para o método de instalação autónoma dos UVs e fica desativado nas instalações via gestor de pacotes. Não permita que dois instaladores concorram pelo mesmo executável.

Comandos úteis de identidade:

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

As instalações geridas de Python, as ferramentas persistentes e as entradas de cache descartáveis possuem diretórios separados. O cache pode ser eliminado e recriado; ele não constitui uma fonte de verdade.

As quatro fronteiras do fluxo de trabalho UV

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

Um projeto UV normalmente possui três artefatos diferentes:

Entradas e estado derivado num projeto UV

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

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

Os atuais modelos de aplicação UV criam main.py, pyproject.toml, README.md, e .python-version. Por predefinição, eles não definem um sistema de compilação. Utilize uv init --lib para uma biblioteca empacotada com um src layout e compilação backend.

uv run verifica o projeto, atualiza o bloqueio quando necessário, sincroniza as dependências exigidas e executa o comando. A primeira operação no projeto cria .venv e uv.lock conforme necessário; uv init Em si, cria apenas os ficheiros do projeto.

Commit os inputs, não o ambiente

Cometer pyproject.toml, uv.lock, fonte, e um intencional .python-version. Ignorar .venv e os caches dos UVs.

O mecanismo de bloqueio regista uma resolução válida para os marcadores e plataformas suportados; no entanto, ele não torna as versões nativas idênticas em macOS, Linux, Intel e Apple Silicon. É necessário testar cada plataforma de implementação.

Bloqueio da frescura: --locked não é --frozen

Por predefinição, os comandos do projeto podem ser atualizados uv.lock quando as declarações são alteradas.

Utilize --locked para exigir que o bloqueio esteja atualizado com a metadados do projeto:

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

Se pyproject.toml e uv.lock Em discordância: esses comandos falham em vez de resolver um novo bloqueio. Geralmente, este deveria ser o gate útil do CI.

Utilize --frozen só quando se pretende intencionalmente que o UV utilize o bloqueio existente sem verificar se este é atual:

uv sync --frozen

Isso pode ser útil numa fase de compilação controlada em que o bloqueio já foi validado, mas não se trata de um detetor de bloqueios obsoletos. uv sync Por predefinição, é exato e remove pacotes desnecessários; uv run usa uma sincronização imprecisa por predefinição, a menos que --exact Foi solicitado.

Python Gerido: um pedido de versão, e não um binário universal

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

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

as compilações geridas de CPython da uv provêm do python-build-standalone project. O uv também consegue detetar interpretadores do sistema, do Homebrew, do pyenv, do Conda e de outras fontes.

.python-version É um pedido de versão detetado pelo uv e por outras ferramentas compatíveis. requires-python em pyproject.toml é o contrato de compatibilidade do projeto. Mantenham ambos intencionais:

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

Fixação 3.12 Não garante que a mesma versão do patch permaneça disponível para sempre, nem que o mesmo artefato funcione em todos os sistemas operativos. Solicite um patch específico apenas quando isso for realmente necessário, e configure o CI para selecionar e indicar explicitamente o interpretador a ser utilizado.

Utilize outro gestor em Python quando um projeto exigir uma configuração de distribuição ou de compilação que o uv não fornecer. O uv ainda pode utilizar esse interpretador através de --python ou descoberta normal.

Escolha entre uv run, uvx, e ferramentas instaladas

Escolher um ambiente de ferramentas para projeto, efémero ou persistente

Ferramentas acopladas ao projeto: uv run

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

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

Executar essa ferramenta uvx Isolá-lo-ia do projeto e poderá ocultar o pacote instalado ou os plugins de que ele necessita.

Ferramentas ad hoc: uvx

uvx é um alias para uv tool run. Ele cria um ambiente isolado armazenado no cache UV descartável:

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

Fixe a versão da ferramenta no CI ou na documentação. Uma primeira chamada sem especificação de versão seleciona uma versão atual, sendo que chamadas posteriores podem reutilizar o estado do cache.

Executáveis persistentes: uv tool install

Instale uma ferramenta quando scripts fora do seu controlo necessitarem da sua instrução de comando PATH, ou quando o manifesto da máquina o possui intencionalmente:

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

Ferramentas persistentes continuam a utilizar ambientes isolados. Não modifique esses ambientes manualmente com o pip.

Scripts: tornar um único ficheiro a unidade de lançamento

O PEP 723 define a metadados de script em linha. Um executor compatível consegue ler o bloco de comentários e criar um ambiente isolado.

Anatomia de um script PEP 723

# /// 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 metadados com o uv:

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

Texto simples python fetch.py Ignora os metadados do comentário. Por isso, o script depende de um executor compatível, embora a sintaxe em Python continue a ser válida.

Para um script que deve reproduzir uma resolução posteriormente, crie um bloqueio adjacente:

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

Isto escreve fetch.py.lock. Um exclude-newer O timestamp pode restringir as datas de distribuição dos candidatos, mas é menos eficaz do que uma resolução fixa exata e não garante que o artefato permaneça disponível.

Utilize um projeto quando vários ficheiros partilham dependências, o código puder ser importado como um pacote, os testes necessitarem do estado do projeto ou vários scripts tiverem de ser movidos em conjunto.

Ficheiros de requisitos: compatibilidade, não falhas

A requirements.txt Um ficheiro pode conter entradas não estruturadas, pinos exatos, hashes, restrições, índices, URLs ou um ambiente compilado. A sua reprodutibilidade depende de como foi criado e consumido; o nome do ficheiro, por si só, não revela qualquer informação.

Utilize a interface compatível com pip do uv sem necessidade de migração:

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

uv pip sync faz com que o ambiente corresponda ao ficheiro, enquanto uv pip install -r É aditivo.

Para uma aplicação própria, uma migração em fases 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 o caminho completo de teste e implementação antes de eliminar ficheiros antigos. Se um sistema a montante ainda esperar o formato pip, obtenha-o a partir do ficheiro uv lock validado:

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

Não efetuar manutenção uv.lock e uma exportação editada manualmente com duas resoluções concorrentes.

Cache, índices e limites da cadeia de abastecimento

O cache UV melhora as instalações repetidas, mas continua a ser descartável:

uv cache prune
uv cache clean

Preferir prune para a limpeza de rotina. clean Elimina todas as entradas de cache e obriga a realização de transferências e compilações posteriores.

Um ficheiro de bloqueio melhora a reprodutibilidade; no entanto, não torna as dependências confiáveis. Revise as fontes dos pacotes, a configuração do índice, as revisões do Git, os mecanismos de compilação, as licenças e as credenciais. Mantenha a configuração do índice autenticada fora dos ficheiros submetidos para armazenamento permanente, a menos que o repositório armazene apenas referências não secretas a um mecanismo de credenciais aprovado.

Para pacotes nativos, registe a arquitetura de implementação e a disponibilidade da versão de teste. Caso contrário, um resolvedor poderá recorrer a uma compilação local que necessita de compiladores e bibliotecas do sistema ausentes no ambiente CI ou em produção.

Uma lista de verificação operacional compacta

Para cada projeto:

  1. Defina requires-python e as dependências diretas em pyproject.toml2. Separe os recursos extras publicados dos grupos de dependências locais.
  2. Faça o commit. uv.lock; ignorar .venv E o estado do cache.
  3. Executar ferramentas acopladas ao projeto através do ambiente do projeto.
  4. Utilizar uv lock --check ou --locked em CI.
  5. Testar cada sistema operativo e arquitetura alvo representados pelo lock.
  6. Exportar formatos de compatibilidade apenas para os consumidores finais especificados.
  7. Rever a política de fontes e credenciais de forma independente da resolução.

O uv é especialmente útil quando essas fronteiras de propriedade permanecem visíveis. Um único binário consegue geri-las todas sem ser necessário transformá-las num único ambiente. Essa combinação — menos ferramentas, sem a pretensão de que todos os fluxos de trabalho sejam iguais — é precisamente o motivo pelo qual ainda o utilizo como a minha ferramenta padrão para projetos em Python no macOS.

Referências