Pasar al contenido principal
Please wait...
Logo Python en briques, renard en LEGO sur fond bleu et jaune.

Mejora la calidad de tu código Python con Ruff

Con el paso de los años y la profesionalización de la comunidad, el ecosistema de Python se ha enriquecido con una multitud de herramientas de análisis estático de código para ayudar a los equipos a mantener un código de calidad: Flake8, pylint, isort, Mypy, Pyright, Black, Bandit… Estas herramientas cumplen funciones variadas, desde la verificación de estilos de código hasta la detección de errores potenciales. Sin embargo, su uso simultáneo puede a veces ralentizar los flujos de trabajo y aumentar la complejidad de la configuración.

Es ahí donde entra en juego ruff, con la ambición de convertirse en una herramienta única para reemplazarlas a todas.

ruff es una herramienta aparecida en 2022 que busca sustituir a los linters y formatters existentes, poniendo el acento en la rapidez de ejecución, gracias a estar escrita en Rust en lugar de Python. Hoy ya implementa más de 800 reglas de verificación, tomadas de Pyflakes, pycodestyle, mccabe, isort, pydocstyle, pyupgrade, Flake8 (y varias decenas de sus plugins), Bandit, eradicate, Pylint, tryceratops, flynt, refurb, pydoclint… Y por si no fuera suficiente, empieza también a integrar sus propias reglas adicionales, en particular para frameworks populares como FastAPI o NumPy.

A pesar de este gran número de reglas, se ejecuta con una rapidez sorprendente, capaz de analizar la mayoría de las bases de código en menos de un segundo. Por ejemplo, analiza toda la base de CPython en apenas 160 ms, frente a casi 12 s para Pyflakes y más de un minuto para Pylint.

En lo relativo al formateo, el ecosistema Python ya se encontraba ampliamente unificado alrededor de Black, que se impuso gracias a su elección radical de imponer un estilo casi sin opciones de configuración, evitando así largas y estériles discusiones sobre reglas de estilo. ruff retoma este principio y propone un formateo prácticamente idéntico al de Black (las diferencias son voluntarias y documentadas), pero con una velocidad de ejecución multiplicada. Además, es ligeramente más configurable, con parámetros que pueden convencer a ciertos equipos: es posible darle preferencia a las simple quotes en lugar de las double quotes para las cadenas, o incluso preservar la elección hecha por el desarrollador.

Cabe señalar que parte de las divergencias respecto a Black siguen siendo retrocompatibles: ruff introduce modificaciones que Black acepta, sin obligar a revertirlas. Esto permite incluso la convivencia de ambos en ciertos entornos, como me ocurrió en un proyecto donde ruff empezaba a ser adoptado por los desarrolladores, mientras Black seguía siendo la referencia en los flujos de CI/CD.

¿Adoptar o no adoptar ruff?

 

Desde un punto de vista funcional, la decisión de adoptar ruff dependerá mucho de las herramientas que ya estés usando.

¿No usas aún un linter?

¡Ya es hora de implementar uno en tu cadena de producción de software! ruff es una opción muy adecuada, ya que no tendrás que lidiar con diferencias respecto a tus herramientas actuales, y gracias a su excelente rendimiento podrás integrarlo en tus workflows sin un impacto significativo en la velocidad.

Eso sí, evita ser demasiado ambicioso al principio: comienza activando únicamente las reglas por defecto de ruff y, una vez que tu código esté en conformidad, añade de forma progresiva las reglas que más te interesen. Así evitarás desanimarte frente a la gran carga de trabajo que puede implicar adaptar una base de código con un largo historial.

¿Usas principalmente Flake8 o herramientas similares? 

En este caso, pasar a ruff también es una decisión acertada. Ganarás en velocidad manteniendo una excelente compatibilidad con tu ecosistema actual.

¿Eres un usuario intensivo de Pylint?

Aquí la elección es más compleja. Aunque ruff ha comenzado a integrar algunas reglas de Pylint, no pretende reemplazarlo por completo en el corto plazo. En efecto, Pylint no es solo un linter: también realiza verificación de tipos (con la particularidad de hacerlo en gran parte sin depender de anotaciones), algo que ruff ha decidido no implementar de momento.

Si tu código está correctamente tipado, la solución puede ser combinar ruff para el lint y Mypy para la verificación de tipos.
De lo contrario, es preferible seguir con Pylint. También puedes optar por un compromiso: usar ruff en los entornos de desarrollo, para un análisis más rápido, y Pylint en la CI/CD, para un análisis más exhaustivo.

 ¿Y qué pasa con el formateo?

Ya uses o no un formateador, reemplazarlo por ruff puede ser interesante para ganar en comodidad gracias a su rendimiento. Sin embargo, cabe matizar que mientras Black garantiza una ejecución idéntica antes y después del reformatado (comparando rigurosamente los AST generados), ruff no ofrece a priori este nivel de garantía. Existe, por tanto, un ligero riesgo al aplicarlo en grandes bases de código, aunque el objetivo de producir un código prácticamente idéntico al de Black debería evitar sorpresas desagradables.

¿Por qué no adoptar ruff?

El instrumento perfecto no existe, y lamentablemente hay también buenas razones para no adoptar ruff. Estas se centran principalmente en su gobernanza y en la elección del lenguaje Rust.

En cuanto a la gobernanza, a diferencia de la mayoría de herramientas que ruff pretende sustituir, no es un proyecto puramente comunitario. Se desarrolla bajo la dirección de Astral, una empresa neoyorquina. Aunque Astral parece sinceramente comprometida con el open-source y con seguir ofreciendo herramientas gratuitas, inevitablemente llegará el momento de plantear un modelo económico.

El hecho de que use una licencia muy permisiva (MIT) garantiza que, en caso de conflicto entre las aspiraciones de Astral y la comunidad, siempre será posible un fork. No obstante, aquí entra en juego el uso de Rust: si bien esta elección era necesaria para alcanzar el rendimiento buscado, dificulta la posibilidad de un fork, ya que muchos desarrolladores de Python no dominan Rust. Esta desventaja se atenúa por la creciente popularidad de Rust en la comunidad Python, donde reemplaza cada vez más al C y al C++ en el desarrollo de librerías de alto rendimiento, como es el caso de Pydantic (reescrito en gran parte en Rust) o tokenizers de Hugging Face.

Finalmente, se plantea la cuestión del futuro de las herramientas existentes. ruff se inspira ampliamente en ellas para desarrollarse rápidamente, pero su éxito podría amenazarlas al desviar parte de su base de usuarios. Por ello, sería interesante que en el futuro su gobernanza se compartiera con la PSF y PyCQA, para preservar la experiencia acumulada en el ecosistema.

Por mi parte, ya he adoptado ruff en la mayoría de mis proyectos, especialmente en los de OBI Partner, aunque sigo atento a estos tres puntos. Así que, si tú también quieres dar el paso y necesitas asistencia en la implementación, no dudes en ponerte en contacto con nosotros.

¿Listo? ¡pipx install ruff!

Etiquetas

Añadir nuevo comentario

HTML Restringido

  • Puede alinear imágenes (data-align="center") pero también videos, citas, y demás.
  • No sólo puede subtitular imágenes (data-caption="Text"), sino también videos, blockquotes, y mucho más.