Ruff ajuda a detectar problemas de código e a manter um estilo consistente sem combinar vários comandos diferentes. O linter encontra imports não usados, erros comuns e violações selecionadas; o formatador reorganiza a apresentação do código. São funções complementares.
Antes de configurar dezenas de regras, defina um conjunto pequeno que a equipe consiga corrigir. O objetivo é reduzir defeitos e discussões repetitivas, não transformar cada commit em uma disputa de estilo. O guia de PEP 8 explica as convenções que continuam relevantes.
Instalar e executar
Adicione Ruff como dependência de desenvolvimento:
python -m pip install ruff
ruff check .
ruff format --check .
Para aplicar correções e formatação:
ruff check --fix .
ruff format .
Revise o diff e execute os testes depois. Uma correção sintaticamente válida ainda pode revelar uma expectativa incorreta no projeto.
Configuração no pyproject.toml
Uma base conservadora é suficiente:
[tool.ruff]
target-version = "py312"
line-length = 88
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "B"]
[tool.ruff.format]
quote-style = "double"
F cobre verificações do Pyflakes, I organiza imports e B reúne alertas do flake8-bugbear. Não ative famílias inteiras sem ler o impacto. A referência oficial de configuração descreve precedência e opções.
O formatador não ordena imports sozinho. A sequência recomendada é executar o linter com correção e depois formatar. A documentação do formatador também lista regras que podem entrar em conflito com a formatação.
Adotar em código existente
Primeiro execute Ruff sem --fix e registre a quantidade de ocorrências. Corrija erros objetivos, adicione a configuração ao repositório e só depois amplie regras. Evite um único commit que reformate todo o projeto junto com mudanças funcionais; isso dificulta revisão e histórico.
Na CI, valide sem modificar arquivos:
ruff check .
ruff format --check .
Combine esses comandos com testes em pytest. O linter não substitui testes, revisão ou type checker: cada ferramenta observa uma classe diferente de problema.
Checklist
- Fixe a faixa de versão nas dependências de desenvolvimento.
- Defina
target-versionconforme o Python realmente suportado. - Comece com poucas regras e documente exceções.
- Rode
check --fixantes deformatquando quiser corrigir imports. - Valide
checkeformat --checkna CI. - Revise correções automáticas e rode a suíte de testes.
Uma configuração curta e obrigatória costuma gerar mais valor que centenas de regras ignoradas. Ruff funciona melhor quando o feedback é rápido, previsível e igual no editor, no terminal e na CI.
O que o linter encontra e o formatador decide
Separar as duas funções evita expectativas erradas. ruff check analisa o código e aponta regras violadas: um nome indefinido, um import sem uso, uma comparação problemática ou imports fora da ordem. ruff format reescreve a apresentação, como quebras de linha, espaços e aspas, sem tentar corrigir toda decisão lógica.
Essa diferença também define a ordem dos comandos. Quando a regra I está ativa, ruff check --fix organiza imports; em seguida, ruff format estabiliza o layout. Para apenas verificar, sem tocar nos arquivos, use ruff check . e ruff format --check .. Essa é a modalidade adequada para CI.
Um relatório limpo não prova que o programa está correto. Ruff trabalha com padrões estáticos e algumas correções mecânicas. Testes verificam exemplos de comportamento, enquanto um type checker examina contratos de tipos. As ferramentas se complementam.
Escolher regras com intenção
Os códigos de regra pertencem a famílias. E4, E7 e E9 cobrem erros selecionados do pycodestyle; F corresponde ao Pyflakes; I trata imports; B incorpora verificações do flake8-bugbear. Cada regra tem documentação própria na referência oficial de regras.
Não copie uma lista extensa apenas porque outro projeto a utiliza. Uma aplicação web, uma biblioteca pública e um conjunto de notebooks têm necessidades diferentes. Comece por erros de alta confiança, entenda os falsos positivos percebidos pela equipe e amplie em mudanças pequenas. Quando ativar uma família, registre no commit por que ela ajuda.
ignore global deve ser a última opção. Se uma exceção faz sentido apenas em testes ou scripts de migração, use uma configuração por arquivo:
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"]
O exemplo admite assert em testes se a família de segurança correspondente estiver ativa. A justificativa deve ficar próxima da configuração. Para uma única linha excepcional, um # noqa: CODIGO específico é melhor que # noqa genérico, pois mantém as outras verificações.
Exclusões, arquivos gerados e notebooks
Diretórios de ambientes virtuais, caches e builds não devem entrar na análise. Ruff já reconhece exclusões comuns, e opções como extend-exclude permitem acrescentar caminhos do projeto. Não exclua uma pasta apenas para silenciar dívida técnica sem registrar um plano.
Código gerado merece tratamento explícito. Se o arquivo é sempre recriado por uma ferramenta externa, formatá-lo pode produzir um diff que será perdido na próxima geração. Exclua-o ou configure o gerador. Se o código gerado é editado e mantido como fonte, então ele deve seguir a política normal.
Ruff também oferece suporte a notebooks, mas regras e correções podem ter efeitos diferentes porque a ordem das células importa. Experimente em uma cópia, revise o diff e escolha se notebooks fazem parte do escopo. A política precisa ser intencional, não um efeito colateral de executar na raiz.
Correções automáticas e segurança
O comando --fix aplica correções consideradas disponíveis, mas nem toda transformação possível é habilitada como segura. Ruff distingue correções seguras e inseguras; uma transformação insegura pode alterar comportamento ou remover informação. Leia o diagnóstico antes de habilitar --unsafe-fixes.
Mesmo correções seguras precisam de revisão. Remover um import sem uso costuma ser mecânico, mas o import poderia existir apenas por efeito colateral, o que já indica um design que deve ser explicitado. Organizar imports pode expor ciclos que antes dependiam de uma ordem acidental. Rode testes depois de qualquer alteração ampla.
Use ruff check --diff quando quiser inspecionar correções propostas sem modificar arquivos. Em adoções grandes, aplique uma família por vez e separe formatação de mudanças funcionais. Isso facilita revisão, git blame e reversão.
Versão alvo, comprimento de linha e formatação
target-version permite que Ruff considere a sintaxe e algumas modernizações válidas na versão mínima do projeto. Configure-o de acordo com requires-python e com a matriz da CI. Declarar py312 enquanto ainda se promete Python 3.10 pode gerar sugestões incompatíveis.
line-length orienta linter e formatador, mas não significa que toda linha será quebrada. URLs, strings longas e construções que não podem ser divididas podem ultrapassar o limite. Não complemente o formatador com regras conflitantes apenas para forçar uma métrica visual.
Ao migrar de Black, compare uma formatação completa em uma branch dedicada. O formatador do Ruff busca compatibilidade de estilo, mas existem diferenças documentadas. Remova o comando anterior, a integração do editor e a configuração antiga quando concluir a migração; dois formatadores concorrentes criam alterações alternadas.
Integração com editor, hooks e CI
O editor pode formatar ao salvar e mostrar diagnósticos, porém a configuração versionada continua sendo a fonte de verdade. Cada pessoa pode escolher quando aplicar correções, desde que o resultado final passe nos mesmos comandos.
Hooks locais fornecem feedback antes do push, mas não substituem a CI: hooks podem ser ignorados e ambientes locais variam. Se o projeto usa pre-commit, fixe a revisão da integração e mantenha argumentos equivalentes aos comandos documentados.
Na CI, execute verificações que não alteram o checkout:
ruff check --output-format=github .
ruff format --check --diff .
python -m pytest
O formato de saída pode melhorar anotações no provedor, mas não muda as regras. Fixe a versão de Ruff nas dependências ou no mecanismo de instalação da CI. Atualizações podem introduzir novas regras, corrigir diagnósticos e alterar formatação; faça esse upgrade em um pull request revisável.
Diagnosticar um resultado inesperado
Quando uma regra parece surgir ou desaparecer, execute Ruff no arquivo específico e confira qual configuração foi descoberta. Projetos aninhados podem ter mais de um pyproject.toml. Observe também seleções na linha de comando, que podem alterar o conjunto esperado.
Se CI falha, mas a máquina local passa, compare primeiro a versão de Ruff, o diretório de execução e os arquivos efetivamente analisados. Depois confirme target-version e exclusões. Rodar a mesma linha de comando a partir da raiz elimina grande parte dessas diferenças.
Antes de mesclar uma política nova, peça que a CI passe em um checkout limpo, confirme que o formatador não produz diff e execute testes após as correções. Assim, Ruff deixa de ser apenas uma ferramenta rápida e passa a ser um contrato pequeno, explícito e verificável para o repositório.