2011-12-28

Python 101: Primeros pasos con ActivePython (Parte 1)

Durante varios años había trabajado con la distribución oficial de Python para Windows sin ningún problema. A pesar de ello, a comienzos del año pasado -aprovechando un cambio de ordenador-, se me ocurrió probar la Community Edition de ActivePython, que distribuye la empresa canadiense ActiveState; todo esto con el objetivo de trabajar simultáneamente con las versiones 2.x y 3.x del lenguaje.

Hoy, luego de más de un año de trabajo diario con ActivePython en Windows, RHEL5 y Mac OS X; no sólo confieso que estoy totalmente satisfecho con dicha distribución, sino que además, me encuentro a la espera de comenzar a probar Stackato, el producto de cloud computing de ActiveState.

En esta chuleta se detallan los pasos que sigo, para instalar ActivePython en mis ordenadores.

Paso 1: Consideraciones previas

Lo primero es aclarar exactamente ¿qué vamos a instalar en cada ordenador?. En efecto, la razón por la que comencé a utilizar ActivePython (al principio, conviviendo con la versión 2.6 de la distribución oficial), era la necesidad de tener múltiples versiones de Python en mi portátil1.

Así, vamos a comenzar enumerando lo que queremos instalar en cada ordenador:

  • En mi portátil con Windows (utilizado en casa y en el trabajo)

    Se trata de instalar:

    • ActivePython 2.7, como distribución de trabajo diario; y
    • ActivePython 3.2, para realizar pruebas de compatibilidad con Python 3.
  • En mis servidores con RHEL5 (usados sólo en el trabajo)

    Aquí instalaremos únicamente la versión:

    • ActivePython 2.7 (exactamente la misma versión que tengo en mi portátil), para desplegar en producción los servicios que desarrollo.
  • En mi MacBook Air (utilizado sólo en casa)

    Aunque Mac OS X también viene con su propia versión de Python, se trata de tener la misma distribución en casa que en el trabajo, por lo que la versión de Apple no la he utilizado nunca, sino más bien:

    • ActivePython 2.7 (idéntica versión que en los casos anteriores), para los momentos en los que necesitas probar las últimas 10 líneas de código que se te ocurrieron mientras dormías la siesta.

Aclarado lo anterior, podemos hacer un poco de historia con miras a justificar un poco estos requisitos de instalación, o pasar directamente a la instalación de ActivePython sobre Windows; ya que las instalaciones sobre RHEL5 y Mac OS X son triviales, y se dejan para la segunda parte de esta chuleta.

Un poco de historia (opcional)

Advertencia: “Si no necesita una justificación para instalar ActivePython; esta sección puede matarlo de aburrimiento”.

Para entender el por qué probar una distribución no oficial de Python, tengo que hacer un poco de historia para ponerlo todo en contexto.

En octubre del 2008, cuando la PSF liberó la versión 2.6 de la distribución oficial de Python; el Google App Engine estaba dando sus primeros pasos, ejecutándose sobre la versión 2.5 del intérprete. Esto obligó a algunos de nosotros a quedarnos en la versión 2.5, durante más tiempo del que estábamos acostumbrados a esperar (al menos mientras jugábamos con GAE).

Las cosas fueron complicándose a medida que añadíamos más “constantes” a nuestra ecuación. En aquel entonces también me tocó trabajar simultáneamente con varios servidores RHEL5 (esta distro incluye sólo la versión 2.4 de Python) y mantener nuestra distribución oficial de Python 2.5 dentro de los portátiles con Windows XP (mientras rodaban por allí las versiones 2.6 y 3.0). Por lo que ya estábamos nadando entre cuatro (4) versiones de Python.

Todo esto, fue motivo suficiente para intentar instalar múltiples versiones de Python en mi portátil (y quizás, complementar la distro de mis servidores con una versión estable -pero un tanto más actualizada- del lenguaje, lo cual excluía por supuesto a Python 3.0).

Pero, ¿qué tiene esto de complicado?

La instalación de dos versiones diferentes de las distribuciones oficiales de Python (la versión 2.5 y la 2.6), por alguna razón que todavía desconozco, no me funcionaba del todo bien en Windows.

Mi problema era similar al que describía años atrás Ned Batchelder, en el artículo titulado “Multiple python installations on Windows”; en el que Trent Mick comentaba que era posible instalar múltiples versiones de ActivePython, incluso conviviendo con una versión de la distribución oficial.

A partir de dicho comentario, la instalación de Python dentro de mi portátil incluía las siguientes versiones:

  • Una instalación de la versión 2.5 de ActivePython, para trabajar^Wjugar sólo con Google App Engine, y
  • Una instalación de la versión 2.6 de la distribución oficial de Python, para realizar mi trabajo diario.

Todo esto, manteniendo en mis servidores la versión 2.4, que Red Hat distribuía de serie.

Un año después, en octubre del 2009, ActiveState anunciaba el lanzamiento de su gestor de paquetes binarios2: PyPM, a la vez que instaba a probar las versiones 3.x de ActivePython, que podían ser instaladas simultáneamente, junto a las versiones 2.5 y 2.6 más estables.

A pesar de esto, mi desconocimiento acerca de la compatibilidad de ActivePython con las librerías de terceras partes, que se distribuían en forma binaria3 para la distribución oficial de Python en Windows (e.g. numpy, lxml, cx_Oracle, entre otras); me hizo mantener el esquema de instalación anterior durante cierto tiempo.

Lo que mal empieza, no siempre mal termina

En enero del 2011, ya me había aburrido de jugar con GAE, y aprovechando el cambio de mi portátil (mas no de sistema operativo), se me ocurrió probar con un esquema de instalación diferente:

  • Instalar las distribuciones de ActivePython disponibles para las versiones 2.7 y 3.2 (a partir de febrero) del lenguaje, dejando a un lado la distribución oficial.

  • Seguir usando la versión 2.7 como herramienta de trabajo, hasta que todas las librerías que necesito estén disponibles en el repositorio comunitario de la versión 3.2 (o superior).

  • Utilizar el gestor de paquetes de ActiveState (PyPM) para la instalación de los paquetes que necesite, cuando estos estén disponibles en el repositorio de ActiveState; todo esto complementado con PyPI a través de pip, que sería utilizado como gestor de paquetes fuente, y que funciona en ActivePython, recién salido de la caja.

  • Hacer uso de las distribuciones binarias de las librerías de terceras partes, que sean compatibles con la versión 2.7 de distribución oficial de Python, siempre que éstas se instalen vía programa de instalación (para eliminarlas con facilidad, cuando estén disponibles en PyPM, o haya que actualizarlas).

  • Probar la compatibilidad de mi código con la versión del lenguaje Python 3, utilizando la versión 3.2 de ActivePython y sólo aquellas dependencias disponibles en su repositorio de ActiveState; omitiendo la comprobación de compatibilidad de mi código, cuando éste dependa de otros paquetes de terceras partes, que no estén disponibles en dichos repositorios.

Aunque en principio me dio un poco de repelús pasar completamente de la distribución oficial de Python; doce meses después confieso que es fácil aconstumbrarse a ActivePython y que, hasta ahora, no he pensado en volver a la distribución oficial (por lo menos mientras necesite varias versiones del intérprete :-(.

Por esta razón, en los siguientes apartados se describe cómo llevar a cabo la instalación, actualización y configuración de ActivePython, para implementar el escenario descrito en la sección anterior.

Paso 2: Descarga e instalación

La instalación tradicional de ActivePython consiste en descargar, hacer double-click sobre el paquete de instalación -desde una cuenta de usuario con privilegios de administrador-, y seleccionar las opciones de instalación según nuestros gustos y/o necesidades.

Pero, dada mi extraña manera de utilizar Windows XP, lo normal es que describa los pasos de instalación desde la línea de comandos, alegando que esto facilita la creación de un script para la instalación desatendida (unattended) del programa (cosa que probablemente nunca haré4 :-(.

Este caso no será la excepción!

Descargando los paquetes de instalación

Para comenzar, abriremos una ventana del Símbolo del sistema, bajo una sesión creada con una cuenta de usuario con privilegios administrativos.

Microsoft Windows XP [Versión 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\> pushd %TEMP%

Desde allí, procedemos a descargar los dos (2) paquetes de instalación, copiando las URL de cada paquete desde la página de descargas de ActiveState.

D:\Temp> wget http://downloads.activestate.com/ActivePython/releases/2.7.2.5/ActivePython-2.7.2.5-win32-x86.msi
--2011-12-26 12:40:17--  http://downloads.activestate.com/ActivePython/releases/2.7.2.5/ActivePython-2.7.2.5-win32-x86.msi
Resolviendo downloads.activestate.com... 204.244.102.19
Connecting to downloads.activestate.com|204.244.102.19|:80... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 47198208 (45M) [application/octet-stream]
Saving to: `ActivePython-2.7.2.5-win32-x86.msi'

100%[================================================>] 47.198.208   792K/s   in 2m 10s

2011-12-26 12:42:27 (354 KB/s) - `ActivePython-2.7.2.5-win32-x86.msi' saved [47198208/47198208]

D:\Temp> wget http://downloads.activestate.com/ActivePython/releases/3.2.2.3/ActivePython-3.2.2.3-win32-x86.msi
--2011-12-26 12:43:25--  http://downloads.activestate.com/ActivePython/releases/3.2.2.3/ActivePython-3.2.2.3-win32-x86.msi
Resolviendo downloads.activestate.com... 204.244.102.19
Connecting to downloads.activestate.com|204.244.102.19|:80... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 47527424 (45M) [application/octet-stream]
Saving to: `ActivePython-3.2.2.3-win32-x86.msi'

100%[===============================================> ] 47.527.424   730K/s   in 1m 49s

2011-12-26 12:45:15 (425 KB/s) - `ActivePython-3.2.2.3-win32-x86.msi' saved [47527424/47527424]

Hecho esto, podremos continuar con la instalación propiamente dicha.

Instalando en modo silencioso

Con los paquetes de instalación descargados en un directorio temporal cualquiera, podremos comenzar creando un directorio base (en mi caso, el C:\World\Programs\Python) para realizar la instalación de las versiones descargadas de ActivePython.

D:\Temp> mkdir C:\World\Programs\Python

Ahora, iniciamos la instalación de la versión 3.2, invocando el instalador de Windows, con los siguientes argumentos de la línea de comandos:

D:\Temp> start /wait msiexec /qn ALLUSERS=1 INSTALLDIR=C:\World\Programs\Python\3.2 ADDLOCAL=core,doc,pywin32 /i ActivePython-3.2.2.3-win32-x86.msi

D:\Temp> echo %errorlevel%
0

Nótese que hemos utilizado el comando start /wait, para iniciar el instalador de Windows, deteniendo la ejecución del Símbolo del sistema hasta que finalice el proceso de instalación. También hay que notar que, al tratarse de una instalación no interactiva, hemos ejecutado el comando echo %errorlevel% para conocer el resultado de la instalación, en este caso: exitosa!

De los argumentos de la llamada al instalador (comando msiexec), el parámetro /qn indica que deseamos realizar una instalación (parámetro /i <package-name>) no interactiva; que se llevará a cabo sobre el directorio (variable INSTALLDIR=<directory>) ubicado en C:\World\Programs\Python\3.2; y que estará disponible para su uso por parte de todos los usuarios (variable ALLUSERS=1) de nuestro sistema.

Finalmente, lo más importante es la variable ADDLOCAL=core,doc,pywin32; pues es la que nos permite seleccionar qué componentes de ActivePython deseamos instalar. Las opciones documentadas se enumeran a continuación:

  • El componente core es el base del intérprete Python y es una dependencia para el resto de los componentes de ActivePython.

  • El componente doc es la documentación en línea (en formato .chm).

  • El componente pywin32 incluye una copia integrada de la librería pywin32 de Mark Hammond (recomendable para los que tenemos que trabajar sobre Windows).

  • Finalmente, también existe un componente denominado register -aunque no es precisamente un “componente”-, que indica al instalador que deseamos registrar las extensiones Windows y la asociación de ficheros, entre otras opciones de post-configuración (también es recomendable para winderos, pero aquí lo utilizaremos sólo al instalar la versión 2.7).

En el caso de la versión 3.2, hemos utilizado sólo las opciones core,doc,pywin32; para instalar el sistema base, su documentación en línea y las extensiones pywin32 (esto último no es obligatorio para una instalación de pruebas de compatibilidad con Python 3).

Finalmente, instalamos la versión 2.7 incluyendo todos los componentes del paquete (variable ADDLOCAL=ALL, con el valor ALL escrito en mayúsculas), cambiando la ruta de destino y el nombre del paquete de instalación (e.g. ActivePython-2.7.2.5-win32-x86.msi).

D:\Temp> start /wait msiexec /qn ALLUSERS=1 INSTALLDIR=C:\World\Programs\Python\2.7 ADDLOCAL=ALL /i ActivePython-2.7.2.5-win32-x86.msi

D:\Temp> echo %errorlevel%
0

Si todo ha ido bien, en este momento estaríamos a punto de comenzar a utilizar nuestro nuevo ActivePython! Pero también podríamos complicar un poco las cosas, como de hecho se hace en la siguiente sección.

Configurando la instalación a nivel global

En otros artículos de este blog hemos utilizado un junction point, para facilitarnos un poco la gestión de la variable de entorno PATH. También esto puede ser muy útil aquí, dado que tenemos varias versiones de Python instaladas y nos puede interesar cambiar de versión corriente con cierta facilidad.

Nota: Para crear el mencionado “junction point”, necesitamos tener instalado el comando junction de la “suite” de utilidades de Sysinternals.

Para ello, desde la ventana del Símbolo del sistema abierta en el paso anterior, procedemos a ejecutar:

D:\Temp> pushd C:\World\Programs\Python

C:\World\Programs\Python> dir
 El volumen de la unidad C es System
 El número de serie del volumen es: 1234-ABCD

 Directorio de C:\World\Programs\Python

26/12/2011  12:55    <DIR>          .
26/12/2011  12:55    <DIR>          ..
26/12/2011  12:54    <DIR>          2.7
26/12/2011  12:59    <DIR>          3.2
               0 archivos              0 bytes
               4 dirs  11.539.787.776 bytes libres

C:\World\Programs\Python> junction Current 2.7

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: C:\World\Programs\Python\Current
Targetted at: C:\World\Programs\Python\2.7

C:\World\Programs\Python> dir
 El volumen de la unidad C es System
 El número de serie del volumen es: 1234-ABCD

 Directorio de C:\World\Programs\Python

26/12/2011  12:55    <DIR>          .
26/12/2011  12:55    <DIR>          ..
26/12/2011  12:54    <DIR>          2.7
26/12/2011  12:59    <DIR>          3.2
26/12/2011  13:01    <JUNCTION>     Current
               0 archivos              0 bytes
               5 dirs  11.539.775.488 bytes libres

C:\World\Programs\Python> popd

Finalmente, debemos modificar la variable de entorno PATH a nivel del sistema (de modo que los cambios apliquen a todos los usuarios de nuestro ordenador). Esto se hace, desde el diálogo de Propiedades del sistema, seleccionando la pestaña Opciones avanzadas y el botón Variables de entorno.

Y si nos da pereza coger el ratón (mouse), podremos abrir dicho diálogo ejecutando:

D:\Temp> start /wait sysdm.cpl

Desde allí, en la lista de Variables del sistema, debemos modificar el valor de la variable PATH; cambiando las rutas que ha añadido el instalador de la versión 2.7 (el instalador de la versión 3.2 no habrá cambiado el valor de dicha variable de entorno), por las rutas equivalentes que apunten a nuestro junction point.

Por ejemplo, si nuestra instalación de Python 2.7 está ubicada en la ruta C:\World\Programs\Python\2.7, se deberá modificar la ruta según se indica en la siguiente tabla.

Cambios en la configuración del variable de entorno PATH
Valor actualValor nuevo
C:\World\Programs\Python\2.7C:\World\Programs\Python\Current
C:\World\Programs\Python\2.7\ScriptsC:\World\Programs\Python\Current\Scripts

Aunque no es indispensable (dado que tenemos una única instalación de uso diario: la versión 2.7), podemos modificar también las asociaciones de los tipos de fichero creadas durante la instalación, de manera que éstas apunten también a nuestro junction point.

Por ejemplo, si consultamos las asociaciones actualmente configuradas en nuestro sistema, mediante los siguientes comandos:

D:\Temp> assoc .py
.py=Python.File

D:\Temp> ftype Python.File
Python.File="C:\World\Programs\Python\2.7\python.exe" "%1" %*

D:\Temp> assoc .pyw
.pyw=Python.NoConFile

D:\Temp> ftype Python.NoConFile
Python.NoConFile="C:\World\Programs\Python\2.7\pythonw.exe" "%1" %*

Notaremos que las extensiones .py y .pyw están asociadas a una versión concreta de Python; en nuestro caso, la versión 2.7.

Aplicando el mismo esquema de modificación de las rutas de nuestra variable PATH, podremos cambiar esta configuración, de la siguiente manera:

D:\Temp> ftype Python.File="C:\World\Programs\Python\Current\python.exe" "%1" %*
Python.File="C:\World\Programs\Python\Current\python.exe" "%1" %*

D:\Temp> ftype Python.NoConFile="C:\World\Programs\Python\Current\pythonw.exe" "%1" %*
Python.NoConFile="C:\World\Programs\Python\Current\pythonw.exe" "%1" %*

De este modo, si creamos un fichero de pruebas hello.py, que imprima la versión del intérprete sobre el cual se ejecuta:

D:\Temp> python -V
Python 2.7.2

D:\Temp> copy con: hello.py
import sys
print(sys.version)
^Z
        1 archivos copiados.

D:\Temp> hello.py
2.7.2 (default, Jun 24 2011, 12:21:10) [MSC v.1500 32 bit (Intel)]

Podremos cambiar de intérprete por defecto, introduciendo la siguiente línea de comandos, antes de comenzar a trabajar:

D:\Temp> pushd C:\World\Programs\Python && junction -d Current && junction Current 3.2 && popd

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Deleted Current.

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: C:\World\Programs\Python\Current
Targetted at: C:\World\Programs\Python\3.2

D:\Temp> python -V
Python 3.2.1

D:\Temp> hello.py
3.2.1 (default, Jul 18 2011, 13:46:30) [MSC v.1500 32 bit (Intel)]

D:\Temp> pushd C:\World\Programs\Python && junction -d Current && junction Current 2.7 && popd

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Deleted Current.

Junction v1.06 - Windows junction creator and reparse point viewer
Copyright (C) 2000-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

Created: C:\World\Programs\Python\Current
Targetted at: C:\World\Programs\Python\2.7

D:\Temp> python -V
Python 2.7.2

Desde luego, esta práctica no es muy ortodoxa, por lo que debemos usarla con mucho cuidado!!!

Configurando la instalación a nivel de usuario

Toda vez realizados los cambios anteriores, debemos cerrar la ventana del Símbolo del sistema que hemos utilizado para llevar a cabo la instalación (con privilegios de usuario administrador); y abrir una nueva ventana del Símbolo del sistema, con nuestro usuario de trabajo cotidiano.

Si bien ya tenemos configurado nuestro sistema a nivel global, hay una parte de la configuración que debemos realizar desde la sesión de nuestro usuario de trabajo. Se trata de la implementación de la PEP–0370, que nos permite instalar los paquetes de terceras partes de manera local. Esto requiere que dispongamos de un directorio Scripts privado, cuya ruta esté incluida en nuestra variable PATH a nivel de usuario.

El instalador de la versión 2.7 de ActivePython (que hemos designado como nuestra versión de trabajo); modificará la variable PATH a nivel del usuario con el que hemos ejecutado la instalación, añadiéndole la ruta %APPDATA%\Python\Scripts dentro de su entorno privado.

El problema con esto, es que Windows XP no expande el valor de la variable APPDATA, por lo que debemos hacerlo nosotros de manera manual. Por ejemplo, si nuestra variable de entorno APPDATA contiene el siguiente valor a nivel de usuario: C:\World\Settings\Antonio\Data; debemos añadir a la lista de rutas de nuestra variable local PATH, la siguiente ruta para los scripts: C:\World\Settings\Antonio\Data\Python\Scripts.

Esto se hace de la misma forma cómo hicimos las modificaciones de la configuración a nivel global:

Microsoft Windows XP [Versión 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\> start /wait sysdm.cpl

Pero esta vez, modificando el valor de la variable de entorno PATH, que se encuentra dentro de la lista de Variables de usuario para….

Y al igual que en el caso anterior, debemos aceptar los cambios y cerrar la ventana del Símbolo del sistema, de modo que éste tome los cambios sobre nuestra configuración de usuario.

Paso 3: Hello, ActivePython!

Sé que a los más pytónicos les podrá sentar mal el ejemplo del Hello, ActivePython!, por su naturaleza trivial; pero es una tradición y por tanto, no me queda otra cosa que transcribirlo sin demasiados comentarios:

Microsoft Windows XP [Versión 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\> python
ActivePython 2.7.2.5 (ActiveState Software Inc.) based on
Python 2.7.2 (default, Jun 24 2011, 12:21:10) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print "Hello, ActivePython!"
Hello, ActivePython!
>>> ^Z

C:\> exit

Nota: Para los más arriesgados, el ejemplo de configuración del “junction point” descrito más arriba, puede ser más interesante que el modesto Hello, ActivePython! presentado aquí.

Próximos pasos

Por su contenido, esta chuleta era demasiado extensa como para haberla terminado en un sólo día. De hecho, llevaba en borrador desde el 28 de diciembre (fecha bajo la cual será publicada) y he tenido que dividirla en partes, para irlas publicando a medida que tenga tiempo de ordenar mis apuntes (de otro modo, cuando terminara estaríamos hablando de Python 4 :-S.

Es por ello que nuestro próximos pasos, consisten en:

  • En la parte 2, resumir brevemente los pasos para instalar ActivePython en RHEL5 y Mac OS X; brevemente, porque el procedimiento es trivial.

  • En la parte 3, retornaremos de nuevo a Windows y nos centraremos en describir el uso del gestor de paquetes PyPM, el ya conocido pip y la integración de todo esto con virtualenv.

Cuando éstas estén disponibles, tendremos que añadir aquí los enlaces correspondientes.


  1. Realmente, todo empezó cuando quería probar el Google App Engine; pues éste requería Python 2.5, y yo necesitaba actualizarme a la distribución oficial de Python 2.6.

  2. Paquete binario, en este contexto, se refiere a aquellos que han sido primero construidos y luego empaquetados para facilitar su distribución, lo cual es útil cuando necesitas un compilador de ANSI C o de Fortran para llevar a cabo el proceso de construcción, y estás trabajando con un ordenador con Windows.

  3. Ver por ejemplo, los Unofficial Windows Binaries for Python Extension Packages de Christoph Gohlke.

  4. Básicamente, porque me resulta más simple copiar y pegar los comandos, directamente desde esta chuleta.