tabnanny en Python: corrige la indentación

Publicado el: 04/08/2026
Tempo de leitura: 7 minutos
Editor de código que representa corrección de tabs y espacios con tabnanny en Python

Python usa la indentación para definir bloques, por lo que mezclar tabs y espacios puede producir errores difíciles de ver. Un archivo puede parecer alineado en un editor y formar niveles diferentes en otro porque el ancho de la tabulación es configurable. El módulo tabnanny en Python analiza archivos y directorios para detectar indentación ambigua antes de que cause fallos o una interpretación inesperada.

Esta guía explica el uso desde la terminal, la comprobación recursiva de proyectos, check(), process_tokens() y una política confiable de whitespace. Complementa nuestros artículos sobre tokenize en Python, IndentationError, TabError, bytecode con dis y buenas prácticas en scripts.

Por qué tabs y espacios causan problemas

Un carácter tab no representa una cantidad fija de espacios visuales. Los editores pueden mostrarlo con ancho de dos, cuatro u ocho columnas. Dos líneas que parecen alineadas pueden contener secuencias distintas.

if activo:
	procesar()
    finalizar()

Según las columnas efectivas, el intérprete puede lanzar TabError, IndentationError o interpretar bloques de forma diferente a la intención del autor.

Qué detecta tabnanny

Tabnanny busca indentación cuyo significado depende del ancho asignado a las tabs. No es un formateador y no reescribe archivos. Su objetivo es señalar líneas ambiguas para corregir la fuente original.

La documentación oficial de tabnanny indica que el módulo está pensado principalmente para ejecutarse como script, aunque una IDE puede importarlo.

Comprobar un archivo

Ejecuta el módulo con -m y proporciona una ruta.

python -m tabnanny programa.py

Cuando no hay problemas, normalmente no se imprime nada. Si se encuentra ambigüedad, el diagnóstico incluye archivo, línea e información sobre el whitespace.

Comprobar un directorio

Cuando recibe un directorio, tabnanny recorre recursivamente el árbol y comprueba archivos .py.

python -m tabnanny src

Los directorios que son enlaces simbólicos no se recorren como directorios ordinarios. En proyectos grandes, elige una raíz limitada para evitar entornos virtuales, dependencias copiadas y resultados generados.

Salida detallada

La opción -v aumenta los mensajes de progreso.

python -m tabnanny -v src

Repetir la opción puede incrementar la verbosidad interna. Es útil para diagnóstico local; en integración continua suele ser preferible una salida corta.

Mostrar solo nombres

La opción -q imprime únicamente los nombres de archivos con problemas.

python -m tabnanny -q src

El formato puede alimentar otro script, pero omite los detalles de línea. Para corregir, vuelve a ejecutar sin -q.

Usar check() desde Python

tabnanny.check() acepta un archivo o directorio.

import tabnanny

tabnanny.check("src")

Los diagnósticos se escriben en stdout mediante print(). La función no fue diseñada como una API estructurada moderna, por lo que una integración debe redirigir la salida o usar piezas internas con cuidado.

Capturar la salida

from contextlib import redirect_stdout
from io import StringIO
import tabnanny

salida = StringIO()

with redirect_stdout(salida):
    tabnanny.check("src")

reporte = salida.getvalue()
print(reporte)

La redirección global de stdout no es segura en un servidor multithread. Las herramientas concurrentes deberían ejecutar tabnanny en un subprocess.

Procesar tokens directamente

process_tokens() recibe tokens producidos por tokenize.

import tabnanny
import tokenize

with open("programa.py", "rb") as archivo:
    tokens = tokenize.tokenize(archivo.readline)
    tabnanny.process_tokens(tokens)

Al detectar ambigüedad, la función lanza NannyNag. check() captura la excepción y muestra el diagnóstico.

Capturar NannyNag

try:
    with open("programa.py", "rb") as archivo:
        tokens = tokenize.tokenize(archivo.readline)
        tabnanny.process_tokens(tokens)
except tabnanny.NannyNag as error:
    print("Indentación ambigua:", error)

La excepción contiene información usada por el informe, pero esta superficie puede cambiar. La documentación advierte que la API programática puede no ser compatible entre versiones.

Una API que puede cambiar

Tabnanny es una utilidad antigua orientada a la terminal. Las herramientas que dependen de detalles internos deben fijar versiones, mantener pruebas de compatibilidad y ofrecer una alternativa.

Cuando se necesitan datos estructurados estables, considera invocar python -m tabnanny en subprocess o implementar una regla sobre tokens INDENT y DEDENT.

tabnanny frente a TabError

TabError aparece cuando el intérprete encuentra tabs y espacios inconsistentes durante la compilación. Tabnanny puede inspeccionar un árbol completo sin importar ni ejecutar módulos.

Por eso funciona como comprobación preventiva en commits, builds y editores.

tabnanny frente a IndentationError

IndentationError abarca problemas más amplios, como un bloque ausente, indentación inesperada o un dedent incompatible.

if activo:
print("falta indentación")

Tabnanny tiene el propósito más específico de detectar ambigüedad de whitespace. El proyecto también debe compilar o parsear el código para encontrar otros errores.

Integración continua

Un job de CI puede analizar las carpetas del proyecto.

python -m tabnanny src tests

Confirma el comportamiento del código de salida en la versión elegida. Como la utilidad se centra en imprimir diagnósticos, un pipeline confiable puede envolverla y fallar cuando aparece salida.

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)

Prueba el wrapper con un archivo deliberadamente ambiguo.

Comprobación pre-commit

Un hook de Git puede verificar los archivos Python modificados.

python -m tabnanny archivo1.py archivo2.py

La interfaz recibe rutas, por lo que un wrapper puede invocarla una vez por archivo. Excluye entornos virtuales y artefactos generados.

Corregir la indentación

La corrección más segura consiste en convertir la indentación a espacios, normalmente cuatro por nivel, sin alterar tabs dentro de strings o datos.

Usa el comando de conversión del editor, inspecciona el diff y ejecuta tests. Una sustitución global de todos los caracteres \t puede dañar contenido intencional.

Configurar el editor

Activa:

  • espacios al pulsar Tab;
  • ancho visual de cuatro espacios;
  • visualización de caracteres invisibles;
  • eliminación de whitespace final;
  • detección de indentación por archivo.

Un archivo .editorconfig ayuda a compartir la política entre IDEs.

Formateadores y linters

Formateadores como Black normalmente normalizan la indentación en código válido. Los linters detectan tabs y otros problemas. Tabnanny sigue siendo útil porque forma parte de la biblioteca estándar.

Un orden razonable es: detectar errores de sintaxis, corregir whitespace ambiguo, formatear, ejecutar el linter y correr tests.

Archivos generados y dependencias

No edites automáticamente código de terceros dentro de un entorno virtual. Excluye carpetas como .venv, build, dist y caches seleccionando la raíz correcta.

Si el código generado falla, corrige el generador en vez de parchear únicamente el resultado.

Encoding

Tabnanny depende de tokenize, que respeta BOM UTF-8 y cookies de encoding. Un problema de codificación puede aparecer antes del análisis de indentación.

Usa UTF-8 en proyectos modernos y conserva fixtures para codificaciones heredadas que deban seguir funcionando.

Código temporalmente incompleto

Mientras se escribe, un archivo puede contener una string o delimitador sin cerrar. La tokenización puede generar TokenError. Las IDE deberían esperar un pequeño intervalo o analizar después de guardar.

No conviertas cada estado intermedio en una advertencia permanente.

Verificador aislado

from pathlib import Path
import subprocess
import sys


def verificar(ruta: Path) -> list[str]:
    resultado = subprocess.run(
        [sys.executable, "-m", "tabnanny", str(ruta)],
        capture_output=True,
        text=True,
        timeout=30,
    )
    lineas = resultado.stdout.splitlines() + resultado.stderr.splitlines()
    return [linea for linea in lineas if linea.strip()]

El timeout limita recorridos inesperados por árboles muy grandes.

Seguridad

La utilidad lee código sin ejecutarlo, lo cual es más seguro que importarlo. Una ruta no confiable todavía puede apuntar a árboles enormes, archivos especiales o ubicaciones fuera del proyecto autorizado.

Resuelve la raíz permitida, rechaza salidas de esa raíz, limita tamaño y cantidad de archivos y ejecuta con permisos mínimos.

Errores frecuentes

  • Esperar que tabnanny formatee el archivo.
  • Analizar todo el entorno virtual.
  • Redirigir stdout global en un servidor multithread.
  • Depender de detalles internos sin pruebas de versión.
  • Sustituir tabs dentro de strings.
  • Considerar todo IndentationError una ambigüedad de tabs.
  • Parchear archivos generados en vez del generador.
  • Analizar una ruta sin límites.

Buenas prácticas

  • Estandariza cuatro espacios.
  • Ejecuta tabnanny en archivos modificados y en CI.
  • Combina con parser, formatter, linter y tests.
  • Excluye dependencias y artefactos.
  • Usa subprocess para integraciones concurrentes.
  • Prueba compatibilidad en versiones soportadas.
  • Corrige generadores que producen whitespace ambiguo.
  • Protege la raíz y limita recursos.

Conclusión

El módulo tabnanny en Python detecta indentación ambigua causada por la combinación de tabs y espacios. Puede inspeccionar un archivo o recorrer directorios de forma recursiva, por lo que es una comprobación ligera para editores, hooks y pipelines.

Su alcance es específico y su API programática puede cambiar, pero su objetivo es claro: localizar problemas de whitespace antes de ejecutar. Con una política de cuatro espacios, caracteres invisibles visibles, un formateador y tests automáticos, tabnanny ayuda a mantener bloques Python predecibles en cualquier editor.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código fuente y sintaxis que representan análisis léxico con tokenize en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tokenize en Python: analiza código fuente

    Aprende tokenize en Python para analizar tokens, comentarios, encoding, posiciones y reconstruir código fuente con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Terminal de programación que representa compilación de entradas interactivas con codeop en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    codeop en Python: compila entradas interactivas

    Aprende codeop en Python para detectar entradas completas, compilar comandos de REPL y conservar __future__ con seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Desarrollador analizando estructura de código y tablas de símbolos con symtable en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    symtable en Python: ámbitos y símbolos

    Aprende symtable en Python para analizar ámbitos, símbolos, globals, nonlocals, closures, imports, annotations y type parameters.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Monitor con código binario que representa análisis de bytecode con dis en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    dis en Python: entiende el bytecode

    Aprende dis en Python para analizar bytecode, instrucciones, cachés adaptativas, posiciones, tracebacks y detalles internos de CPython.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Pantalla de error que representa diagnóstico de crashes y deadlocks con faulthandler en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    faulthandler en Python: diagnostica bloqueos

    Aprende faulthandler en Python para diagnosticar crashes, deadlocks y timeouts mediante pilas de threads y código nativo.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Portátil con código que representa análisis de traceback y depuración en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    traceback en Python: errores y pila

    Aprende traceback en Python para capturar, formatear y registrar pilas de error sin filtrar datos sensibles ni retener memoria.

    Ler mais

    Tempo de leitura: 6 minutos
    03/08/2026