Thursday, February 21, 2008

Desarrollo y Despliegue en zope

Siguiendo con los apuntes de zope 3, aquí esta la versión aumentada y corregida de como trabajar con zope. Básicamente se quiere llevar a cabo dos actividades: desarrollo (development) y despliegue (deployment).

Preconfiguración

Antes de desarrollar cualquier aplicación es conveniente tener un entorno sano y reproducible y de preferencia trabajar en un sandbox personal. Ya vimos una opción para crear este entorno virtual usando virtual-python. El sucesor de virtual-python es virtualenv. Esta aplicación funciona mejor que virtual-python en windows y genera un entorno menos polucionado. Además, instala automaticamente easy_install y un script de activación del entorno:
# con una version previa de easy_install, instalar virtualenv
$ wget http://peak.telecommunity.com/dist/ez_setup.py
$ sudo python2.4 ez_setup
$ sudo easy_install-2.4 virtualenv

# crear el entorno virtual de python

# y comenzar a trabajar en el
$ virtualenv ~/entorno
$ cd ~/entorno
$ source bin/activate

# instalar zope-project
$ easy_install zopeproject

# instalar zc.buildout

$ easy_install zc.buildout
El ultimo comando se encarga de fijar algunas variables de entorno, modificar el path para usar el interprete de python del entorno virtual y modificar el prompt para indicar que el entorno esta activo.


Despliegue

El despliegue es la creación y configuración del sitio web propiamente. Para crear el sitio de despliegue (una instancia de zope 3) usamos zopeproject dentro de nuestro entorno virtual previamente activado:
# Crear una instancia
$ zopeproject misitio
{introducir el login del administrador}
{introducir la contraseña del administrador}
{introducir la ruta donde se guardarán los eggs para el proyecto
indicar preferiblemente ~/entorno/lib/python2.4/site-packages/ }

# comenzar a trabajar en el sitio de despliegue
$ cd misitio
El sitio se configura en src/misitio/sonfigure.zcml y sus dependencias para la generación del egg se especifican en setup.py, como de costumbre. El script para el buildout es buildout.cfg.

Como siempre, al agregar o eliminar dependencias, se debe correr bin/buildout.


Desarrollo

El desarrollo es la creación de paquetes para zope. Estos paquetes normalmente no tienen utilidad fuera del zope, sino que son las piezas de lego con las que se construye un sitio. Es conveniente que cada paquete de desarrollo resida en su propio directorio y sus requerimientos sean manejados por zc.buildout. Ahora se creará la estructura mínima de un paquete de desarrollo, siempre en el entorno virtual previamente activado:
# Crear el directorio para el buildout del paquete
$ mkdir mipaquete
$ cd mipaquete
$ buildout init

# Crear la estructura mínima del buildout
$ touch setup.py
$ mkdir -p src/mipaquete
$ touch src/mipaquete/__init__.py
La estructura básica de buildout.cfg es
[buildout]
develop = .
parts = test
eggs-directory = /home/jdinunci/apps/webdev/lib/python2.4/site-packages/
{ruta donde yo guardo los eggs}

[test]
recipe = zc.recipe.testrunner
eggs = mipaquete [test]


La estructura básica de setup.py es
import os
from setuptools import setup, find_packages

def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()

setup (
name='mipaquete',
version='0.1',
author = "Jose Dinuncio",
author_email = "micorreo@midominio.org",
description = "Mi paquete",
license = "GPL",
keywords = "zope3",
classifiers = [
'Environment :: Web Environment',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope3'],
packages = find_packages('src'),
include_package_data = True,
package_dir = {'':'src'},
# linea de abajo solo necesaria para
# paquetes virtuales
#namespace_packages = ['reduc'],
extras_require = dict(
test = [
'zope.testing',
'zope.app.container [test]',
],
),
install_requires = [
'setuptools',
'zope.interface',
'ZODB3',
'zope.schema',
'zope.app.container',
'zope.app.content',
'zope.dublincore',
],
dependency_links =
['http://download.zope.org/distribution'],
zip_safe = False,
)

En mi caso, mis paquetes usan paquetes virtuales, por lo que suelen llamarse reduc.mipaquete, lo cual implica ligeras modificaciones en el procedimiento
#Crear el directorio para el buildout del paquete
$ mkdir reduc.mipaquete
$ cd reduc.mipaquete
$ buildout init

# Crear la estructura mínima del buildout
$ touch setup.py
$ mkdir -p src/reduc/mipaquete
$ touch src/reduc/mipaquete/__init__.py

# Crear el paquete virtual reduc
$ echo "__import__('pkg_resources').declare_namespace(__name__)"
> src/reduc/__init__.py
En este caso, hay que agregar una configuración a setup.py para el manejo del paquete virtual:
namespace_packages = ['reduc'],

Estos paquetes en desarrollo pueden ser incluidos en el sitio de despliegue con la directiva develop

[buildout]
develop = .
../mipaquete

Al ejecutar bin/buildout, se crea un enlace en develop-egg que permite que los paquetes sean encontrados.

Este es el ciclo depurado para el desarrollo y despliegue en python. Aún puede agregarse mas comodidad al mismo, como agregar al buildout la descarga automatica de paquetes de desarrollo vía svn.

Friday, February 15, 2008

Como obtener paquetes de Zope via svn

Lo ideal es obtener los paquetes de zope vía easy_install o buildout. Sin embargo, una importante cantidad de paquetes es estado de desarrollo, pero aún estables, se encuentran en un repositorio de subversion.

La primera pregunta es: ¿Como saber que hay en ese repositorio? Una forma fácil es visitando http://svn.zope.org. Supongamos que eliges http://svn.zope.org/z3c.weblog/. Después de ubicar el paquete en cuestión, es solo cosa de descargando usando el svn, mas con la siguiente salvedad: se sustituye el protocolo por svn y se prefija la url con repos/main/:

svn co svn://svn.zope.org/repos/main/z3c.weblog z3c.weblog
Una vez hecho esto, se debe generar el entorno para el buildout y ejecutar el buildout propiamente:
# bootstrap
# bin/buildout
O, si ya se dispone de un buildout, simplemente invocarlo.

Friday, February 1, 2008

Desarrollando con zc.buildout

Siguiendo con el desvío tomado en Huevos y Constructores, abordaremos el desarrollo de paquetes en python usando zc.buildout. La instancia de zope que creamos con zopeproject es un proyecto manejado por buildout, por lo que es de suma importancia entender como funciona este de manera aislada. Para ello crearemos un paquete en python con una implementación de ejemplo.

Por que usar buildout? Dado que queremos hacer fácilmente instalable nuestro paquete por terceras personas, requerimos algún método para empaquetarlo y distribuirlo. Podríamos usar distutil, pero durante el desarrollo con cada cambio hecho al código deberiamos generar la distribución e instalarla antes de hacer una prueba. Adicionalmente, para hacer la instalación se requiere permisología de root.

Otras ventajas de builtout sobre distutils es que este usa setuptools, por lo que podemos resolver los problemas de dependencias y versiones con los que se enfrentaría quien tratara de instalar el paquete. buildout se ocupa además de preconfigurar el paquete antes de hacer la instalación o pruebas.

Para instalar zc.buildout se requiere setuptools y se recomienda virtual-python (veáse Instalando Zope 3).

Para procesar un paquete o aplicación con buildout se requiere un archivo buildout.cfg que defina el entorno que el paquete necesita:
[buildout]
develop=.
...
La estructura del archivo buildout.cfg es una serie de secciones cuyo nombre aparece entre corchetes, seguida por una serie de pares clave=valor que definen la sección. [buildout] es la sección principal y la única requerida.

buildout.cfg define una serie de partes o elementos necesarios para que la aplicación funcione. Cada parte se define en una sección diferente. Cada parte es procesada por un recipe (un programa en python para instalar y actualizar la parte). Las demas lineas de una sección sirver para configurar el recipe. Hay una gran variedad de recipes para distintas funciones, como descargar eggs, compilar aplicaciones, correr la batería de pruebas de un paquete,e tc. En caso de necesidad el desarrollador puede crear sus propios recipes.


Desarrollando un paquete con buildout


Comenzamos desarrollando un paquete normal en python
# mkdir blah
# cd blah

# mkdir src {aquí va el código fuente de los paqutes a desarrollar}
# mkdir src/blah
# ... {se agregan los módulos al paquete blah}
Este paquete será distribuido con setuptools, por lo que debemos crear un archivo blah/setup.py que defina su distribución:
# blah/setup.py
from setuptools import setup, find_packages

setup(name='blah',
version='0.1',
packages=find_packages("src"),
package_dir={"": "src"},
# Notese que los requisitos del paquete son indicados
# aquí para que setuptools pueda generar
# correctamente su egg

install_requires=[ 'zope.tal' ], )
Hasta este punto tenemos un paquete convencional de python, listo para ser distribuído via setuptools. Ahora hay que convertir el directorio de trabajo en un directorio manejado por buildout.

Ahora, se define el archivo buildout.cfg que determinará como generar la aplicación
[buildout]
develop=.
parts=me

[me] recipe=zc.recipe.egg
eggs=zope.tal
Este archivo define una parte llamada 'me', la cual para ser construida requiere el recipe encargado de descargar eggs. El único egg a descargar será zope.tal.

Pero aún falta en manejar este proyecto a traves de buildout. Para crear la infraestructura necesaria, hay que hacer un bootstrap. Este procedimiento se realiza una única vez en la vida del proyecto:
# ruta-hacia-buildout/buildout bootstrap

(Desde luego, buildout debe estar instalado, cosa fácil gracias a easy_install).

buildout creará un directorio bin donde instalará su ejecutable y cualquier otro requerido por las dependencias. Creará además un directorio eggs donde instalará los eggs necesarios por esta aplicación, un directorio develop-eggs donde creará referencia a los eggs que esta aplicación defina y un directorio parts, para ser utilizado por las partes del archivo de configuración.

Ya con toda la infraestructura en su lugar, para asegurar que la aplicación tenga todos sus requerimientos instalados basta con ejecutar
# buildout
Con cada cambio en las dependencias es necesario re-ejecutar el comando, para que satisfaga las nuevas necesidades de la aplicación.

Jugando con las partes y los recipes se puede automatizar el proceso de instalación de las dependencias de la aplicación. Otras funciones determinan si se descargará la versión mas nueva de un paquete o una en especifico.

Se puede generar la distribución de los paquetes por medio de setuptools o por medio de buildout. En el último caso, los comandos son:
# bin/buildout setup . sdist {distribución fuente}
# bin/buildout setup . bdist {binarios}

# bin/buildout setup . bdist_egg {bnarios en eggs}
La fuente autoritativa de zc.buildout se encuentra en http://pypi.python.org/pypi/zc.buildout

Huevos y Constructores

Antes de proseguir con el desarrollo en zope es conveniente tomar un desvío hacia dos tecnologías usadas por zope que pueden no ser conocidas por los desarrolladores en python: los eggs y buildout.


Los eggs son una forma conveniente de distribuir paquetes de python. Pueden pensarse como el equivalente a los .jar de java, solo que con mayor riqueza. Los eggs son una extensión al mecanismo tradicional de distribución de paquetes en python, ofrecido por distutils.

distutils es la herramienta incorporada en python para la compilación e instalación de paquetes. Normalmente el usuario descarga un archivo .tgz con la fuente del paquete, lo descomprime y ejecuta el archivo setup.py que este contiene. setup.py invoca a distutils que compila (de ser necesario) e instala el paquete en un lugar donde pueda ser encontrado por python.

Los eggs mejoran este proceso. Son paquetes ya compilados, por lo que no requieren herramientas de desarrollo adicionales (compiladores, etc). Pueden estar comprimidos, siendo mas fácilmente manipulables. Además, ofrecen una metadata mas rica, lo cual permite la detección de dependencias.

Esta última característica es lo que permite usar eggs para construir un repositorio de aplicaciones con instalación simplificada. El programa easy_install.py se aprovecha estas características para permitir una instalación de las aplicaciones y sus dependencias con una simple instrucción.

El crear un egg es tan simple como crear un paquete con distutils. Solo se necesita tener instalado el paquete setuptools (el cual es en si mismo un egg que puede ser instalado automáticamente por easy_install). Si el egg va a ser distribuido empaquetado como un zip, entonces debe seguirse unas convenciones adicionales.


La otra tecnología es buildout. El término en general se refiere a todo lo necesario para la construcción e implementación de una aplicación. Cuando un desarrollador esta trabajando en una aplicación con muchas dependencias, necesita herramientas para automatizar su configuración y seguir las versiones de cada paquete usado. La gente de zope desarrolló el paquete zc.buildout con esta finalidad.

zc.buildout permite crear entornos para el desarrollo que sean fácilmente repetibles. De esta manera, el desarrollador podrá trabajar con frameworks complejos como zope y trasladar su trabajo a otro equipo. El resultado final de zc.buildout es un egg con la información exacta de todas las dependencias, versiones y todos sus procesos de configuración. Al instalar este egg en un tercer equipo se obtendrá una copia exacta del entorno en el equipo original.

El ingrediente final en la entrada anterior fue el paquete zopeproject. Este paquete instala un comando del mismo nombre que genera un buildout preconfigurado para iniciar un proyecto con zope.

En entradas posteriores trataré el uso de los eggs y de zc.buildout en desarrollos de python independientes de zope para mostrar su utilidad general. Esto permitirá comprender de forma mas fácil que su uso en zope es conveniente mas dispensable.

Instalando Zope 3

La presente explicación aplica para usuarios de Linux y otras formas de Unix.

La mas reciente versión de Zope es la 3.4.0Beta. La serie 3.4 es la primera en migrar hacia la distribución en eggs. Esto hace que su proceso de instalación sea diferente al tradicional descomprimir-configurar-compilar-instalar. Los eggs son paquetes de python con sus dependencias indicadas y una infraestructura (easy_install) para obtenerlos e instalarlos automáticamente.

Otro punto a considerar es que zope recomienda el python 2.4 mas su paquete de desarrollo, los cuales podría no ser los instalados en el sistema.

Para trabajar con mayor comodidad y seguridad con zope es mejor hacerlo como un usuario normal y no hacer una instalación como root en las rutas por defecto. Para ello es recomendable crear un entorno virtual para python. Baja virtual-python.py y ejecutalo:

# python2.4 bin/virtual-python.py --prefix=~/zope3/

Esto creará una carpeta zope3 en tu directorio home que contendrá una copia ligera del python2.4, sus archivos include y sus librerías. Aquí podrás instalar cualquier aplicación o paquete hecho en python sin tener necesidad de privilegios de administración.

El siguiente paso es instalar easy_install, la aplicación que maneja los eggs y permite instalar paquetes de python de manera automatica. Baja ez_setup.py y ejecutalo:

# ~/zope3/bin/python bin/ez_setup.py

Hasta este punto no has hecho nada que sea especifico de zope. Solo tienes un entorno propio de python, con soporte para instalación de eggs. Eso esta por cambiar. Con la magia de easy_install instalaremos un único paquete que te permitirá crear instancias de zope y bajará todas las librerías necesarias:

# ~/zope/bin/easy_install zopeproject

Es en este punto que podemos crear nuestra primera instancia de zope3, llamemosla webdev:

# ~/zope/bin/zopeproject webdev

zopeproject preguntará por un login y contraseña para el administrador de la instancia y por el lugar en el cual descargará los eggs del zope. Responde a esta pregunta con ~/zope/lib/python2.4 /site-packages. A continuación zopeproject bajará zc.buildout que es un paquete encargado de construir aplicaciones, descargando automáticamente sus dependencias. Si es la primera vez que ejecutas zopeproject preparate a esperar unos buenos minutos mientras descarga todas las librerías que conforman zope. Invocaciones posteriores serán mucho mas rapidas mientras sigas indicando la misma ruta de descarga de los eggs.

Al finalizar el proceso tendras dentro de zope una carpeta webdev. Esta carpeta contiene tu instancia zope. Para iniciar tu instancia puedes ejecutar

# ~/zope/webdev/bin/webdev-ctl fg

y puedes ver a la aplicación corriendo en http://localhost:8080

Las fuentes para esta entrada están aquí y aquí, solo que de forma menos digerida.

En este punto solo queda comenzar a desarrollar tu propia aplicación en zope y un poco de conocimiento de zc.buildout para el momento final en que empaquetaras tu aplicación.

zope 2 y zope 3

La nueva versión de Zope es Zope 3. Esta es una reescritura desde cero de su anterior y también magnifico producto Zope 2. Zope 2 introdujo conceptos interesantes como el desarrollo de aplicaciones a traves del web, almacenar los componentes en una base de datos orientada a objetos y permisología basada en roles.

Sin embargo, extender Zope 2 no era fácil. Adicionalmente conforme la aplicación fue evolucionando, es código se volvió mas y mas desordenado. La aplicación había sobrepasado su diseño original.

Luego se creó el concepto de arquetipos. Desarrollar componentes con arquetipos era una tarea casi trivial: se indicaban los campos que definían a los objetos o componentes por una parte y las funciones que los manipulaban por la otra. La información de los campos era usada para generar las páginas web automáticamente y solo bastaba hacer el enlace con el funciones.

Ese fue el detonante para Zope 3. Si desarrollar una aplicación dentro de Zope era mucho mas fácil usando arquetipos, por que no desarrollar el Zope mismo bajo este concepto? Los arquetipos se convirtieron en interfaces, componentes, adaptadores y utilidades y una aplicación casi monolítica se convirtió en un archipielago de pequeños y simples componentes interactuando entre si.

Desarrollo web con zope

A principios de este año retomé un viejo amor no correspondido con Zope. Zope es un servidor de aplicaciones con favoritismo hacia el web escrito casi totalmente en python.

Zope ofrece un framework para el manejo de contenido a través del web. Es como un lego que permite armar pieza por pieza una aplicación web. Para quienes gustan de los buzzwords es un CMF con una base de datos transaccional orientada a objetos y con capacidades de diseño a través del web. Que hace a zope atractivo? Un diseño elegante con separación de responsabilidades. Zope mantiene religiosamente separados código y html.

Pero su influencia va mas allá de si mismo. El corazón del Zope, el ZCA (Zope Component Architecture) es usado por terceras partes como Creative Commons Publisher, Gaphor o Launchpad, aplicaciones estas que no tienen que ver con el web. Zope ha sido un motor en el desarrollo de python hasta el punto que se ha llegado a decir que donde Zope guia, python le sigue.

Desde luego, Zope no es perfecto. Al ser un framework, esto le impone al desarrollador el conocer la arquitectura del mismo para poder interactuar con él. Esto significa un costo de entrada pronunciado. Luego de unos intentos en falso, gracias a Web Component Development with Zope 3, he comenzado a cosechar mis primeros resultados sobre los que comentaré en futuras notas.