18 octubre 2014

Entornos virtuales para desarrollos reales, jugando con virtualenv

No se en vuestro caso, pero yo suelo desarrollar varios proyectos al mismo tiempo. El problema es que aveces necesitas librerías para un proyecto que entran en conflicto con las de otro. Por eso eso es por lo que virtualenv existe en Python.

Gracias a virtualenv puedes mantener todas las versiones de python, librerías, paquetes y dependencias de un projecto aisladas de las de otro. Virtualenv hace esto creando para tu proyecto una copia de python aislada y separada de las del resto de tus proyectos. Esto es especialmente útil también si tienes que desarrollar e instalar librerías de python en un sistema linux para que el que no tienes permisos de root/sudo con los que instalar cosas a nivel de sistema operativo.

Usar virtualenv como parte habitual de tus herramientas de desarrollo te ahorrará quebraderos de cabeza futuros.

El primer paso a la hora de usar virtualenv es asegurarse de qué versión de python vamos a usar para nuestro proyecto. La herramienta virtualenv original no funciona correctamente en Python 3, por lo que si quieres usarlo te tendrás que ceñir a Python 2.7. Afortunadamente, desde su versión 3.3, Python incluye su propia versión de virtualenv con el nombre de venv. La pega es que la versión de venv que viene con Python 3.3 no soporta el uso de pip dentro del entorno virtual, aunque afortunadamente dicho soporte de añadió en Python 3.4. Vamos a cubrir ambos en este artículo: primero virtualenv y luego venv.

Se puede instalar virtualenv usando el gestor de paquetes nativo del sistema operativo o el gestor de paquetes pip de python. En Ubuntu, usando el gestor de paquetes del sistema sería:
dante@Camelot:~$ sudo aptitude install python-virtualenv

Usando pip bastaría con:
dante@Camelot:~$ pip install virtualenv

Se puede conprobar qué versión se ha instalado con:
dante@Camelot:~$ virtualenv --version

Para usarlo, sólo que hay que ir con la consola al directorio de tu proyecto y ejecutar el comando siguiente:
dante@Camelot:~/project-directory$ virtualenv --no-site-packages env
New python executable in env/bin/python Installing setuptools, pip...done. dante@Camelot:~/project-directory$

Ese comando creará un direcotio llamado venv donde se pondrán los ejecutables necesarios para ejecutar el entorno virtual. La opción --no-site-packages aisla del todo tu entorno de trabajo del resto del sistema al no incluir en él los paquetes y módulos ya instalados en el sistema. De esa manera, se puede tener un entorno aislado, libre de cualquier paquete previamente instalado.

Antes de empezar a trabajar hay que arrancar el entorno virtual ejecutando el script de activación:
dante@Camelot:~/project-directory$ source env/bin/activate (env)dante@Camelot:~/project-directory$

Se puede saber que se está trabajando en un entorno virtual gracias a que aparece el nombre del directorio del entorno, rodeado por paréntesis, a la izquierda de la ruta en la línea de comandos. Mientras permanezcas en el entorno virtual, todos los paquetes que instales con pip serán almacenados en la instancia virtual de python dejando tranquilo al python de tu sistema operativo.

Para salir del entorno virtual sólo hay que teclear deactivate:
(env)dante@Camelot:~/project-directory$ deactivate dante@Camelot:~/project-directory$

Deberías crear un entorno virtual cada vez que comiences un nuevo proyecto.

Usar venv en Python 3.4 no es tan diferente. Sin embargo, hay que tener en cuenta que Ubuntu 14.04 viene con una versión estropeada de venv. Si intentases crear un entorno virtual con venv en Ubuntu 14.04, nos saldría un error como este:
dante@Camelot:~/project-directory2$ pyvenv-3.4 env Error: Command '['/home/dante/project-directory2/env/bin/python3.4', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1 dante@Camelot:~/project-directory2$

La única manera que que he encontrado de solucionar este problema es actualizar Ubuntu a la versión 14.10:
dante@Camelot:~/project-directory2$ sudo do-release-upgrade -d

El sistema tardará unas cuantas horas en actualizarse a la versión 14.10. En ese punto puede ser que haya que instalar venv a través del gestor de paquetes:
dante@Camelot:~/project-directory2$ cat /etc/issue Ubuntu 14.10 \n \l dante@Camelot:~/project-directory2$ pyvenv-3.4 env El programa «pyvenv-3.4» no está instalado. Puede instalarlo escribiendo: sudo apt-get install python3.4-venv dante@Camelot:~/project-directory2$ sudo aptitude install python3.4-venv Se instalarán los siguiente paquetes NUEVOS: python3.4-venv 0 paquetes actualizados, 1 nuevos instalados, 0 para eliminar y 0 sin actualizar. Necesito descargar 1.438 kB de archivos. Después de desempaquetar se usarán 1.603 kB. Des: 1 http://es.archive.ubuntu.com/ubuntu/ utopic/universe python3.4-venv amd64 3.4.2-1 [1.438 kB] Descargados 1.438 kB en 0seg. (1.717 kB/s) Seleccionando el paquete python3.4-venv previamente no seleccionado. (Leyendo la base de datos ... 237114 ficheros o directorios instalados actualmente.) Preparing to unpack .../python3.4-venv_3.4.2-1_amd64.deb ... Unpacking python3.4-venv (3.4.2-1) ... Processing triggers for man-db (2.7.0.2-2) ... Configurando python3.4-venv (3.4.2-1) ... dante@Camelot:~/project-directory2$ pyvenv-3.4 env

De esa manera venv se ejecutaría sin errores:
dante@Camelot:~/project-directory2$ source env/bin/activate (env)dante@Camelot:~/project-directory2$

Una vez en tu entorno virtual puedes instalar todos lo paquetes que necesites para tu desarrollo usando pip, y sin ensuciar las librerías de tu sistema operativo. Las distribuciones modernas de Linix hacen un uso intensivo de aplicaciones de python. Por eso es una buena práctica mantener limpias las librerías de python del sistema operativo, con sólo lo que realmente necesite tu linux, y cacharrear con las librerías específicas de tus desarrollos a través de sus respectivos entornos virtuales. Por ejemplo, podrías usar un entorno virtual si necesitases desarrollar en Python 3 en un sistema operativo cuyo intérprete de python por defecto fuese de la versión 2.7:
dante@Camelot:~/project-directory2$ source env/bin/activate (env) dante@Camelot:~/project-directory2$ python Python 3.4.2 (default, Oct 8 2014, 13:08:17) [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> exit() (env) dante@Camelot:~/project-directory2$ deactivate dante@Camelot:~/project-directory2$ python Python 2.7.8 (default, Oct 8 2014, 06:57:53) [GCC 4.9.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>

No te cortes con los entornos virtuales. Puedes usarlos en entornos de producción, de hecho son lo que se recomienda en realidad para situaciones de producción, en las que no quieres que una actualización de las librerías del sistema operativo rompa las dependencias de una aplicación desarrollada y en funcionamiento.