Python usa indentação para definir blocos, por isso tabs e espaços misturados podem produzir erros difíceis de perceber. Um arquivo pode parecer alinhado em um editor e formar níveis diferentes em outro, dependendo da largura configurada para a tabulação. O módulo tabnanny no Python analisa arquivos e diretórios para localizar indentação ambígua antes que ela cause falhas ou comportamentos inconsistentes.
Neste guia, você aprenderá a executar o módulo pela terminal, verificar projetos recursivamente, integrar check() e process_tokens() a ferramentas e criar uma política confiável de whitespace. O conteúdo complementa nossos artigos sobre tokenize no Python, IndentationError, TabError, bytecode com dis e boas práticas em scripts.
Por que tabs e espaços causam problemas
Um caractere tab não representa uma quantidade fixa de espaços na tela. Editores podem exibi-lo com largura 2, 4 ou 8. Duas linhas visualmente alinhadas podem conter sequências diferentes.
if ativo:
processar()
finalizar()Dependendo das colunas efetivas, o interpretador pode emitir TabError, IndentationError ou interpretar os blocos de modo diferente do esperado.
O que tabnanny detecta
Tabnanny procura indentação cuja interpretação depende do tamanho atribuído às tabs. Ele não é um formatador e não reescreve o arquivo. Seu objetivo é apontar linhas ambíguas para que o desenvolvedor corrija a origem.
A documentação oficial de tabnanny informa que o módulo é pensado principalmente para execução como script, embora possa ser importado por IDEs.
Verificar um arquivo
Execute o módulo com -m e informe o caminho.
python -m tabnanny programa.pyQuando não há problemas, normalmente nenhuma mensagem é exibida. Se uma ambiguidade for encontrada, o diagnóstico inclui arquivo, linha e informações sobre a indentação problemática.
Verificar um diretório
Ao receber um diretório, tabnanny percorre recursivamente sua árvore e analisa arquivos com extensão .py.
python -m tabnanny srcDiretórios que são links simbólicos não são percorridos como diretórios comuns. Ainda assim, projetos grandes devem controlar o ponto inicial para evitar analisar ambientes virtuais, dependências copiadas e diretórios gerados.
Modo verboso
A opção -v aumenta as mensagens de progresso.
python -m tabnanny -v srcRepetir a opção pode incrementar o nível interno de verbosidade. Use em diagnósticos locais; em integração contínua, uma saída curta costuma ser mais útil.
Mostrar somente nomes
A opção -q ativa o modo que imprime apenas nomes de arquivos com problemas.
python -m tabnanny -q srcEsse formato pode alimentar scripts que agregam resultados, mas perde detalhes de linha. Para correção manual, execute novamente sem -q.
Usar check() programaticamente
tabnanny.check() aceita um arquivo ou diretório.
import tabnanny
tabnanny.check("src")As mensagens são impressas em saída padrão por meio de print(). A função não foi desenhada como uma API estruturada moderna, então capturar resultados exige redirecionar a saída ou usar as funções internas com cuidado.
Capturar a saída
from contextlib import redirect_stdout
from io import StringIO
import tabnanny
saida = StringIO()
with redirect_stdout(saida):
tabnanny.check("src")
relatorio = saida.getvalue()
print(relatorio)O redirecionamento de stdout afeta o processo e não é ideal em múltiplas threads. Em ferramentas concorrentes, execute a verificação em subprocesso.
Processar tokens diretamente
process_tokens() recebe tokens produzidos pelo módulo tokenize.
import tabnanny
import tokenize
with open("programa.py", "rb") as arquivo:
tokens = tokenize.tokenize(arquivo.readline)
tabnanny.process_tokens(tokens)Ao detectar ambiguidade, a função gera NannyNag. check() captura essa exceção e imprime o diagnóstico.
Capturar NannyNag
try:
with open("programa.py", "rb") as arquivo:
tokens = tokenize.tokenize(arquivo.readline)
tabnanny.process_tokens(tokens)
except tabnanny.NannyNag as erro:
print("Indentação ambígua:", erro)A exceção carrega informações usadas pelo diagnóstico, mas essa superfície pode mudar. A documentação alerta que a API do módulo não é estável entre releases.
API sujeita a mudanças
Tabnanny é antigo e orientado à linha de comando. Ferramentas que importam seus detalhes internos devem fixar versões, criar testes de compatibilidade e oferecer uma alternativa.
Para um produto que precisa de dados estruturados estáveis, considere chamar python -m tabnanny em subprocesso ou implementar uma regra própria baseada nos tokens INDENT e DEDENT.
tabnanny versus TabError
TabError ocorre quando o próprio interpretador encontra uso inconsistente de tabs e espaços durante a compilação. Tabnanny permite verificar uma árvore inteira sem importar ou executar os módulos.
Assim, ele funciona como inspeção preventiva em commits, builds e editores.
tabnanny versus IndentationError
IndentationError abrange problemas mais gerais, como bloco ausente, recuo inesperado ou dedent incompatível.
if ativo:
print("faltou recuo")Tabnanny tem foco específico em ambiguidades relacionadas a whitespace. Um projeto deve também compilar ou analisar a sintaxe para descobrir os demais erros.
Integrar à integração contínua
Um job simples pode verificar a pasta do projeto.
python -m tabnanny src testsAntes de usar, confirme o código de saída da versão e do ambiente escolhidos. Como a ferramenta foi desenhada para imprimir diagnósticos, pipelines mais robustos podem executar uma pequena camada que captura saída e retorna status não zero quando encontra mensagens.
import subprocess
import sys
resultado = subprocess.run(
[sys.executable, "-m", "tabnanny", "src"],
capture_output=True,
text=True,
)
if resultado.stdout.strip() or resultado.stderr.strip():
print(resultado.stdout)
print(resultado.stderr)
raise SystemExit(1)Teste esse wrapper com um arquivo propositalmente ambíguo.
Git pre-commit
A verificação pode rodar antes do commit, preferencialmente apenas nos arquivos Python alterados.
python -m tabnanny arquivo1.py arquivo2.pyComo a interface padrão recebe caminhos, um script pode invocá-la uma vez por arquivo. Não inclua ambientes virtuais ou artefatos gerados.
Corrigir o problema
A correção mais segura é converter a indentação para espaços, normalmente quatro por nível, sem alterar alinhamentos internos em strings.
Use o comando de conversão de tabs do editor, revise o diff e execute testes. Não faça substituição global de \t em todo o arquivo, pois tabs dentro de strings e dados podem ser intencionais.
Configurar o editor
Ative:
- inserção de espaços ao pressionar Tab;
- largura visual de quatro espaços;
- exibição de caracteres invisíveis;
- remoção de whitespace no fim da linha;
- detecção de indentação por arquivo.
Arquivos de configuração como .editorconfig ajudam a compartilhar a política entre IDEs.
Formatadores e linters
Ferramentas como Black geralmente normalizam indentação em código válido. Linters podem detectar tabs e inconsistências adicionais. Tabnanny continua útil por fazer parte da biblioteca padrão e exigir nenhuma dependência.
A ordem recomendada é: detectar sintaxe inválida, corrigir ambiguidade, formatar e executar testes.
Arquivos gerados e dependências
Não altere automaticamente código de terceiros dentro de um ambiente virtual. Exclua diretórios como .venv, build, dist e caches ao escolher a raiz de verificação.
Se um arquivo gerado precisa ser analisado, corrija o gerador, não apenas o resultado.
Encoding
Tabnanny usa tokenize, que respeita BOM e cookies de encoding. Um problema de encoding pode surgir antes da análise de indentação.
Abra e salve projetos modernos em UTF-8 e mantenha testes para arquivos legados que usam outra codificação.
Código temporariamente incompleto
Durante a digitação, um arquivo pode conter strings ou parênteses abertos. A tokenização pode gerar TokenError. IDEs devem esperar um pequeno intervalo ou analisar somente após salvar.
Não transforme cada estado intermediário em um alerta persistente.
Exemplo de verificador isolado
from pathlib import Path
import subprocess
import sys
def verificar(caminho: Path) -> list[str]:
resultado = subprocess.run(
[sys.executable, "-m", "tabnanny", str(caminho)],
capture_output=True,
text=True,
timeout=30,
)
linhas = []
linhas.extend(resultado.stdout.splitlines())
linhas.extend(resultado.stderr.splitlines())
return [linha for linha in linhas if linha.strip()]O timeout evita uma varredura sem controle em árvores inesperadamente grandes.
Segurança
A ferramenta lê código sem executá-lo, o que é mais seguro que importar módulos. Contudo, caminhos não confiáveis podem apontar para árvores enormes ou arquivos especiais.
Resolva a raiz permitida, recuse caminhos fora dela, limite quantidade e tamanho dos arquivos e execute com permissões mínimas.
Erros frequentes
- Esperar que tabnanny reformate o código.
- Verificar toda a pasta do ambiente virtual.
- Capturar stdout globalmente em servidor multithread.
- Depender de detalhes internos sem fixar a versão.
- Substituir tabs dentro de strings.
- Confundir qualquer IndentationError com ambiguidade de tabs.
- Ignorar arquivos gerados pelo projeto.
- Usar uma árvore de entrada sem limites.
Boas práticas
- Padronize quatro espaços.
- Execute tabnanny em arquivos alterados e na CI.
- Combine com parser, formatter e testes.
- Exclua dependências e artefatos.
- Use subprocesso para integração concorrente.
- Teste a compatibilidade da versão.
- Corrija o gerador quando o arquivo for gerado.
- Proteja a raiz e limite recursos.
Conclusão
O módulo tabnanny no Python detecta indentação ambígua causada pela combinação de tabs e espaços. Ele pode analisar um arquivo ou percorrer diretórios, tornando-se uma verificação leve para editores, hooks e pipelines.
Seu escopo é específico e sua API programática pode mudar, mas a utilidade é clara: localizar problemas de whitespace antes da execução. Com uma política de quatro espaços, visualização de caracteres invisíveis, formatador e testes, tabnanny ajuda a manter blocos Python previsíveis em qualquer editor.







