5. Formateo automático con Black y organización de imports con isort

5.1 Objetivo del tema

En el tema anterior vimos convenciones de estilo. En proyectos reales no conviene corregir cada espacio, salto de línea e import manualmente. Para eso existen herramientas automáticas.

En este tema usaremos Black para formatear código Python e isort para ordenar imports. El objetivo es que el formato sea consistente y que el equipo pierda menos tiempo en discusiones de estilo.

Objetivo práctico: instalar Black e isort, configurarlos en pyproject.toml y aplicarlos sobre archivos Python sin cambiar el comportamiento del programa.

5.2 Qué problema resuelve Black

Black es un formateador automático. Toma un archivo Python válido y lo reescribe con un estilo consistente. No decide nombres, no mejora responsabilidades y no elimina code smells de diseño, pero reduce mucho el ruido visual.

Por ejemplo, este código funciona, pero es incómodo de leer:

def calcular(precio,cantidad,cliente):
    total=precio*cantidad
    if cliente=="vip": total-=total*0.15
    return round(total,2)

Black lo puede convertir en una forma más uniforme:

def calcular(precio, cantidad, cliente):
    total = precio * cantidad
    if cliente == "vip":
        total -= total * 0.15
    return round(total, 2)

5.3 Qué problema resuelve isort

isort ordena y agrupa imports. Esto evita que cada programador acomode los imports a su manera y facilita detectar dependencias innecesarias.

Ejemplo desordenado:

from ventas import calcular_total_venta
import os
from decimal import Decimal
import requests
from datetime import date

Ejemplo ordenado:

import os
from datetime import date
from decimal import Decimal

import requests

from ventas import calcular_total_venta

5.4 Activar el entorno virtual

Trabajaremos sobre el proyecto ventas_demo creado en temas anteriores. Desde la carpeta del proyecto, activa el entorno virtual.

En Windows PowerShell:

.venv\Scripts\Activate.ps1

En Linux o macOS:

source .venv/bin/activate

Verifica que estás en la carpeta donde se encuentra pyproject.toml.

5.5 Instalar Black e isort

Instala las herramientas dentro del entorno virtual:

python -m pip install black isort

Comprueba las versiones instaladas:

python -m black --version
python -m isort --version

Usamos python -m para asegurarnos de ejecutar las herramientas del entorno virtual activo.

5.6 Configurar pyproject.toml

Agrega esta configuración al archivo pyproject.toml del proyecto:

[tool.black]
line-length = 88
target-version = ["py310"]

[tool.isort]
profile = "black"
line_length = 88

El perfil black en isort hace que ambas herramientas usen criterios compatibles. Así evitamos que una herramienta cambie algo que luego la otra vuelve a modificar.

5.7 Crear un archivo para practicar

Crea un archivo llamado src/reporte.py con código deliberadamente mal formateado:

from ventas import calcular_total_venta
import os
from datetime import date

def generar_resumen(productos,cliente,pais):
    total=calcular_total_venta(productos,cliente,pais)
    return {"fecha":date.today().isoformat(),"cliente":cliente,"pais":pais,"total":total,"directorio":os.getcwd()}

El archivo tiene imports desordenados, falta de espacios, línea larga y una función pegada a los imports.

5.8 Revisar sin modificar con Black

Antes de formatear, podemos pedirle a Black que revise si cambiaría archivos:

python -m black --check src tests

Si encuentra archivos que no cumplen el formato, informará que los modificaría. Este modo es útil para controles automáticos porque no escribe cambios.

5.9 Ver el diff de Black

También podemos ver qué cambiaría Black sin modificar el archivo:

python -m black --diff src/reporte.py

El diff permite revisar el impacto antes de aplicar el formateo. En archivos grandes, esto ayuda a separar cambios de estilo de cambios de comportamiento.

5.10 Aplicar Black

Para formatear el archivo, ejecuta:

python -m black src/reporte.py

También puedes formatear todas las carpetas principales del proyecto:

python -m black src tests

Después del formateo, el archivo src/reporte.py debería quedar con una forma similar a esta:

from ventas import calcular_total_venta
import os
from datetime import date


def generar_resumen(productos, cliente, pais):
    total = calcular_total_venta(productos, cliente, pais)
    return {
        "fecha": date.today().isoformat(),
        "cliente": cliente,
        "pais": pais,
        "total": total,
        "directorio": os.getcwd(),
    }

Black mejora el formato, pero no ordena los imports de la forma esperada. Para eso usaremos isort.

5.11 Revisar imports con isort

Primero ejecuta isort en modo revisión:

python -m isort --check-only src tests

Si los imports están desordenados, isort informará qué archivos necesitan cambios. Para ver el diff:

python -m isort --diff src/reporte.py

5.12 Aplicar isort

Ejecuta isort sobre el archivo:

python -m isort src/reporte.py

O sobre las carpetas del proyecto:

python -m isort src tests

Ahora los imports deberían quedar ordenados:

import os
from datetime import date

from ventas import calcular_total_venta

5.13 Orden recomendado de ejecución

Una práctica común es ejecutar primero isort y luego Black:

python -m isort src tests
python -m black src tests

Como isort está configurado con profile = "black", el resultado debería ser estable. Si vuelves a ejecutar ambos comandos, no deberían aparecer cambios nuevos.

5.14 Verificar pruebas después del formateo

El formateo no debería cambiar el comportamiento. Después de aplicar Black e isort, ejecuta:

python -m pytest

Si las pruebas fallan, revisa el archivo. Un formateador trabaja sobre sintaxis válida, pero si hiciste cambios manuales junto con el formateo, podrías haber modificado la lógica accidentalmente.

5.15 Agregar scripts simples al README

Conviene documentar los comandos habituales del proyecto en README.md. Por ejemplo:

## Comandos útiles

Ordenar imports:

python -m isort src tests

Formatear código:

python -m black src tests

Ejecutar pruebas:

python -m pytest

Cuando un proyecto tiene comandos visibles, es más fácil que todos los integrantes trabajen de la misma forma.

5.16 Qué no hacen estas herramientas

Black e isort son muy útiles, pero tienen límites. No solucionan todos los problemas de calidad.

  • No eligen nombres más expresivos.
  • No separan responsabilidades mezcladas.
  • No eliminan duplicación de reglas de negocio.
  • No detectan todos los errores lógicos.
  • No reemplazan la revisión humana.
Formatear es necesario, pero no suficiente. Un archivo puede estar perfectamente formateado y seguir teniendo code smells importantes.

5.17 Ejercicio guiado

Crea el archivo src/clientes.py con este contenido:

import json
from datetime import datetime
import os

def crear_cliente(nombre,email,activo=True):
    return {"nombre":nombre,"email":email,"activo":activo,"creado_en":datetime.now().isoformat(),"directorio":os.getcwd()}

Ejecuta los comandos:

python -m isort src/clientes.py
python -m black src/clientes.py

Luego revisa qué cambió y responde: ¿qué partes corrigieron las herramientas y qué problemas de diseño seguirían dependiendo de una persona?

5.18 Ejercicio propuesto

Ejecuta Black e isort sobre todo el proyecto:

python -m isort src tests
python -m black src tests
python -m pytest

Luego realiza estas tareas:

  • Confirma que las pruebas siguen pasando.
  • Identifica un cambio hecho por Black.
  • Identifica un cambio hecho por isort.
  • Busca un problema de calidad que las herramientas no hayan corregido.

5.19 Lista de verificación

Antes de continuar, verifica que puedes hacer lo siguiente:

  • Instalar Black e isort en un entorno virtual.
  • Configurar ambas herramientas en pyproject.toml.
  • Ejecutar Black en modo revisión, diff y escritura.
  • Ejecutar isort en modo revisión, diff y escritura.
  • Aplicar ambas herramientas sobre src y tests.
  • Ejecutar pruebas después del formateo.
  • Explicar qué problemas no resuelven los formateadores.

5.20 Conclusión

En este tema automatizamos una parte importante del estilo del código. Black nos ayuda a mantener un formato uniforme e isort ordena los imports de manera consistente.

En el próximo tema incorporaremos Ruff, una herramienta de análisis estático que puede detectar problemas antes de ejecutar el programa y complementar el trabajo de Black e isort.