Un gestor de paquetes poético

En la mayoría de los artículos que he escrito en el blog los ejemplos de código que he mostrado siempre son gestionados  por una tool llamada poetry, esta herramienta ha venido ganando terreno dentro del ecosistema de python, por ejemplo en el state python 2020 como se puede ver en la Figura 1 ya apareció en la lista de preferencias de algunos usuarios, también en proyectos públicos en github se pueden encontrar proyectos que lo usan, pero que es realmente poetry? qué beneficios ofrece? en este artículo responderemos estas preguntas

Figura 1 Uso de la herramienta poetry

Que es poetry?

Su documentacion oficial lo define como un gestor de dependencias y un empaquetador de librerías python, si han desarrollado con python depronto han escuchado un poco del dependency hell (ver Figura 2) en donde el reto está en coordinar versiones de librerías, versiones de python y versiones de diferentes frameworks para instalar exactamente las versiones con las que el proyecto funciona buscando que durante el proceso no entre en conflicto con otros proyectos que usen las mismas dependencias pero con diferentes versiones... por tal motivo buscando diferentes soluciones me he encontrado con poetry, uno de los mayores beneficios de este gestor de dependencias es su archivo pyproject.toml este archivo es la clave de poetry, este contiene información de la metada del proyecto y de todas sus dependencias, si han trabajado con node y npm es el equivalente a package.json, pero adicionalmente poetry tiene su propio CLI este es una gran ventaja a largo plazo pues facilita entre muchas cosas acceso a diferentes configuraciones de manera rápida y sencilla, a lo largo del artículo analizaremos algunos comandos que podremos utilizar, sin embargo en su documentacion encontrarán toda la información

Figura 2 Python dependency hell

Para iniciar a trabajar con poetry tenemos 2 comandos claves, los 2 al final del dia nos inicializan el archivo pyproject.toml pero de diferente forma

  • poetry init este primer comando nos inicializa un proyecto de manera interactiva  como se ve en la Figura 3  y el resultado es  un archivo pyproject.toml  con la siguiente información
[tool.poetry]
name = "poetry-intro"
version = "0.1.0"
description = "Este es un ejemplo"
authors = ["jairo <me@jairoandres.com>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

Figura 3 Inicialización de un proyecto utilizando el comando init
  • poetry new con este comando poetry genera un archivo de configuración, pero además genera una estructura de proyecto (ver Figura 4) lista para empezar a codificar, para este ejemplo usare el comando
poetry new myporyecto --name src

para que dentro del proyecto cree una carpeta llamada src donde estará todo el código python

Figura 4 Estructura del proyecto generada por poetry

Solamente Virtualenv y Pip

Generalmente cuando se trabaja con un stack en python se utilizan estas dos herramientas, de hecho por ejemplo el libro two scoops django las recomienda, y funcionan muy bien ademas que son muy prácticas y cumplen  con el 12 twelve factor al tener las dependencias en un archivo manifiesto y usarlas aisladas del sistema principal, sin embargo esto genera algunos inconvenientes como se describieron aquí ya que pip es solo un instalador de paquetes y virtualenv un aislador, pero realmente aquí no se tiene un gestor de paquetes, al no tenerlo en mi caso un problema común que me sucedía al utilizar sólo estas dos herramientas se presenta a continuación:

Instalo cualquier librería, la mayoría de librerías tienen dependencias de otras librerías por lo tanto al instalar se instalan sus dependencias, por ejemplo utilizare flask

pip install flask

Al ejecutar este comando me instala además de flask sus dependencias

click==7.1.2
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
Werkzeug==1.0.1

El problema viene cuando deseo desinstalar flask

pip uninstall flask
click==7.1.2
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
Werkzeug==1.0.1

Lo pueden notar? no se desinstalaron las dependencias que tenía flask, y esto a largo plazo puede hacer que nuestro archivo requirements.txt se llene de basura o de dependencias no deseadas

Beneficios

Poetry al final del dia internamente usa virtualenv y pip, lo importante aquí es la capa de abstracción que crea incluyendo su CLI que pone a nuestra disposición para mejorar la productividad y evitar problemas a futuro sobre todo en producción, a continuación mencionaré los principales beneficios de poetry

  • Dependencias de desarrollo utilizando solamente pip para lograr tener dependencias de desarrollo y de producción toca dar un montón de vueltas y se debe gestionar todo de manera manual, con poetry utilizamos solamente el siguiente comando
poetry add pdbpp -D

Nuestro archivo  de configuración de poetry se veria asi

[tool.poetry]
name = "src"
version = "0.1.0"
description = ""
authors = ["jairo <me@jairoandres.com>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]
pytest = "^5.2"
pdbpp = "^0.10.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

observamos que las dependencias se agregan a [tool.poetry.dev-dependencies] ahora cuando el proyecto se mueve de maquina que es uno de los mayores sustos estas dependencias se pueden ignorar sencillamente con el comando

poetry install --no-dev

este comando solo instalará dependencias de producción

  • Gestión de los entornos virtuales a veces trabajar con los virtualenvs puede ser un poco tedioso y más si tenemos diferentes entornos con diferentes versiones llenamos carpetas con entornos o incluso se ensucia el proyecto con carpetas de entornos, con poetry se puede gestionar varios entornos utilizando el comando
poetry env list

Este comando retorna los entornos que se han generado utilizando poetry

src-RXqvWCCk-py3.7
src-RXqvWCCk-py3.8
src-RXqvWCCk-py3.9 (Activated)

En mi caso tengo tres entornos utilizando diferentes versiones generados (ejemplo poetry env use python3.8) se puede cambiar de manera sencilla, gestionar y agregar uno nuevo en la carpeta predefinida  por poetry

  • Remover paquetes y sus dependencias anteriormente mencione que este es uno de los inconvenientes que sucede constantemente y que son difíciles de gestionar  por lo tanto requieren más trabajo del que debería dedicarse, en poetry por ejemplo se tiene el archivo de configuración
[tool.poetry]
name = "src"
version = "0.1.0"
description = ""
authors = ["jairoufps <jairoandrescp@ufps.edu.co>"]

[tool.poetry.dependencies]
python = "^3.7"
Flask = "^1.1.2"

[tool.poetry.dev-dependencies]
pytest = "^5.2"
pdbpp = "^0.10.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

En este caso agregue flask y se puede apreciar que aquí no se tienen agregadas las dependencias de la librería, estas se agregan al archivo poetry.lock pero es transparente para el desarrollador, por lo tanto al remover un paquete como flask se remueven sus dependencias de manera automática como se ve en la Figura 5 genial!

poetry remove flask
Figura 5 Proceso de remover automáticamente las dependencias de una librería
  • Empaquetamiento de código realizar el empaquetamiento de código solamente con pip como una librería requiere de varios pasos, en poetry solamente se debe agregar el folder en el cual se va instalar como librería, agregando la siguiente línea a nuestro archivo de configuración
packages = [{include="src"}]

agregue el folder src por que ahi es donde se encuentra el código que deseo instalar, luego de  ello ejecuto el siguiente comando para instalarla como librería del sistema

poetry install

ahora en este caso ya se puede llamar al código como una librería cualquiera instalada como en el siguiente ejemplo

from src.myproject import Myproject

project_one = Myproject()

Estos beneficios descritos presentan a poetry como una herramienta totalmente alineada con la cultura pythonica, enfocar al desarrollador en lo realmente importante permitiéndole llegar a producción con la menor cantidad de problemas posibles relacionado con las dependencias

Conclusión

Al final del día como desarrolladores es conveniente tener aplicaciones que nos faciliten los ciclos y las entregas, es casi común encontrarnos el en mi maquina  funciona o que raro? por este motivo herramientas como poetry nos ayudan a que las dependencias se gestionen de la mejor manera (tanto en entornos dev como prod) , darle una oportunidad en un nuevo proyecto es una gran idea para explotar los beneficios que ofrece poetry