El análisis estático revisa el código sin ejecutar el programa. Sirve para detectar problemas de estilo, imports sin usar, variables no utilizadas, errores comunes, complejidad innecesaria y muchas señales tempranas de baja calidad.
En este tema usaremos Ruff, una herramienta rápida para linting en Python. La instalaremos, la configuraremos en pyproject.toml y la aplicaremos sobre el proyecto ventas_demo.
Un linter analiza el código y marca situaciones sospechosas. Algunas son simples problemas de estilo; otras pueden indicar errores reales.
Por ejemplo, Ruff puede detectar:
True o False.Ruff puede encontrar problemas sin ejecutar el programa, pero no comprueba que las reglas de negocio sean correctas. Las pruebas siguen siendo necesarias para verificar comportamiento.
Por ejemplo, Ruff puede detectar que descuento no se usa:
def calcular_total(precio, cantidad):
descuento = 0.10
return precio * cantidad
Pero no puede saber por sí solo si el cálculo de una promoción responde a la regla comercial esperada. Para eso necesitamos pruebas y revisión humana.
Desde la carpeta del proyecto ventas_demo, activa el entorno virtual.
En Windows PowerShell:
.venv\Scripts\Activate.ps1
En Linux o macOS:
source .venv/bin/activate
Comprueba que estás en la carpeta que contiene pyproject.toml.
Instala Ruff dentro del entorno virtual:
python -m pip install ruff
Verifica la instalación:
python -m ruff --version
Al igual que con otras herramientas, usamos python -m para ejecutar la versión instalada en el entorno activo.
Ejecuta Ruff sobre las carpetas principales del proyecto:
python -m ruff check src tests
Si no encuentra problemas, mostrará una salida breve. Si encuentra advertencias o errores, indicará el archivo, la línea y un código de regla.
Una salida típica puede mencionar reglas como F401 para imports sin usar o F841 para variables locales asignadas y no utilizadas.
Para practicar, crea src/problemas_ruff.py con este contenido:
import os
import math
def obtener_emails(usuarios):
resultado = []
contador = 0
for usuario in usuarios:
if usuario["activo"] == True:
resultado.append(usuario["email"])
return resultado
Este archivo tiene varios problemas: un import no usado, una variable no usada y una comparación booleana innecesaria.
Ejecuta Ruff sobre el archivo:
python -m ruff check src/problemas_ruff.py
Ruff debería señalar problemas similares a estos:
F401: import no utilizado.F841: variable local asignada y no utilizada.E712: comparación con True o False.Los códigos pueden variar según la configuración activa, pero el objetivo es aprender a leer el diagnóstico.
Una versión corregida del archivo sería:
def obtener_emails(usuarios):
resultado = []
for usuario in usuarios:
if usuario["activo"]:
resultado.append(usuario["email"])
return resultado
Eliminamos imports que no se usan, quitamos la variable innecesaria y simplificamos la comparación booleana.
Vuelve a ejecutar:
python -m ruff check src/problemas_ruff.py
Algunos problemas pueden corregirse automáticamente. Para probarlo, vuelve a dejar el archivo con imports sin usar y ejecuta:
python -m ruff check src/problemas_ruff.py --fix
Ruff puede eliminar imports no utilizados y aplicar algunas correcciones seguras. Aun así, siempre conviene revisar los cambios.
Agrega esta configuración al archivo pyproject.toml:
[tool.ruff]
line-length = 88
target-version = "py310"
[tool.ruff.lint]
select = ["E", "F", "B", "SIM", "I"]
ignore = []
Las reglas seleccionadas cubren estilo básico, errores frecuentes, recomendaciones de buenas prácticas, simplificaciones e imports.
Ruff también puede revisar y ordenar imports si se habilita la familia de reglas I. Por ejemplo:
python -m ruff check src tests --select I
Y para corregir imports automáticamente:
python -m ruff check src tests --select I --fix
Si ya usas isort, puedes conservarlo o migrar gradualmente a Ruff. Lo importante es no tener dos configuraciones contradictorias.
Ruff también incluye un formateador. En este curso venimos usando Black, por lo que mantendremos Black para formato e incorporaremos Ruff para análisis estático.
Si quisieras probar el formateador de Ruff, los comandos serían:
python -m ruff format src tests
python -m ruff format --check src tests
En un proyecto real conviene elegir una estrategia clara: Black para formato o Ruff para formato, pero no alternar sin criterio.
Ejecuta el análisis sobre el proyecto completo:
python -m ruff check src tests
Corrige los problemas que Ruff señale. Luego ejecuta las herramientas en este orden:
python -m ruff check src tests
python -m isort src tests
python -m black src tests
python -m pytest
Este flujo permite detectar problemas, ordenar imports, formatear y finalmente comprobar comportamiento.
Supón que en ventas.py aparece una variable que quedó de un intento anterior:
def calcular_total_venta(productos, cliente, pais):
subtotal = 0
cantidad_productos = len(productos)
for producto in productos:
if producto["cantidad"] > 0:
subtotal += producto["precio"] * producto["cantidad"]
return subtotal
Si cantidad_productos no se usa, Ruff puede señalarlo. Esa advertencia ayuda a eliminar ruido y a detectar código incompleto.
Los imports sin usar pueden indicar código abandonado o dependencias innecesarias:
import os
def calcular_subtotal(productos):
return sum(
producto["precio"] * producto["cantidad"]
for producto in productos
)
Si os no se usa, conviene eliminarlo. Un archivo con imports mínimos es más fácil de entender.
Algunas reglas ayudan a simplificar expresiones innecesariamente verbosas.
Versión menos clara:
if usuario["activo"] == True:
emails.append(usuario["email"])
Versión preferida:
if usuario["activo"]:
emails.append(usuario["email"])
La segunda versión expresa la misma condición con menos ruido.
Crea el archivo src/usuarios.py con este contenido:
import os
import json
def filtrar_usuarios_activos(usuarios):
usuarios_activos = []
cantidad = 0
for usuario in usuarios:
if usuario["activo"] == True:
usuarios_activos.append(usuario)
return usuarios_activos
Ejecuta:
python -m ruff check src/usuarios.py
Corrige los problemas señalados y vuelve a ejecutar Ruff hasta que no informe advertencias.
Agrega Ruff al flujo habitual del proyecto. Ejecuta:
python -m ruff check src tests
python -m isort src tests
python -m black src tests
python -m pytest
Luego responde:
Antes de continuar, verifica que puedes hacer lo siguiente:
ruff check sobre archivos y carpetas.--fix.pyproject.toml.En este tema incorporamos Ruff como herramienta de análisis estático. Aprendimos a detectar problemas antes de ejecutar el programa, corregir algunos automáticamente y configurar reglas básicas desde pyproject.toml.
En el próximo tema estudiaremos los code smells como concepto central: cómo reconocer señales de mala calidad, cuándo actuar y cuándo evitar cambios innecesarios.