El irónico estado de la gestión de dependencias en Python (II)

11 de diciembre de 2023

Los mundos virtuales de Python

Supongamos que ya tenemos el intérprete adecuado funcionando. Ahora toca instalar las dependencias del proyecto. Una de ellas es la librería tech.py versión 2.0. Dado que es un sistema que aloja varios proyectos, da la casualidad de que Python ya posee ese paquete instalado porque otro proyecto hace uso de dicha librería.

Pero hay un problema. La librería que está instalada es la versión 1.2 de tech.py y nuestro proyecto usa muchas funciones y clases definidas en la versión 2.0. Aunque forzáramos la instalación, al ejecutar el proyecto daría error. ¿Qué hacemos? Porque intérprete Python solo tenemos uno con esa versión.

El propio proyecto Python trató de dar una solución a este problema en el pep-582. Aspiraba a compartir intérprete pero a la vez, hacer que las librerías de cada proyecto sean independientes una de otras metiéndolas en una carpeta: __pypackages__ local al proyecto.

De este modo, no habría colisión y el mismo intérprete usaría unas librerías u otras cuando se arrancase desde un proyecto diferente. Una buena idea...que terminó siendo rechazada por el propio comité.

¿Cómo hacemos para tener múltiples proyectos y separar sus dependencias para que no se estorben unos a otros?

La solución está en tener una copia del intérprete, sus librerías y binarios asociados y cambiar las rutas que apuntan al binario python. Es decir, duplicar el entorno y aislarlo del exterior haciendo "creer" a la shell que Python está instalado en un ruta diferente y alterna a la instalación del sistema (e incluso a la de pyenv). Es lo que se denomina, sin mucho más misterio: entorno virtual.

Y es que lo que hace una herramienta o librería de administración de entornos virtuales es exactamente eso: copiar o enlazar un mismo ejecutable y proveer de un entorno de librerías asociadas, toda vez que se manipulan las variables de entorno adecuadas para activarlo.

Ahora, cuando instalemos paquetes Python o las dependencias de un proyecto quedarán aisladas a dicho entorno virtual, sin afectar en absoluto a cualquier otro. Esto resuelve el problema que genera disponer de un intérprete que da servicio a múltiples proyectos.

¿Cómo lo usamos? Disponemos de varias opciones, la más directa es utilizando el propio módulo venv que traen todas las distribuciones Python a partir de la versión 3.3 (por cierto, su respectivo pep está aquí).

Tan fácil como hacer:

Eso nos crea un entorno llamado 'mientornovirtual' en el mismo directorio del proyecto.

No obstante, debemos activarlo antes de trabajar con él de un modo parecido a como activamos las versiones de Python con pyenv:

A partir de ahí, todo lo que hagamos será sobre el entorno que está en dicha carpeta.

Cuando terminemos de trabajar, tan solo tenemos que desactivarlo para volver al intérprete original:

¿Alternativas al manejo de entornos virtuales?

Tenemos el proyecto que originó la creación de entornos virtuales en Python, virtualenv. De hecho, es la herramienta que ha de ser usada en vez del módulo (que usaríamos solo en caso de no disponer de virtualenv). El uso es exactamente igual solo que invocaríamos a virtualenv en vez del módulo.

Bonus si usas pyenv

En caso de que estés usando pyenv para instalar y activar intérpretes, existe un plugin para pyenv que nos permite administrar entornos virtuales.

Con dicho plugin todo queda integrado en una sola herramienta: instalación y selección del intérprete y además la creación y gestión de entornos virtuales.

Otra ventaja al respecto es que no crea una carpeta en el proyecto, sino en un directorio a modo de caché de entornos virtuales con lo que en proyectos que consideremos comunes (que no tienen problemas de dependencias) podemos reutilizar los entornos ya creados solo con su nombre.

Además. Si en el archivo .python-version indicamos el nombre del entorno virtual, al entrar en el directorio del proyecto se activará automágicamente. El no va más.

¿Estamos seguros de que ya disponemos de todo lo que nos da la tecnología para tener un entorno Python reproducible?

Pues, no. Aún queda un "pequeño" detalle que veremos en la siguiente entrega.

—MÁS PARTES DE ESTA SERIE

El irónico estado de la gestión de dependencias en Python (I)
El irónico estado de la gestión de dependencias en Python (III)