Añadir dependencia editable con Poetry

Desarrollo en local de una librería

En este post veremos como añadir una dependencia editable con Poetry para facilitar el desarrollo en local de una librería.

Con Poetry (en realidad con pip), es posible añadir una dependencia editable (también conocido como develop mode) con lo que podremos trabajar en local modificando directamente el código de la dependencia y ver actualizados los cambios en nuestra aplicación.

Para nuestro ejemplo, crearemos 2 proyectos: MyProject y MyLibrary.

poetry new --src MyProject
poetry new --src MyLibrary

En MyLibrary añadiremos el paquete cowsay.

En MyLibrary/src/mylibrary/__init__.py escribimos el siguiente código:

import cowsay


class Greeter:
    @staticmethod
    def greeter(name: str) -> None:
        cowsay.cow(name)


if __name__ == '__main__':
    Greeter.greeter("I'm a cow")

A continuación, añadiremos MyLibrary como dependencia editable a MyProject:

poetry add --editable ..\MyLibrary\

Que se traduce en pyproject.toml de MyProject como:

mylibrary = {path = "../MyLibrary", develop = true}

Fíjate que al instalar MyLibrary en MyProject, también se instaló cowsay en el entorno virtual de MyProject.

Ahora simplemente podemos importar nuestra librería y usarla tal y como estamos acostumbrados con cualquier otra dependencia:

# MyProject/src/myproject/__init__.py
from mylibrary import Greeter

if __name__ == '__main__':
    Greeter.greeter("panicoenlaxbox")

Pero no sólo eso (en realidad si sólo fuera eso y no quisiéramos editar la librería hubiera bastado con poetry add ..\MyLibrary\ ), ahora podemos editar desde MyProject el código de MyLibrary y el cambio estará sincronizado porque estamos atacando al mismo fichero. Esto es así, porque si vamos a la carpeta site-packages del entorno virtual de MyProject veremos que en la carpeta mylibrary-0.1.0.dist-info existe un fichero llamado direct_url.json:

{"url": "file:///<PATH_TO_MY_LIBRARY>", "dir_info": {"editable": true}}

Algo a tener en cuenta es que si añadimos dependencias a MyLibrary (o cambiamos alguna existente) no se verán reflejadas en MyProject por lo que tocará desinstalar y volver a instalar el paquete.

Para verlo con un ejemplo podemos añadir colored a MyLibrary:

import cowsay
from colored import Fore, Back, Style


class Greeter:
    @staticmethod
    def greeter(name):
        cowsay.cow(name)
        print(f'{Fore.white}{Back.green}name!!!{Style.reset}')

Si volvemos a ejecutar ahora MyProject dará un error porque no encuentra colored. Así que toca desinstalar (poetry remove mylibrary) y volver a instalar (poetry add --editable ..\MyLibrary\) MyLibrary en MyProject.

Este flujo de trabajo implica (y eso es carne de otro post) que cuando vayamos a producción habría que reemplazar la dependencia a MyLibrary por una dependencia real, es decir, algo como PyPI o un feed interno donde estés publicando tus paquetes.

Un saludo!


Ver también