uv: o gerenciador de pacotes e projetos Python mais rápido

Cansado de programar?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Projetos práticos

Projetos práticos voltados para o mercado de trabalho

Prática profissional

Formação moderna com foco na prática profissional

Resposta rápida

O uv é o gerenciador de pacotes e projetos Python da Astral, escrito em Rust. Com um só comando você cria o projeto (uv init), adiciona bibliotecas (uv add requests) e roda o código (uv run) sem ativar ambiente virtual. Ele troca pip, venv, pipx e pyenv por uma ferramenta muito mais rápida.

1
2
3
4
$ uv init meu-projeto   # cria pyproject.toml, .python-version e README.md
$ cd meu-projeto
$ uv add requests       # instala e registra no pyproject.toml e no uv.lock
$ uv run meu-projeto    # Hello from meu-projeto!

Resumo em 30 segundos:

  • uv add e uv remove mudam o pyproject.toml, o uv.lock e o .venv de uma vez.
  • uv run sincroniza o ambiente antes de executar: não precisa de source .venv/bin/activate.
  • uv.lock vai para o Git; .venv não. Quem clonar roda uv sync.
  • uv python install 3.12 instala o Python; uvx ruff roda uma ferramenta sem instalar.
  • Projetos antigos com requirements.txt funcionam com uv venv + uv pip install -r.

Salve salve Pythonista!

pip install demorando, requirements.txt desatualizado, “na minha máquina funciona” e três ferramentas só para ter um Python 3.12 com ambiente virtual: o uv resolve tudo isso numa ferramenta só, e rápida de verdade.

Aqui você vai ver como instalar, criar um projeto, adicionar dependências, entender o uv.lock, gerenciar versões do Python, usar o uvx e decidir, com uma tabela honesta, quando vale trocar o pip, o Poetry ou o Pipenv pelo uv.

Todos os comandos foram executados com uv 0.12.19 no Linux, e as saídas mostradas são as reais (só encurtamos caminhos de pasta e removemos linhas repetidas de build).

Então… Bora pro post! :rocket:

Vá Direto ao Assunto…

O que é o uv?

O que é o uv? O uv é um gerenciador de pacotes e de projetos Python, feito pela Astral em Rust e distribuído como um único executável. Ele cria projetos com pyproject.toml, resolve e trava dependências no uv.lock, cria e sincroniza o ambiente virtual .venv, instala versões do Python e roda ferramentas de linha de comando. A documentação oficial o descreve como uma ferramenta para substituir pip, pip-tools, pipx, poetry, pyenv, twine e virtualenv.

Antes do uv, um projeto Python “bem configurado” costumava envolver várias peças:

  • pyenv (ou o instalador do python.org) para ter a versão certa do Python;
  • venv ou virtualenv para isolar as bibliotecas do projeto (se ainda não conhece, veja nosso guia de ambientes virtuais com venv e virtualenv);
  • pip para instalar pacotes e um requirements.txt para registrá-los;
  • pip-tools, Poetry ou Pipenv para travar as versões exatas;
  • pipx para instalar ferramentas globais como Black ou Ruff.

O uv faz tudo isso sozinho, com um cache global que evita baixar o mesmo pacote duas vezes.

Quão mais rápido que o pip?

A Astral afirma que o uv é “10-100x mais rápido que o pip”. Em vez de só repetir a frase, medimos: um projeto novo com Python 3.12, instalando django, requests e pandas, com o cache de cada ferramenta já preenchido (duas rodadas, valores arredondados):

Ferramenta Versão Tempo
Pipenv 2026.8.0 cerca de 11,5 s
pip (em um venv) 25.0.1 cerca de 8,5 s
Poetry 2.5.1 cerca de 2,4 s
uv 0.12.19 cerca de 0,2 s

Com o cache vazio, o uv levou cerca de 0,7 s contra uns 8 s do pip sem cache. Os números mudam com a máquina e a rede, mas a ordem de grandeza se repete: no dia a dia você sente a diferença sempre que cria um ambiente, troca de branch ou roda o CI.

Como instalar o uv

O jeito recomendado é o instalador oficial, que não depende de ter Python instalado:

1
2
3
4
5
# Linux e macOS
$ curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Também dá para instalar por gerenciadores de pacotes: brew install uv (macOS), winget install --id=astral-sh.uv -e (Windows), pipx install uv ou pip install uv. Confira depois com:

1
$ uv --version
1
uv 0.12.19 (x86_64-unknown-linux-gnu)

Se instalou pelo instalador oficial, atualize com uv self update. Se instalou pelo pip, Homebrew ou outro gerenciador, atualize por ele. A lista completa está na página de instalação do uv.

Repare que o uv não precisa de um Python pré-instalado. Mesmo assim, se você quiser ter o Python no sistema para outras coisas, temos guias de como instalar o Python no Linux e no Windows.

Criando um projeto com uv init

O uv init cria a estrutura de um projeto novo:

1
2
$ uv init meu-projeto
$ cd meu-projeto
1
Initialized project `meu-projeto` at `/home/voce/meu-projeto`

Desde a versão 0.12, o padrão é um projeto de aplicação com layout src/:

1
2
3
4
5
6
7
8
9
meu-projeto/
├── .git/
├── .gitignore
├── .python-version
├── README.md
├── pyproject.toml
└── src/
    └── meu_projeto/
        └── __init__.py

O coração do projeto é o pyproject.toml, no formato padrão do Python (tabela [project], da PEP 621):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[project]
name = "meu-projeto"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
    { name = "Seu Nome", email = "[email protected]" }
]
requires-python = ">=3.14"
dependencies = []

[project.scripts]
meu-projeto = "meu_projeto:main"

[build-system]
requires = ["uv_build>=0.12.19,<0.13.0"]
build-backend = "uv_build"

O que cada arquivo faz:

  • pyproject.toml: nome, versão, dependências e a versão mínima do Python (requires-python). Os autores vêm do seu git config.
  • .python-version: a versão do Python que o uv usa para criar o ambiente. Ele grava a versão que encontrou na máquina (aqui, 3.14). Para escolher outra, use uv init meu-projeto --python 3.12.
  • [project.scripts]: cria o comando meu-projeto, que chama a função main() de src/meu_projeto/__init__.py. A pasta meu_projeto é um pacote Python; se tiver dúvida sobre o papel do __init__.py, veja para que serve o __init__.py.
  • .gitignore: já ignora .venv, __pycache__/ e dist/.

Rode o projeto:

1
$ uv run meu-projeto
1
2
3
4
Using CPython 3.14.3
Creating virtual environment at: .venv
Installed 1 package in 2ms
Hello from meu-projeto!

Na primeira execução o uv criou o .venv e o uv.lock sozinho, sem python -m venv nem ativação.

Quero só um main.py

Para scripts, estudos ou projetos que nunca vão virar pacote, use --no-package. Esse era o padrão antes da versão 0.12:

1
$ uv init estudos --no-package
1
2
3
4
5
estudos/
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

Aqui você roda com uv run main.py. Existem ainda --lib (biblioteca para publicar no PyPI) e --bare (só o pyproject.toml).

Adicionando dependências com uv add

Para instalar uma biblioteca, use uv add em vez de pip install:

1
$ uv add requests
1
2
3
4
5
6
7
8
Resolved 6 packages in 3ms
Installed 6 packages in 2ms
 + certifi==2026.7.22
 + charset-normalizer==3.5.1
 + idna==3.20
 ~ meu-projeto==0.1.0 (from file:///home/voce/meu-projeto)
 + requests==2.34.2
 + urllib3==2.8.0

Um comando fez três coisas: instalou no .venv, registrou "requests>=2.34.2" em dependencies no pyproject.toml e travou as versões exatas de tudo (inclusive certifi, idna e as outras dependências indiretas) no uv.lock.

Outras formas comuns:

1
2
3
4
$ uv add 'rich>=14,<16'      # com restrição de versão
$ uv add --dev pytest        # só para desenvolvimento
$ uv add -r requirements.txt # importa um requirements.txt existente
$ uv remove rich             # remove do pyproject, do lock e do .venv

O --dev coloca o pacote num grupo separado, que não faz parte das dependências de quem usa o seu código:

1
2
3
4
5
6
7
8
dependencies = [
    "requests>=2.34.2",
]

[dependency-groups]
dev = [
    "pytest>=9.1.1",
]

Para ver a árvore de dependências, use uv tree:

1
2
3
4
5
6
7
8
9
10
11
meu-projeto v0.1.0
├── requests v2.34.2
│   ├── certifi v2026.7.22
│   ├── charset-normalizer v3.5.1
│   ├── idna v3.20
│   └── urllib3 v2.8.0
└── pytest v9.1.1 (group: dev)
    ├── iniconfig v2.3.0
    ├── packaging v26.3
    ├── pluggy v1.6.0
    └── pygments v2.21.0

Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine as PyDicas e receba 30 dias do melhor conteúdo Python na sua Caixa de Entrada: direto e sem enrolação!

Rodando código com uv run

O uv run executa qualquer comando dentro do ambiente do projeto. Vamos usar o requests em src/meu_projeto/__init__.py:

1
2
3
4
5
6
7
8
import sys

import requests


def main() -> None:
    print(f"Python {sys.version_info.major}.{sys.version_info.minor}")
    print(f"requests {requests.__version__}")
1
$ uv run meu-projeto
1
2
Python 3.14
requests 2.34.2

Antes de executar, o uv run confere se o uv.lock bate com o pyproject.toml e se o .venv bate com o uv.lock, e corrige o que estiver faltando. Por isso você não precisa lembrar de “rodar o install” depois de um git pull.

Funciona com qualquer comando, não só com scripts:

1
2
3
$ uv run pytest -q
$ uv run python -c "import requests; print(requests.__version__)"
$ uv run --with rich python -c "import rich; print('rich ok')"
1
2
3
4
.                                                                        [100%]
1 passed in 0.01s
2.34.2
rich ok

O --with adiciona um pacote só naquela execução, sem mexer no pyproject.toml: bom para testar uma biblioteca antes de decidir adotá-la.

Se preferir o jeito tradicional, o .venv é um ambiente virtual comum: source .venv/bin/activate no Linux e macOS, .venv\Scripts\activate no Windows, e depois python, pytest etc. funcionam direto.

O uv.lock e o uv sync: ambiente reproduzível

O uv.lock é o “retrato” exato do ambiente: versão, origem e hash de cada pacote, para todas as plataformas (Linux, macOS e Windows) ao mesmo tempo. É um arquivo TOML legível, mas não deve ser editado à mão. A documentação é clara: ele deve ir para o controle de versão.

Quando alguém clona o repositório, basta um comando para ter o mesmo ambiente:

1
2
3
$ git clone https://github.com/voce/meu-projeto.git
$ cd meu-projeto
$ uv sync
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Using CPython 3.14.3
Creating virtual environment at: .venv
Resolved 12 packages in 1ms
Installed 11 packages in 9ms
 + certifi==2026.7.22
 + charset-normalizer==3.5.1
 + idna==3.20
 + iniconfig==2.3.0
 + meu-projeto==0.1.0 (from file:///home/voce/meu-projeto)
 + packaging==26.3
 + pluggy==1.6.0
 + pygments==2.21.0
 + pytest==9.1.1
 + requests==2.34.2
 + urllib3==2.8.0

Os comandos do dia a dia com o lockfile:

Comando O que faz
uv lock Atualiza o uv.lock a partir do pyproject.toml (sem instalar)
uv sync Deixa o .venv idêntico ao uv.lock (remove o que sobrar)
uv sync --no-dev Igual, mas sem o grupo dev (bom para produção)
uv sync --locked Falha se o uv.lock estiver desatualizado (use no CI)
uv lock --check Só verifica se o lockfile está em dia
uv lock --upgrade-package requests Atualiza um pacote para a versão mais nova permitida
uv lock --upgrade Atualiza todos os pacotes
uv export --format requirements.txt Gera um requirements.txt a partir do lock

Um detalhe importante: o uv não atualiza versões sozinho. Enquanto a versão travada no uv.lock satisfizer o pyproject.toml, ela fica. Atualizar é sempre uma decisão sua, com uv lock --upgrade-package.

O uv export é útil quando a plataforma de deploy só entende requirements.txt. Em projetos empacotados (o padrão do uv init), a primeira linha do arquivo gerado é -e .; use --no-emit-project para tirá-la.

Gerenciando versões do Python com uv python

O uv também substitui o pyenv. Para instalar versões do Python:

1
$ uv python install 3.13
1
2
3
4
Downloading cpython-3.13.15-linux-x86_64-gnu (download) (33.4MiB)
 Downloaded cpython-3.13.15-linux-x86_64-gnu (download)
Installed Python 3.13.15 in 1.21s
 + cpython-3.13.15-linux-x86_64-gnu (python3.13)

Outros comandos úteis:

1
2
3
$ uv python install 3.12 3.13   # várias versões de uma vez
$ uv python list                # instaladas e disponíveis para download
$ uv python pin 3.13            # grava 3.13 no .python-version do projeto

Três coisas que vale saber:

  1. Download automático. Se o .python-version pedir uma versão que você não tem, o uv baixa na hora ao rodar uv run, uv sync ou uv venv --python 3.12. Muitas vezes você nem precisa do uv python install.
  2. Ele usa o Python do sistema também. Se você já tem um Python instalado, o uv encontra sozinho, sem configuração.
  3. O pin respeita o requires-python. Num projeto com requires-python = ">=3.14", uv python pin 3.12 falha (veja em Erros comuns).

As versões vêm do projeto python-build-standalone, mantido pela Astral. Por padrão o uv só cria executáveis com versão no nome (python3.12), para não brigar com o python do sistema. Detalhes no guia de instalação do Python com uv.

uv venv e uv pip: o modo compatível com pip

Nem todo projeto vai migrar para pyproject.toml amanhã. Para projetos com requirements.txt, o uv tem uma interface que imita o pip e o venv, só que mais rápida:

1
2
3
$ uv venv --python 3.12
$ source .venv/bin/activate
$ uv pip install -r requirements.txt
1
2
3
4
5
6
7
8
9
10
Using CPython 3.12.13
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
Resolved 5 packages in 2ms
Installed 5 packages in 3ms
 + certifi==2026.7.22
 + charset-normalizer==3.5.1
 + idna==3.20
 + requests==2.34.2
 + urllib3==2.8.0

Os equivalentes diretos:

pip / venv uv
python -m venv .venv uv venv
pip install requests uv pip install requests
pip install -r requirements.txt uv pip install -r requirements.txt
pip freeze > requirements.txt uv pip freeze > requirements.txt
pip list uv pip list
pip-compile requirements.in uv pip compile requirements.in
pip-sync requirements.txt uv pip sync requirements.txt

Duas diferenças em relação ao pip que pegam muita gente (as duas estão em Erros comuns):

  • O uv pip exige um ambiente virtual. Ele procura o ambiente ativado (VIRTUAL_ENV) ou uma pasta .venv na pasta atual ou acima dela. Para instalar no Python do sistema, só com --system, e a documentação recomenda isso apenas em CI e containers.
  • O ambiente criado por uv venv não tem o pip dentro. Se alguma ferramenta precisar dele, crie com uv venv --seed.

Use esse modo como ponte para acelerar projetos antigos. Para projetos novos, prefira uv init + uv add.

uv tool e uvx: ferramentas de linha de comando

Ferramentas como Ruff, Black, HTTPie ou o django-admin de um projeto novo não deveriam ser instaladas no Python global. O uvx (atalho de uv tool run) roda a ferramenta num ambiente temporário e isolado:

1
$ uvx ruff --version
1
2
Installed 1 package in 2ms
ruff 0.16.9

Variações úteis, da documentação de ferramentas do uv:

1
2
3
4
$ uvx ruff check .                  # checa o código da pasta atual
$ uvx ruff@latest check .           # força a versão mais nova
$ uvx [email protected] check .            # versão específica
$ uvx --from httpie http --version  # pacote com nome diferente do comando

Se você usa a ferramenta todo dia, instale de vez (o substituto do pipx):

1
2
3
4
$ uv tool install ruff
$ uv tool list
$ uv tool upgrade ruff     # ou: uv tool upgrade --all
$ uv tool uninstall ruff
1
2
3
4
5
6
7
8
Resolved 1 package in 3ms
Installed 1 package in 2ms
 + ruff==0.16.9
Installed 1 executable: ruff
ruff v0.16.9
- ruff
Nothing to upgrade
Uninstalled 1 executable: ruff

Se o terminal disser que o comando não foi encontrado, rode uv tool update-shell para colocar a pasta de ferramentas no PATH.

uv run ou uvx? Use uv run pytest (e não uvx pytest) quando a ferramenta precisa importar o seu projeto e as dependências dele, como pytest e mypy. Use uvx para ferramentas que só leem arquivos, como formatadores e linters.

Scripts com dependências embutidas

Para aquele script solto que usa uma biblioteca externa, o uv grava as dependências dentro do próprio arquivo, no formato padrão de metadados de script (PEP 723). Considere o tabela.py:

1
2
3
4
5
6
7
8
9
10
from rich.console import Console
from rich.table import Table

tabela = Table(title="Linguagens")
tabela.add_column("Nome")
tabela.add_column("Ano")
tabela.add_row("Python", "1991")
tabela.add_row("Rust", "2015")

Console().print(tabela)
1
2
$ uv add --script tabela.py rich
$ uv run tabela.py

O uv add --script colocou este bloco no topo do arquivo:

1
2
3
4
5
6
# /// script
# requires-python = ">=3.14"
# dependencies = [
#     "rich>=15.0.0",
# ]
# ///

E o uv run criou um ambiente isolado, instalou o rich e executou:

1
2
3
4
5
6
7
8
Installed 4 packages in 9ms
   Linguagens
┏━━━━━━━━┳━━━━━━┓
┃ Nome   ┃ Ano  ┃
┡━━━━━━━━╇━━━━━━┩
│ Python │ 1991 │
│ Rust   │ 2015 │
└────────┴──────┘

Você pode mandar esse único arquivo para um colega: com o uv instalado, uv run tabela.py funciona sem pip install nenhum.

Gerenciar dependências com uv é só o começo: montar o projeto Django em si, do model às APIs REST, é o que você pratica na Jornada Python:

Django com uv

O uv combina muito bem com o fluxo do nosso post seu primeiro projeto Django em 15 minutos. Os passos de “criar venv, ativar e instalar o Django” viram estes:

1
2
3
4
5
6
$ uv init meu-site --no-package
$ cd meu-site
$ rm main.py
$ uv add django
$ uv run django-admin startproject config .
$ uv run python manage.py runserver

Conferimos com uv run python manage.py check (saída System check identified no issues (0 silenced).) e o Django instalado foi o 6.1.1. Daqui em diante, qualquer comando do manage.py é só prefixar com uv run.

pip + venv vs Poetry vs Pipenv vs uv: qual usar?

Todas as quatro isolam dependências; a diferença está no que cada uma resolve sozinha. Resumo honesto, com as versões de setembro de 2026 (pip 25+, Poetry 2.5, Pipenv 2026.8, uv 0.12):

Critério pip + venv Poetry Pipenv uv
Já vem com o Python Sim Não Não Não
Arquivo de dependências requirements.txt pyproject.toml Pipfile pyproject.toml
Lockfile com versões exatas Não nativo (use pip-tools) poetry.lock Pipfile.lock uv.lock (multiplataforma)
Instala versões do Python Não Experimental (poetry python install) Via pyenv ou asdf Sim, uv python install
Roda ferramentas isoladas (tipo pipx) Não Não Não Sim, uvx
Velocidade no nosso teste cerca de 8,5 s cerca de 2,4 s cerca de 11,5 s cerca de 0,2 s
Publicar no PyPI Com build e twine poetry publish Não é o foco uv build e uv publish
Maturidade Padrão há mais de 15 anos Maduro, muitos plugins Maduro, menos adotado em projetos novos Mais novo, ainda na série 0.x
Melhor para Aula, script rápido, máquina sem internet para instalar nada Projetos que já usam Poetry Projetos que já usam Pipenv Projetos novos e CI

Quando não trocar agora:

  • Seu projeto usa Poetry ou Pipenv e está tudo bem. Migrar custa tempo e não traz recurso novo obrigatório (o guia do Poetry cobre o fluxo no 2.x). Troque quando o tempo de instalação ou a falta de gestão de Python começarem a incomodar.
  • Você está aprendendo o básico. Entender python -m venv e pip install continua valendo, porque é o que aparece em tutoriais, provas e servidores antigos. O uv fica muito mais claro depois disso.
  • Ambientes onde você não pode instalar binários. O pip vem junto com o Python; o uv é um executável a mais.

Para projetos novos, o uv é a escolha mais simples hoje, e usa o padrão [project] do Python em vez de um formato próprio.

Migrando para o uv

  • De requirements.txt: na pasta do projeto, uv init --no-package e depois uv add -r requirements.txt.
  • De Poetry ou Pipenv: a ferramenta comunitária migrate-to-uv (não é da Astral) converte o pyproject.toml do Poetry ou o Pipfile e gera o uv.lock aproveitando as versões do lockfile antigo. Testamos com uvx migrate-to-uv num projeto Poetry e ele reescreveu as dependências no formato [project] e a dependência de dev no [dependency-groups]. Revise o resultado antes de commitar.

Erros comuns

Estes são os erros que mais aparecem para quem começa com o uv, com a mensagem real que ele mostra.

Rodar uv add fora de um projeto

1
2
$ cd ~/Downloads
$ uv add requests
1
error: No `pyproject.toml` found in current directory or any parent directory

Correção: uv add precisa de um projeto. Entre na pasta do projeto ou crie um com uv init. Se você só quer instalar num ambiente avulso, use uv venv e uv pip install.

uv pip install sem ambiente virtual

1
$ uv pip install requests
1
error: No virtual environment found; run `uv venv` to create an environment, or pass `--system` to install into a non-virtual environment

Correção: diferente do pip, o uv não instala no Python do sistema por padrão. Rode uv venv antes (ou use uv init + uv add).

ModuleNotFoundError ao rodar com python em vez de uv run

Você fez uv add rich, criou um relatorio.py com from rich import print e rodou com o Python do sistema:

1
$ python3 relatorio.py
1
2
3
4
Traceback (most recent call last):
  File "/home/voce/meu-projeto/relatorio.py", line 1, in <module>
    from rich import print
ModuleNotFoundError: No module named 'rich'

Correção: o rich está no .venv do projeto, não no Python global. Rode uv run relatorio.py, ou ative o ambiente com source .venv/bin/activate antes de usar python.

Chamar o pip dentro de um ambiente criado com uv venv

1
2
$ uv venv
$ .venv/bin/python -m pip install requests
1
/home/voce/legado/.venv/bin/python: No module named pip

Correção: o uv venv não instala o pip no ambiente. Use uv pip install requests, ou crie o ambiente com uv venv --seed se alguma ferramenta exigir o pip.

uv sync --locked com lockfile desatualizado (comum no CI)

Alguém editou o pyproject.toml à mão, adicionou uma dependência e esqueceu de atualizar o lock:

1
$ uv sync --locked
1
2
3
error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided.

hint: To update the lockfile, run `uv lock`.

Correção: rode uv lock localmente e commite o uv.lock novo. Prefira uv add e uv remove, que atualizam os dois arquivos juntos.

Fixar um Python menor que o requires-python

1
$ uv python pin 3.12
1
error: The requested Python version `3.12` is incompatible with the project `requires-python` value of `>=3.14`.

Correção: o projeto foi criado dizendo que exige Python 3.14 ou maior. Se ele precisa rodar na 3.12, ajuste antes o requires-python no pyproject.toml para ">=3.12" e só então rode o pin. Para evitar isso, crie o projeto já com uv init --python 3.12.

Exercícios resolvidos

Tente responder antes de abrir a solução. Todos os comandos foram executados com o uv 0.12.19. Quer mais prática de Python em si? Veja nossa lista de exercícios de Python resolvidos.

Exercício 1. Crie um projeto chamado calculadora que use o Python 3.12 e tenha a biblioteca requests como dependência. Quais valores ficam no .python-version e no requires-python?

Ver solução
1
2
3
4
5
$ uv init calculadora --python 3.12
$ cd calculadora
$ uv add requests
$ cat .python-version
$ grep requires-python pyproject.toml

Saída:

1
2
3.12
requires-python = ">=3.12"

O --python define tanto a versão fixada no .python-version quanto o mínimo em requires-python. Se a 3.12 não existir na máquina, o uv baixa.

Exercício 2. No projeto do exercício anterior, adicione o pytest apenas como dependência de desenvolvimento e rode os testes da pasta tests/.

Ver solução
1
2
$ uv add --dev pytest
$ uv run pytest -q

Saída (com um teste test_soma na pasta tests/):

1
2
.                                                                        [100%]
1 passed in 0.01s

O pytest vai para [dependency-groups] com o nome dev, fora de dependencies. O uv run pytest usa o pytest do .venv do projeto, que enxerga o seu código.

Exercício 3. Um colega clonou o repositório do seu projeto uv. Qual comando ele deve rodar para ter exatamente as mesmas versões que você? E se ele quiser só as dependências de produção?

Ver solução
1
2
$ uv sync            # tudo, inclusive o grupo dev
$ uv sync --no-dev   # só dependências de produção

O uv sync cria o .venv (e baixa o Python do .python-version, se preciso) e instala as versões exatas do uv.lock. Com --no-dev, os pacotes do grupo dev ficam de fora; se já estavam instalados, são removidos.

Exercício 4. Você tem um projeto antigo só com este requirements.txt. Converta-o num projeto uv sem digitar os pacotes de novo.

1
2
requests==2.34.2
rich>=14
Ver solução
1
2
3
$ uv init --no-package --python 3.12
$ uv add -r requirements.txt
$ grep -A3 "^dependencies" pyproject.toml

Saída:

1
2
3
4
dependencies = [
    "requests==2.34.2",
    "rich>=14",
]

O uv add -r lê o arquivo e copia as restrições como estão para o pyproject.toml, gerando o uv.lock na sequência. Depois disso, o requirements.txt pode ser apagado (ou gerado de novo com uv export).

Exercício 5. Você quer checar o estilo do código com o Ruff numa pasta qualquer, sem instalar nada no projeto nem no Python global. Qual comando usar? E se passar a usar o Ruff todo dia?

Ver solução
1
2
$ uvx ruff check .       # uso avulso, ambiente temporário
$ uv tool install ruff   # uso diário, comando ruff fica no PATH

O uvx é o atalho de uv tool run: baixa o Ruff para o cache e executa isolado. O uv tool install faz o papel do pipx install.

Exercício 6. Você tem um script tabela.py que usa a biblioteca rich e quer mandá-lo para um colega que também tem o uv, sem criar projeto nem requirements.txt. Como fazer?

Ver solução
1
2
$ uv add --script tabela.py rich
$ uv run tabela.py

O primeiro comando escreve um bloco # /// script com dependencies = ["rich>=15.0.0"] no topo do arquivo (formato da PEP 723). O colega só precisa rodar uv run tabela.py: o uv cria um ambiente temporário, instala o rich e executa.

Exercício 7 (questão de prova). Num projeto gerenciado com o uv, quais arquivos devem ser enviados para o repositório Git para que outra pessoa reproduza o ambiente com uv sync?

a) Apenas a pasta .venv
b) pyproject.toml, uv.lock e .python-version
c) Apenas o requirements.txt gerado com uv pip freeze
d) pyproject.toml e a pasta .venv

Ver solução

Resposta: b. O pyproject.toml declara as dependências, o uv.lock trava as versões exatas e o .python-version diz qual Python usar. A .venv nunca vai para o Git: ela é específica da máquina, pesada e recriada em segundos pelo uv sync (o uv init já a coloca no .gitignore). O requirements.txt não é lido pelo uv sync.

Exercício 8 (questão de prova). No pipeline de CI, você quer instalar exatamente as versões do uv.lock e fazer o build falhar se alguém esqueceu de atualizar o lockfile depois de mudar o pyproject.toml. Qual comando usar?

a) uv add --dev
b) uv lock --upgrade
c) uv sync --locked
d) uv pip install -r pyproject.toml

Ver solução
1
2
3
4
$ uv sync --locked
error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided.

hint: To update the lockfile, run `uv lock`.

Resposta: c. Com --locked, o uv sync se recusa a atualizar o lockfile e termina com erro (código de saída 1) quando ele não bate com o pyproject.toml. A alternativa b faria o contrário: atualizaria todas as versões. A a adiciona pacotes e a d não é o fluxo de projeto do uv.

Quer usar isso em projetos de verdade, do básico ao Django? Conheça o nosso curso de Python completo.

Conclusão

O uv junta numa ferramenta rápida o que antes pedia pyenv, venv, pip, pip-tools e pipx. Para guardar:

  • Projeto novo: uv init, uv add, uv run.
  • Clonou um projeto: uv sync. No CI: uv sync --locked.
  • Projeto antigo com requirements.txt: uv venv + uv pip install -r, ou migre com uv add -r.
  • Ferramentas: uvx para uso avulso, uv tool install para o dia a dia.

A referência completa está na documentação oficial do uv, com guias de projetos e de lock e sync.

Nos vemos no próximo post!

Perguntas frequentes

O que é o uv no Python?

O uv é um gerenciador de pacotes e de projetos Python criado pela Astral (a mesma empresa do Ruff) e escrito em Rust. Um único executável cria o projeto (uv init), adiciona dependências (uv add), gera o lockfile uv.lock, cria o ambiente virtual .venv, instala versões do Python (uv python install) e roda ferramentas de linha de comando (uvx). Ele substitui pip, pip-tools, pipx, virtualenv, pyenv e boa parte do Poetry.

O uv substitui o pip?

Na prática, sim. O uv tem um modo compatível com o pip, o uv pip install, uv pip freeze e uv pip sync, que aceita o mesmo requirements.txt e costuma ser muitas vezes mais rápido. A diferença é que o uv exige um ambiente virtual por padrão e o ambiente criado por uv venv não vem com o pip dentro. O pip continua funcionando normalmente, e você pode misturar os dois em projetos antigos.

Qual a diferença entre uv e Poetry?

Os dois gerenciam dependências com pyproject.toml e lockfile. O uv é bem mais rápido, instala versões do Python sozinho, roda ferramentas com uvx e usa o padrão [project] do Python. O Poetry é mais antigo, tem um ecossistema de plugins maduro e fluxo consolidado de publicação no PyPI. Se o seu projeto já usa Poetry e funciona bem, não há urgência em trocar; para projetos novos, o uv é a escolha mais simples hoje.

Preciso ativar o ambiente virtual quando uso o uv?

Não. O comando uv run executa qualquer script ou ferramenta dentro do .venv do projeto sem ativação, e ainda confere se o uv.lock e o ambiente estão em dia antes de rodar. Se preferir o fluxo antigo, o .venv criado pelo uv é um ambiente virtual comum: ative com source .venv/bin/activate no Linux e macOS ou .venv\Scripts\activate no Windows.

Devo commitar o uv.lock no Git?

Sim. O uv.lock guarda as versões exatas de todas as dependências (inclusive as indiretas) e deve ir para o controle de versão junto com o pyproject.toml e o .python-version. Assim qualquer pessoa reproduz o mesmo ambiente com uv sync. Não edite o uv.lock à mão. Quem NÃO vai para o Git é a pasta .venv, que o uv init já coloca no .gitignore.

Qual a diferença entre uv run e uvx?

O uv run executa comandos dentro do ambiente do projeto atual, com as dependências do pyproject.toml (ex.: uv run pytest). O uvx, atalho de uv tool run, executa uma ferramenta num ambiente temporário e isolado, sem mexer no projeto (ex.: uvx ruff check .). Use uv run quando a ferramenta precisa enxergar o seu código instalado, como pytest e mypy; use uvx para ferramentas avulsas.

Como instalar uma versão específica do Python com o uv?

Use uv python install 3.12 (ou várias de uma vez, uv python install 3.12 3.13). Para fixar a versão do projeto, rode uv python pin 3.12, que grava o arquivo .python-version. Na maioria dos casos nem é preciso instalar antes: se o projeto pedir uma versão que não existe na máquina, o uv baixa automaticamente ao rodar uv run, uv sync ou uv venv --python 3.12.

Qual comando do uv instala exatamente as versões do uv.lock e falha se o lockfile estiver desatualizado?

É o uv sync --locked. O uv sync sozinho sincroniza o .venv com o lockfile e atualiza o uv.lock se o pyproject.toml mudou. Com --locked, em vez de atualizar, ele para com erro dizendo que o lockfile precisa ser atualizado. Por isso é o comando recomendado em pipelines de CI e em Dockerfiles.

Começe agora sua Jornada na Programação!

Não deixe para amanhã o sucesso que você pode começar a construir hoje!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.