CLI com Python em 2026: argparse, Typer, Click e uv | Python Brasil
Aprenda a criar ferramentas de linha de comando com Python usando argparse, Typer, Click e uv. Guia prático com subcomandos, testes, CI e empacotamento.
Ferramentas de linha de comando continuam sendo um dos melhores projetos para aprender Python de forma profissional. Uma boa CLI automatiza tarefas repetitivas, organiza dados, chama APIs, roda checks de qualidade, processa arquivos e vira evidência concreta em entrevistas. Em 2026, o caminho mais forte não é apenas escrever um script que funciona: é entregar uma ferramenta instalável, testada, documentada e fácil de usar por outra pessoa.
Este guia atualiza a abordagem clássica de argparse e Click com o fluxo moderno de uv, Ruff, pytest e Typer. Se você está montando um portfólio Python ou procurando uma forma prática de demonstrar automação para vagas Python, uma CLI pequena e bem acabada pode valer mais do que um projeto web genérico sem uso real.
Quando Criar uma CLI com Python
CLIs são ideais quando a tarefa precisa ser repetida, versionada ou integrada a outros comandos. Alguns exemplos bons para portfólio:
- Organizar notas fiscais, CSVs ou planilhas em uma pasta.
- Consultar uma API pública e salvar o resultado em JSON ou SQLite.
- Validar arquivos antes de um deploy.
- Gerar relatórios locais para times de dados, QA ou RevOps.
- Automatizar rotinas de scraping, conversão de documentos ou limpeza de dados.
Python é uma escolha natural porque combina biblioteca padrão rica, ecossistema de pacotes, boa legibilidade e integração simples com sistemas operacionais. Para comparar com outras linguagens, Go costuma brilhar em binários únicos e CLIs de infraestrutura; Rust se destaca quando performance e distribuição leve são prioridades. Ainda assim, Python vence quando a ferramenta precisa conversar rapidamente com APIs, dados, notebooks, automações e bibliotecas de negócio.
Escolha Rápida: argparse, Typer ou Click
| Cenário | Melhor escolha | Por quê |
|---|---|---|
| Script simples, sem dependências | argparse | Já vem com Python e resolve comandos básicos. |
| CLI moderna para projeto novo | Typer | Usa type hints, gera ajuda automaticamente e é confortável para FastAPI/Pydantic users. |
| Projeto já baseado em Click | Click | Maduro, estável e muito usado em ferramentas existentes. |
| CLI para empacotar e instalar | Typer ou Click | Melhor ergonomia para subcomandos, testes e mensagens. |
Se você está começando, aprenda argparse para entender a base. Para um projeto que vai para GitHub, README e currículo, Typer costuma ser o ponto ideal em 2026.
Começando com argparse
O argparse já vem incluso no Python. Ele é perfeito para scripts pequenos, automações internas e comandos com poucas opções:
#!/usr/bin/env python3
"""Organizador simples de arquivos por extensão."""
import argparse
from pathlib import Path
def organizar(pasta: Path, aplicar: bool) -> None:
for arquivo in pasta.iterdir():
if not arquivo.is_file():
continue
extensao = arquivo.suffix.removeprefix(".") or "sem-extensao"
destino = pasta / extensao / arquivo.name
print(f"{arquivo.name} -> {destino.relative_to(pasta)}")
if aplicar:
destino.parent.mkdir(exist_ok=True)
arquivo.rename(destino)
def main() -> None:
parser = argparse.ArgumentParser(
description="Organiza arquivos de uma pasta por extensão."
)
parser.add_argument("pasta", type=Path, help="Pasta que será organizada")
parser.add_argument(
"--aplicar",
action="store_true",
help="Move os arquivos de verdade; sem isso, apenas simula",
)
args = parser.parse_args()
organizar(args.pasta, args.aplicar)
if __name__ == "__main__":
main()
Uso:
python organiza.py ~/Downloads
python organiza.py ~/Downloads --aplicar
O detalhe importante é o modo seguro por padrão. O comando primeiro mostra o que faria e só move arquivos quando --aplicar é usado. Essa decisão melhora a confiança do usuário e evita acidentes.
CLI Moderna com Typer
Typer usa type hints para gerar validação, ajuda e conversão de argumentos. Instale com uv:
uv add typer
Exemplo de uma CLI de tarefas com subcomandos:
from __future__ import annotations
import json
from pathlib import Path
import typer
app = typer.Typer(help="Gerenciador de tarefas pelo terminal.")
ARQUIVO = Path.home() / ".tarefas-python.json"
def carregar_tarefas() -> list[dict]:
if not ARQUIVO.exists():
return []
return json.loads(ARQUIVO.read_text(encoding="utf-8"))
def salvar_tarefas(tarefas: list[dict]) -> None:
ARQUIVO.write_text(
json.dumps(tarefas, indent=2, ensure_ascii=False),
encoding="utf-8",
)
@app.command()
def adicionar(titulo: str, prioridade: str = "média") -> None:
"""Adiciona uma nova tarefa."""
tarefas = carregar_tarefas()
tarefa = {
"id": len(tarefas) + 1,
"titulo": titulo,
"prioridade": prioridade,
"concluida": False,
}
tarefas.append(tarefa)
salvar_tarefas(tarefas)
typer.secho(f"Tarefa #{tarefa['id']} criada.", fg=typer.colors.GREEN)
@app.command()
def listar(todas: bool = False) -> None:
"""Lista tarefas pendentes ou todas as tarefas."""
tarefas = carregar_tarefas()
for tarefa in tarefas:
if tarefa["concluida"] and not todas:
continue
status = "ok" if tarefa["concluida"] else "pendente"
typer.echo(f"[{tarefa['id']}] {tarefa['titulo']} - {status}")
if __name__ == "__main__":
app()
Rode localmente:
uv run python tarefas.py adicionar "Revisar currículo Python" --prioridade alta
uv run python tarefas.py listar
Typer fica especialmente bom quando você já usa type hints, Pydantic ou FastAPI, porque o estilo mental é parecido: tipos claros, validação explícita e documentação gerada a partir da assinatura das funções.
Quando Click Ainda Faz Sentido
Click continua excelente e aparece em ferramentas importantes do ecossistema Python. Ele usa decoradores, oferece grupos de comandos, opções coloridas, prompts e testes com CliRunner:
import click
@click.group()
@click.version_option(version="1.0.0")
def cli():
"""Ferramenta de produtividade para projetos Python."""
@cli.command()
@click.argument("nome")
@click.option("--privado/--publico", default=True, help="Tipo do projeto")
def criar(nome: str, privado: bool) -> None:
modo = "privado" if privado else "público"
click.echo(click.style(f"Criando {nome} como projeto {modo}.", fg="green"))
Se você está mantendo uma CLI existente em Click, não precisa migrar só por moda. Atualize documentação, testes, empacotamento e fluxo de instalação antes de trocar biblioteca.
Empacotando com pyproject.toml
Para transformar a ferramenta em comando instalável, configure pyproject.toml:
[project]
name = "tarefas-python"
version = "0.1.0"
description = "CLI de tarefas para demonstrar automação com Python"
requires-python = ">=3.11"
dependencies = ["typer>=0.12"]
[project.scripts]
tarefas = "tarefas:app"
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.pytest.ini_options]
testpaths = ["tests"]
Durante o desenvolvimento:
uv sync
uv run tarefas --help
uv run ruff check .
uv run pytest
Para instalar como ferramenta local, prefira uv tool install . ou pipx install .. Assim o comando fica disponível no terminal sem poluir o ambiente global do Python.
Testando uma CLI
Teste de CLI precisa cobrir comportamento visível: argumentos, saída, arquivos criados e códigos de erro. Com Typer:
from typer.testing import CliRunner
from tarefas import app
runner = CliRunner()
def test_help_mostra_comandos():
resultado = runner.invoke(app, ["--help"])
assert resultado.exit_code == 0
assert "adicionar" in resultado.stdout
def test_adicionar_tarefa():
resultado = runner.invoke(app, ["adicionar", "Estudar pytest"])
assert resultado.exit_code == 0
assert "criada" in resultado.stdout
Para um projeto de portfólio, combine esses testes com pytest, Ruff e uma action de CI. Uma configuração mínima de GitHub Actions pode rodar uv sync, uv run ruff check . e uv run pytest a cada push.
Boas Práticas para CLIs Profissionais
Ao criar ferramentas de linha de comando, siga estas recomendações:
- Inclua
--helpclaro em todos os comandos e opções. - Use
--dry-runou confirmação antes de operações destrutivas. - Retorne códigos de saída adequados:
0para sucesso,1ou outro código documentado para erro. - Escreva mensagens em português claro quando a audiência for brasileira.
- Separe lógica de negócio da camada CLI para facilitar testes.
- Use
pathlibem vez de manipular caminhos como strings. - Registre erros com contexto quando a ferramenta roda em automações.
- Documente exemplos reais no README, não apenas flags isoladas.
- Publique prints ou GIFs curtos do terminal se o projeto for para portfólio.
Ideias de Projeto para Portfólio
Uma CLI fica mais forte quando resolve uma dor concreta. Algumas ideias:
organiza-downloads: separa arquivos por tipo, data e tamanho.gsc-resumo: lê CSV exportado do Google Search Console e mostra oportunidades de CTR.vagas-python: filtra vagas por tecnologia, senioridade e modelo remoto a partir de um JSON.nota-fiscal-tools: renomeia PDFs/XMLs por CNPJ, data e valor.markdown-check: valida links, títulos duplicados e tamanho de artigos.
Cada uma dessas ideias conversa com áreas reais de atuação: dados, automação, QA, conteúdo técnico e operações. Para fortalecer o currículo, conecte o projeto com um estudo de caso em carreira Python e mostre o antes/depois da automação.
Conclusão
Python continua excelente para criar CLIs porque permite sair de um script simples para uma ferramenta instalável sem trocar de linguagem. Em 2026, a recomendação prática é: use argparse quando você quer zero dependências, Typer para novos projetos com type hints e Click quando já existe uma base madura nessa biblioteca.
O diferencial de uma CLI profissional não está apenas no parser de argumentos. Está em segurança por padrão, documentação, testes, empacotamento, CI e exemplos reais. Se você precisa de um projeto pequeno, útil e demonstrável para entrevistas, uma CLI bem construída é uma das melhores apostas do ecossistema Python.
CLIs em outras linguagens: Go com Cobra é uma escolha comum para CLIs de infraestrutura como Docker, Kubernetes e GitHub CLI. Rust com clap também gera CLIs rápidas, com binários pequenos e ótima experiência de distribuição.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português