Una forma sencilla de gestionar las dependencias en tu proyecto.
En la entrada anterior, realizamos la instalación de Poetry, definimos la configuración para nuestro proyecto, así como las depedencias principales, de desarrollo, y las opcionales.
Teniendo el archivo pyproject.toml, podemos integrar en el mismo, diferentes configuraciones, para diversas herramientas, a continuación, algunas de ellas.
Configuración para Black
Black es un formateador que cumple con PEP 8 y tiene su propio estilo. Hace que la revisión del código sea más rápida, al producir las menores diferencias posibles. El código tendrá el mismo aspecto independientemente del proyecto que estés leyendo.
Podemos utilizar nuestro archivo pyproject.toml, para agregar la configuración de Black.
Ejemplo:
# definimos la seccion apropiada
[tool.black]
line-length = 120
target-version = ['py39']
required-version = "21.10b0"
# fix this
# skip-string-normalization = true
exclude = '''
^/(
(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.idea
| \.vscode
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| \.env
| venv
| env
| test
| _build
| buck-out
| build
| dist
| tools
)/
| foo.py
)
'''
Configuración para isort
isort es una utilidad/biblioteca de Python para ordenar las importaciones alfabéticamente, y automáticamente separadas en secciones y por tipo. Requiere Python 3.6+.
Podemos utilizar nuestro archivo pyproject.toml, para agregar la configuración de isort.
Ejemplo:
# definimos la seccion apropiada
[tool.isort]
py_version = 39
profile = "black"
# multi_line_output = 0
line_length = 120
lines_between_sections = 0
include_trailing_comma = true
ensure_newline_before_comments = true
Configuración para Bandit
Bandit es una herramienta diseñada para encontrar problemas de seguridad comunes en el código de Python. Para ello, Bandit procesa cada archivo, construye un AST a partir de él, y ejecuta los plugins apropiados contra los nodos del AST. Una vez que Bandit ha terminado de escanear todos los archivos, genera un informe.
Podemos utilizar nuestro archivo pyproject.toml, para agregar la configuración de Bandit.
Ejemplo:
# definimos la seccion apropiada
[tool.bandit]
# tests = ["B201", "B301"]
# skips = ["B101", "B601"]
skips = ["B105"]
Scripting con Poetry
En muchos proyectos de Python, es común utilizar la línea de comandos para generar crud`s (scaffold), formatear el codigo, generar la documentación, hacer un despliegue en una plataforma cloud etc...
Poetry nos ayuda en estas labores con una sección llamada tool.poetry.scripts
Para este ejemplo tenemos una carpeta llamada tools, pero puede llamarse como quieras, en ella podemos tener varios archivos de código Python que ejecutan diversas tareas, la estructura actual de nuestro proyecto se ve así:
awesome-project
├── main.py
├── pyproject.toml
└── tools
└── scripts.py
Agregamos las entradas para nuestros scripts, al archivo pyproject.toml.
Ejemplo:
[tool.poetry]
# la llave "packages" permite a Poetry encontrar
# nuestra carpeta "tools" y los scripts que contenga.
packages = [
{ include="tools", from="." },
]
[tool.poetry.scripts]
fmt = "tools.scripts:format"
sort = "tools.scripts:sort"
audit = "tools.scripts:audit"
test = "tools.scripts:test"
Para invocar a un script, se debe seguir el formato: "carpeta.archivo:funcion"
Ejemplo:
fmt = "tools.scripts:format"
Nuestro archivo scripts.py luce de la siguiente manera:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
import sys
def test():
print("hola mundo desde Poetry")
print("esto es un script de ejemplo.")
print()
def format():
try:
cmd = ["black", "main.py"]
subprocess.run(cmd)
except KeyboardInterrupt as e:
print("> Command killed by keyboard interrupt...")
except Exception as e:
print(e.output)
sys.exit(1)
def sort():
try:
cmd = ["isort", "--profile", "black", "--atomic", "."]
subprocess.run(cmd)
except KeyboardInterrupt as e:
print("> Command killed by keyboard interrupt...")
except Exception as e:
print(e.output)
sys.exit(1)
def audit():
try:
cmd = ["bandit", "-r", "main.py"]
subprocess.run(cmd)
except KeyboardInterrupt as e:
print("> Command killed by keyboard interrupt...")
except Exception as e:
print(e.output)
sys.exit(1)
Las funciones "format", "sort" y "audit", hacen uso del modulo subprocess de Python para ejecutar los comandos black, isort y bandit con variedad parámetros, para cada herramienta respectivamente.
En este punto, llevamos lo siguiente:
- Configuración para herramientas de terceros en tu proyecto (black, isort, etc...).
- Scripting para ampliar las necesidades de tu proyecto.
Recuerda que actualmente (Poetry 1.x) no es posible ejecutar librerías o herramientas directamente desde la configuración de scripts.
Ejemplo:
[tool.poetry.scripts]
# esto genera un error al ejecutarse
serve = "flask run"
Si se intenta ejecutar el comando:
❯ poetry run serve
Generará un error.
En el caso de querer lanzar un servidor local, como gunicorn o flask, basta con crear un script como los vistos anteriormente.
-- un visitante del blog
...Ó seguir leyendo 👇
Ejecutar scripts desde Poetry
Para hacer uso de los scripts creados con anterioridad, escribimos lo siguiente:
❯ poetry run [script]
Ejemplo:
# Ejecutar el script fmt (black)
❯ poetry run fmt
# Ejecutar el script sort (isort)
❯ poetry run sort
# Ejecutar el script audit (bandit)
❯ poetry run audit
# Ejecutar el script test (hola mundo)
❯ poetry run test
Podemos naturalmente ejecutar estas herramientas ó librerías que instales en tu proyecto, directamente, haciendo uso de Poetry:
❯ poetry run [librería/herramienta] [lista de parámetros]
Ejemplo:
# Ejecutar Black directamente.
❯ poetry run black main.py
# Ejecutar isort directamente
❯ poetry run isort --profile black --atomic .
# Ejecutar bandit directamente.
❯ poetry run bandit .
# Ejecutar Flask directamente.
❯ poetry run flask run
Diseñar scripts para ejecutar con Poetry, al menos en un inicio, puede que no sea la mejor solución, pero cuando tengas muchas cosas por hacer, después de programar tu proyecto, verás la utilidad y potencia que ofrece, entre otras cosas:
- Formatear el código (black).
- Ordenar las importaciones de los modulos de tu proyecto (isort).
- Comprobar el estilo y la calidad de tu código python (flake8).
- lanzar el servidor de pruebas (flask run, gunicorn etc...).
- Encontrar problemas de seguridad (bandit).
- Generar la documentación. 😄
- Realizar despliegues de tu proyecto en gcp, aws, azure, heroku etc...
- Generadores de codigo base (scaffold) para tu proyecto, ej: crud's básicos.
Sí conoces nodeJS, los scripts en Poetry son el equivalente a npm scripts
En resumen, el archivo pyproject.toml es mágico, pero... algunos sistemas y plataformas (heroku, gcp etc...) aún siguen dependendiendo del archivo 'requirements.txt' ¿en ese caso que debería hacer?
-- un visitante del blog
Leer la siguiente sección 👇 de este artículo. 😄
Poetry y el archivo requirements.txt
Para el caso en que necesites el archivo requirements.txt, Poetry provee un comando para generarlo a partir de la sección tool.poetry.dependencies del archivo pyproject.toml.
Ejemplo:
# Generar el archivo requirements.txt
❯ poetry export -f requirements.txt --output requirements.txt --without-hashes
# ó de la forma
❯ poetry export -f requirements.txt --output requirements.txt
Una vez generado, te recomendamos, que no lo modifiques directamente, si agregaste librerías, las actualizaste ó las eliminaste de tu proyecto, utiliza:
❯ poetry install
# ó
❯ poetry update
para actualizar la lista de dependencias y luego, volver a generar el archivo.
En la próxima entrada, hablaremos sobre el uso de plugins, y librerías de utilidad y otras hierbas.