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 addeuv removemudam opyproject.toml, ouv.locke o.venvde uma vez. -
uv runsincroniza o ambiente antes de executar: não precisa desource .venv/bin/activate. -
uv.lockvai para o Git;.venvnão. Quem clonar rodauv sync. -
uv python install 3.12instala o Python;uvx ruffroda uma ferramenta sem instalar. - Projetos antigos com
requirements.txtfuncionam comuv 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! ![]()
Vá Direto ao Assunto…
- O que é o uv?
- Como instalar o uv
- Criando um projeto com uv init
- Adicionando dependências com uv add
- Rodando código com uv run
- O uv.lock e o uv sync: ambiente reproduzível
- Gerenciando versões do Python com uv python
- uv venv e uv pip: o modo compatível com pip
- uv tool e uvx: ferramentas de linha de comando
- Scripts com dependências embutidas
- Django com uv
- pip + venv vs Poetry vs Pipenv vs uv: qual usar?
- Erros comuns
- Exercícios resolvidos
- Conclusão
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 nouv.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 substituirpip,pip-tools,pipx,poetry,pyenv,twineevirtualenv.
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.txtpara 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 seugit 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, useuv init meu-projeto --python 3.12. -
[project.scripts]: cria o comandomeu-projeto, que chama a funçãomain()desrc/meu_projeto/__init__.py. A pastameu_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__/edist/.
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? ![]()
Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?
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:
-
Download automático. Se o
.python-versionpedir uma versão que você não tem, o uv baixa na hora ao rodaruv run,uv syncouuv venv --python 3.12. Muitas vezes você nem precisa douv python install. - Ele usa o Python do sistema também. Se você já tem um Python instalado, o uv encontra sozinho, sem configuração.
-
O
pinrespeita orequires-python. Num projeto comrequires-python = ">=3.14",uv python pin 3.12falha (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 pipexige um ambiente virtual. Ele procura o ambiente ativado (VIRTUAL_ENV) ou uma pasta.venvna 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 venvnão tem o pip dentro. Se alguma ferramenta precisar dele, crie comuv 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 venvepip installcontinua 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-packagee depoisuv add -r requirements.txt. -
De Poetry ou Pipenv: a ferramenta comunitária migrate-to-uv (não é da Astral) converte o
pyproject.tomldo Poetry ou oPipfilee gera ouv.lockaproveitando as versões do lockfile antigo. Testamos comuvx migrate-to-uvnum 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 comuv add -r. - Ferramentas:
uvxpara uso avulso,uv tool installpara 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.
"Porque o Senhor dá a sabedoria, e da sua boca vem a inteligência e o entendimento" Pv 2:6