Blog ElCodiguero
30 dic 2010 Python

Sitios web con Python, virtualenv y fastcgi

A la hora de crear un sitio web con Python, la opción más sencilla es usar un framework y algunas de las muchas aplicaciones y bibliotecas ya disponibles. Pero ¿qué sucede si usamos una biblioteca que no está disponible en la cuenta de alojamiento que contratamos?

virtualenv

La respuesta a esta pregunta es virtualenv. Se trata de un paquete que permite instalar otros paquetes y bibliotecas en un directorio cualquiera, sin depender de la carpeta global de Python o heredando los paquetes instalados en ella.

En mi cuenta de Valcato tuve que utilizar virtualenv para instalar django-cms y el blog Zinnia, ya que no estaban entre los paquetes disponibles.

En mi caso, virtualenv no estaba instalado en la carpeta global, pero esto no es un problema: basta con descargar el archivo .zip y descomprimirlo en una carpeta cualquiera del servidor. Luego simplemente ejecutando python virtualenv.py funciona perfectamente.

Crear el entorno virtual

Para crear el entorno virtual, debemos conectarnos a la cuenta de alojamiento vía SSH, usando PuTTY o un programa similar. Esto es necesario porque se requiere ejecutar comandos. Una vez conectados y en la línea de comandos del servidor, basta con ejecutar el comando virtualenv con un parámetro que indica el nombre de la carpeta en la que se copiarán los archivos necesarios:

# virtualenv mi_entorno_virtual

Para evitar problemas, conviene tener dos puntos en consideración:

  1. El entorno virtual no puede ser cambiado de directorio, por lo que hay que crearlo en la carpeta desde donde vaya a funcionar siempre.
  2. Existe una opción —no-site-packages que desvincula completamente al entorno virtual de la carpeta global. Ideal si queremos evitar cualquier clase de conflicto.

Activar el entorno

Luego de crearlo, y antes de poder utilizarlo, hay que activar el entorno virtual recién creado. Esto hace que las siguientes llamadas a python o a programas hechos en python encuentren las carpetas del entorno virtual y sea posible instalar paquetes allí. La activación requiere otro comando simple:

# . mi_entorno_virtual/bin/activate

Es importante ejecutar el comando anterior tal cual se muestra, incluyendo el punto inicial (el # es simplemente una forma genérica de representar el indicador de la línea de comandos o prompt). Obviamente cambia el nombre de la carpeta donde el entorno virtual fue creado. Lo importante es que luego de esto, las llamadas a python ejecutarán mi_entorno_virtual/bin/python, y mi_entorno_virtual/lib/python/site-packages estará en sys.path (de forma simple: lo que esté en mi_entorno_virtual tendrá precedencia sobre lo que esté en la carpeta global de Python en el sistema)

Instalando programas y bibliotecas

Una vez activado el entorno virtual, se dispone de los comandos pip y easy_install para instalar paquetes de python en él, sin afectar lo que esté instalado en el directorio global. En mi caso necesitaba instalar django-blog-zinnia, así que simplemente usé la siguiente orden:

# pip install django-blog-zinnia

pip no solamente instala el paquete indicado sino que instala también sus dependencias, por lo que una vez finalizada su tarea ya queda todo listo para usar.

Modificando la configuración de FastCGI

Para poder usar el entorno virtual desde la línea de comandos, se requiere ejecutar el programa bin/activate, pero FastCGI no tiene una línea de comandos. Entonces ¿cómo indicarle que utilice los paquetes allí instalados? La respuesta está en la biblioteca estándar de Python, y es el módulo site.

site.addsitedir

El método addsitedir del módulo site sirve para lo que necesitamos: agregar una nueva carpeta al entorno de ejecución de Python para que sea considerada como otra site-packages.

Si ya estás usando Django con FastCGI, seguramente tengas un archivo con extensión .fcgi y con contenido similar a lo siguiente:

1 #!/usr/bin/env python2.6
2 import sys, os
3 
4 sys.path.insert(1, "/ruta/a/tu/proyecto/django")
5 os.environ['DJANGO_SETTINGS_MODULE'] = "proyecto.settings"
6 
7 from django.core.servers.fastcgi import runfastcgi
8 runfastcgi(method="threaded", daemonize="false")

Entonces, para que FastCGI encuentre y use los paquetes instalados en el entorno virtual, se importa el módulo y se invoca a addsitedir antes de hacer el sys.path.insert:

import site
site.addsitedir('/ruta/al/entorno/virtual/lib/python2.6/site-packages')

Conflictos con el site-packages global

Si no hay conflictos de paquetes entre el directorio global y el entorno virtual, lo anterior es suficiente para que todo funcione correctamente. Sin embargo, en caso de conflictos pueden surgir problemas. Esto es porque addsitedir agrega los directorios del entorno virtual después de los directorios globales en sys.path, y sin un orden predefinido. Si tu archivo .fcgi utiliza addsitedir y un día de repente algo no funciona, o funciona mal, podría ser producto de un conflicto de versiones del mismo paquete entre el entorno virtual y el entorno global del servidor.

El problema está más detallado en el sitio de mod_wsgi. La solución es básicamente reordenar sys.path para que los directorios agregados por addsitedir aparezcan primero. El resultado final en el archivo de FastCGI es algo como esto:

 1 #!/usr/bin/env python2.6
 2 import sys, os, site
 3 
 4 # Remember original sys.path.
 5 prev_sys_path = sys.path[:]
 6 
 7 # Add each new site-packages directory.
 8 site.addsitedir('/ruta_al_entorno_virtual/elcodiguero-env/lib/python2.6/site-packages')
 9 
10 # Reorder sys.path so new directories at the front.
11 new_sys_path = []
12 for item in sys.path:
13     if item not in prev_sys_path:
14         new_sys_path.append(item)
15         sys.path.remove(item)
16 sys.path[:0] = new_sys_path
17 
18 sys.path.insert(1, "/ruta_al/proyecto_django/")
19 os.environ['DJANGO_SETTINGS_MODULE'] = "proyecto.settings"
20 
21 from django.core.servers.fastcgi import runfastcgi
22 runfastcgi(method="threaded", daemonize="false")

Una vez cumplidos estos pasos, nuestro sitio Django tendrá disponibles todos los paquetes que queramos instalar en el entorno virtual.

Activa Javascript para para cargar los comentarios, basados en DISQUS

El Blog de ElCodiguero funciona sobre Pelican

Inicio | Blog | Acerca de