Beruflich Dokumente
Kultur Dokumente
Debian 6
MANUAL PRCTICO
ENERO 2012
Pennsula y Baleares 6,95
Canarias 7,05
PROYECTOS COMPLETOS
17 Y FUNCIONALES Especia
l
06 BSICOIntroduccin a
Python con
ejemplos prcticos
48 INFRAESTRUCTURAS
Explota los motores tras
Facebook, Google y Twitter
59 MDULOS
Descubre cmo programar
para 3D y a manipular datos
e imgenes
WWW.LINUX- MAGAZINE.ES
En la tienda de Linux Magazine (www.linux-magazine.es/tienda) vendemos revistas y libros que pue-
den ser de inters a nuestros lectores. Recuerda tambin que con una subscripcin Digital o Club,
des conseguir software, gadgets, libros y servicios. Este mes en nuestra tienda...
Manual LPIC-1
El nico manual en castellano para la certificacin com-
pleta LPIC-1 (exmenes 101 y 102). Ms de 250 pginas
de ejemplos reales tomados de ambos exmenes expli-
cados en todo detalle con ejercicios para prcticas y sus
soluciones.
www.lpi.org.es
Especial Python
Bautizado en honor al grupo de cmicos britnicos Monty
Python, Guido Von Rossum concibi este lenguaje en los
aos 80, comenzando su implementacin en 1989. Gra-
cias a su sencillez y a la idea de que el cdigo bello se
consigue siendo explcito y simple, Python se ha
convertido en sus poco ms de 20 aos de exis-
tencia en el lenguaje favorito para scripts, aun-
que tambin para grandes infraestructuras y
aplicaciones.
As, la mayor parte de los servicios de Goo-
gle y Facebook se construyeron utilizando
Python, las aplicaciones de diseo Inkscape
o Blender (entre muchas otras) utilizan un
motor Python para sus plugins. Tambin se
utiliza ampliamente en la investigacin en
entidades que van desde CERN hasta la
NASA.
Adems, su clara y bien pensada sintaxis,
su modularidad y su sobresaliente rendi-
miento a pesar de ser interpretado hacen de
Python un excelente lenguaje educativo, ideal
para ensear programacin del mundo real a todos
los niveles.
Con este especial pretendemos que el lector pueda
descubrir Python desde el principio, creando para ello
artculos que abordan desde tutoriales introductorios, hasta
programacin de alto nivel y para usos avanzados. Cada seccin
viene con varios ejemplos prcticos, cdigo y soluciones extradas del
mundo real.
W W W. L I N U X - M A G A Z I N E . E S PYTHON 3
CONTENIDO Python 01
Integracin
4 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Python 01 CONTENIDO
VERS
IN
DVD
GNO
ME L
IVE
Infraesctructuras Libreras
48 Pyramid 65 Grficas 3D
Uno de los rivales de peso de Django Crear grficos 3D no es nada difcil en
est creciendo en popularidad poco a Python... sobre todo si tenemos a
poco. mano la librera VTK.
52 Guitarrazos
Los creadores del proyecto Django nos
hablan de la formacin de la Django
Software Foundation y mostramos
cmo comenzar con esta infraestruc-
tura web.
55 Seriales
Hacer que distintos servicios se comu- 69 Vigilantes del planeta
niquen entre ellos es todo un pro- Quin no ha querido alguna vez sen-
blema que Facebook ha tratado de tirse como esos informticos de la
solucionar con Thrift. NASA en su centro de control? Hoy
nos construiremos el nuestro y contro-
laremos el planeta y sus alrededores.
73 Enredados
Podemos automatizar comandos y
programas grficos, por qu no auto-
matizar la interaccin con pginas
web? En este artculo crearemos un
pequeo script que puede ahorrarnos
mucho trabajo con el ratn.
77 ReportLab
Libreras Hoy en da se hace imprescindible dis-
poner de herramientas que permitan 3
generar informes en PDF de alta cali- n pg.
e
59 Cuaderno de Bitcora dad rpida y dinmicamente. Existen
macin
r
Te acuerdas de cuando cambiaste la diferentes herramientas para esta fina- info
versin de Firefox por ltima vez? y lidad, entre ellas cabe destacar Repor- Ver
de por qu instalaste ese programa tan tLab, biblioteca gratuita que permite
raro que parece no servir para nada ? crear documentos PDF empleando
Yo tengo mala memoria, as que uso como lenguaje de programacin
un cuaderno de bitcora. Python.
W W W. L I N U X - M A G A Z I N E . E S PYTHON 5
INTRODUCCIN Primeros Pasos
Primeros Pasos
Python es un lenguaje potente, seguro, flexi-
Para empezar, debemos saber por qu Los programas escritos en este lenguaje de una comunidad de desarrolladores
Python es interesante, por qu es tan tienden a ser fciles de comprender y, cada vez ms amplia. Por ejemplo, per-
famoso y cada vez ms utilizado. Mirando por tanto, de mantener por terceros. Una mite la declaracin dinmica de varia-
un poco por Internet se pueden encontrar enorme ventaja frente a lenguajes como bles, es decir, no tenemos que declarar
multitud de aplicaciones que nos muestran C o Perl. las variables ni tener en cuenta su
parte de las capacidades de este lenguaje Pero veamos una breve comparativa con tamao, ya que son completamente din-
de alto nivel. Vamos a enumerar algunas otros lenguajes: micas. Adems, dispone de un gestor de
de sus sorprendentes caractersticas: Hola Mundo en C: memoria que, de manera similar al de
Orientado a objetos Esto no significa java, se encargar de liberar memoria de
que sea exclusivamente orientado a main () objetos no utilizados. Sin embargo, y al
objetos, podemos utilizarlo como quera- { igual que Java, no permite usar la memo-
mos, aunque le sacaremos ms prove- printf(Hola Mundo); ria a bajo nivel como C, con el que nos
cho si usamos su implementacin de } podamos referir a zonas de memoria
OOP (Programacin Orientada a Obje- directamente.
tos). Hola Mundo en Java: Adems se puede combinar con otros
Libre y gratuito Desde la red, pode- mltiples lenguajes de programacin.
mos descargar el interprete y su cdigo public static void U Podemos mezclar en nuestras aplicaciones
fuente, y al ser un lenguaje de script, main(String args[]) Python y Java (Jython ver el artculo al
viene con la mayora de las distros { respecto en la pgina 28 de este especial),
GNU/Linux de manera predeterminada, System.out.println(Hola U por ejemplo. O Python con C/C++, lo
siendo posible ver el cdigo de una Mundo); cual hace que resulte mas potente si cabe.
enorme parte del software desarrollado } Python tambin cuenta con una amplia
para Python. biblioteca de mdulos que, al estilo de las
Portable Al ser interpretado, podemos Hola Mundo en Python: bibliotecas en C, permiten un desarrollo
ejecutar nuestros programas en cual- rpido y eficiente.
quier S.O. y/o arquitectura simplemente print Hola Mundo La sencillez de Python tambin ayuda a
teniendo instalado previamente el intr- que los programas escritos en este lenguaje
prete en nuestro ordenador . Aunque los Hola Mundo no son muy sean muy sintticos. Como podemos ver
Potente Realizar un programa bajo indicativos de nada, ntese la ausencia de en el ejemplo Hola Mundo anterior, la
este lenguaje seguramente nos costara puntos y comas, llaves, declaracin de fun- simplicidad llega a ser asombrosa. Si este
entre la mitad o la cuarta parte del ciones y otros trastos que entorpecen el programa ya supone ahorrarte 4 5 lneas
tiempo que tardaramos en desarrollar el cdigo. Esto es incluso ms obvio en pro- de cdigo, con una sintaxis tan sencilla y
mismo programa en C/C++ o Java. gramas ms largos. ordenada podemos imaginar que un pro-
Claro Puede que sta sea una de las Python dispone de otras caractersticas grama de 1000 lneas en Java, en Python se
caractersticas ms alabadas de Python: que lo convierten en el lenguaje favorito redujeran unas 250.
6 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Primeros Pasos INTRODUCCIN
8 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Primeros Pasos INTRODUCCIN
cutarlo. En el libro se implementa el diseo Para hacer las pruebas es recomendable Veamos cmo funciona. Lo primero es ir
en C, C++, Java, Perl y AWK. Nosotros lo conseguir un texto de gran tamao. En tex- introduciendo en el diccionario dos prefi-
haremos en Python (ver Listado 4). tos pequeos no surtir tanto efecto. En el jos como ndice y las palabras que les
El programa acepta un texto como proyecto Gtenberg podemos conseguir siguen en el texto dentro de una lista refe-
entrada y genera un texto como salida, pero infinidad de textos clsicos de enorme renciada por ellos. Eso es un diccionario
este segundo texto no tiene sentido. Lo que tamao en ASCII. Pero somos conocedores con dos palabras como ndice que contiene
queremos hacer es generar texto sin sentido de que no todo el mundo entiende el una lista:
pero con estructuras que s lo tengan. Puede idioma anglosajn, as que en lugar de ir al
parecer algo muy complicado, pero no lo es proyecto Gtenberg, podemos coger cual- DICCIONARIO[ palabra 1, U
tanto si usamos la tcnica de cadenas de quier texto que queramos modificar, por palabra 2] -> U
Markov. La idea es coger 2 palabras, elegir ejemplo, alguna noticia de poltica de un LISTA[palabra,...]
una palabra que suceda a cualquiera de las diario digital o alguna parrafada de algn
dos y reemplazar la primera por la segunda blog. O sea, si tenemos las palabras La gente
y la segunda por la palabra escogida. De Este programa es interesante porque per- est La gente opina, crearemos un dic-
esta manera vamos generando un texto que, mitir utilizar las estructuras de datos que cionario de la siguiente forma:
aunque carece de sentido, normalmente se Python implementa, en particular en los
corresponde con la estructura de un texto diccionarios, que generan una tabla donde >>> dict[La, gente] = U
normal aunque disparatado. los ndices sern cadenas de texto. [est]
>>> dict[La, gente].U
Listado 4: markov.py Genera un Texto No-Tan-Aleatorio append(opina)
>>> dict[La, gente]
01 #!/usr/local/bin/python 22 # Fin de archivo
[est,opina]
02 23 dict.setdefault((w1, w2), []
03 #Importamos dos mdulos ).append(no_palabra)
04 #random [que hace] 24 Vamos haciendo esto de manera sucesiva
05 #y sys [que hace] 25 # GENERAMOS LA SALIDA con todos los conjuntos de dos palabras, y
06 import random 26 w1 = no_palabra obtendremos un diccionario en el que
07 import sys 27 w2 = no_palabra muchas entradas referenciarn a una lista
08 28 de ms de un elemento.
09 no_palabra = \n 29 # puedes modificarlo
La magia aparece cuando generamos el
10 w1 = no_palabra 30 max_palabras = 10000
texto, puesto que lo que hacemos es
11 w2 = no_palabra 31
32 for i in xrange(max_palabras):
comenzar por las dos primeras palabras, y
12
33 nueva_palabra = cuando existan varias posibilidades para
13 # GENERAMOS EL DICCIONARIO
random.choice(dict[(w1, w2)]) esa combinacin (como con el ejemplo de
14 dict = {}
34 La,gente), escogeremos aleatoriamente
15
35 if nueva_palabra == no_palabra: entre ellas. Imaginemos que escogemos
16 for linea in sys.stdin:
36 sys.exit()
17 for palabra in linea.split(): opina, entonces escribimos opina por la
37
18 dict.setdefault( (w1, w2), [] pantalla y buscamos en gente, opina y
).append(palabra) 38 print nueva_palabra;
39
as sucesivamente, hasta llegar a no_pala-
19 w1 = w2
40 w1 = w2 bra.
20 w2 = palabra
41 w2 = nueva_palabra Para entender mejor el funcionamiento
21
del programa recomendamos copiar el
cdigo fuente y pasarle unos ejemplos
Listado 5: Salida de markov.py (pongamos, con cat texto.txt |
./markov.py) y ver los resultados. En el
Para empezar, debemos saber por qu Python es obligatorio hacerlo de una
manera. Como es un lenguaje tipo script, debemos poner #! seguido de la Listado 4 vemos un ejemplo de la salida
ejecucin del programa. Tambin tenemos a nuestra disposicin los operadores utilizando el texto de este artculo. El texto
habituales de otros lenguajes: +, -, *, /, etc. Y una vez que sabemos cmo generado casi tiene sentido, pero no del
manejar operadores y asignaciones, se pueden mezclar: diccionarios de listas
de diccionarios, diccionarios de listas, listas de Python tambin vienen todo.
provistas de muchas ms opciones que sus semejantes en otros lenguajes. Por Despus podemos intentar cambiar
ejemplo, vamos a definir una lista que guarde una serie de espacios (logrados cosas en el programa, por ejemplo, en
pulsando la tecla TABULADOR) y una sentencia. Esos espacios son vitales, ya
que marcan la existencia de un texto que, aunque carece de sentido, lugar de utilizar 2 palabras como ndice del
normalmente se corresponde con la que Python trata las listas de diccionario, podemos probar con 1 o con
diccionarios, diccionarios de listas, listas de Python resultan tan 3, y tambin con el tamao del texto que
potentes, es que nos permiten referenciar a un elemento en la sangra de la
OOP. - Es potente. Realizar un programa de 1000 lineas en Java, en Python es se le pase. Se pueden conseguir cosas muy
obligatorio hacerlo de una manera. Como es un diccionario con dos palabras interesantes.
como ndice y las palabras que les siguen en el que muchas entradas
referenciarn a una lista de ms de un bloque de cdigo Python. Ese bloque
aparecer en bucles, funciones o mtodos. Si nos fijamos bien en la sangra de Recursos
la memoria a bajo nivel como C con el tamao del texto que se usa en el Listado
1. [1] Python: http://www.python.org
W W W. L I N U X - M A G A Z I N E . E S PYTHON 9
INTRODUCCIN Ficheros
lbum
En nuestro primer artculo vimos algo mos hacer es llamar a reset_variable() y Para acceder a un fichero, primero
sobre cmo trabajar con objetos en as asegurarnos de que nuestro valor sea necesitamos crear un objeto file. El
Python. Fue muy simple, pero ya nos asignado, pero entonces destruiramos el objeto file es parte de la librera base de
daba la posibilidad de organizar nuestro valor anterior y no sabramos qu podra Python, as que no es necesario importar
cdigo en torno a ellos. Python hace un pasar. ninguna librera.
uso extensivo de los objetos en sus APIs, Por lo tanto, necesitamos un meca-
y especialmente del control de errores nismo de comunicacin para darle a >>> archivo = file(texto.txt)
mediante excepciones, lo que nos da la conocer al usuario que esa variable ya
opcin de lanzarlas cuando algo va mal. est asignada. Esto lo podemos hacer Por definicin, file abre los ficheros en
Una excepcin es un mensaje que pode- con las excepciones. modo de slo lectura. Eso significa que si
mos capturar cuando se ejecuta cierta En el Listado 2 aparece una clase que el fichero no existe, obtendremos un
funcin o mtodo y aparece un error de hereda de la clase Exception llamada error. Para verificar si el fichero existe
algn tipo. Normalmente controlamos Var_Asignada. Cuando en la clase podemos usar la funcin exists() de la
estos errores mediante el valor devuelto obj_variable intentamos asignar un valor librera os.path.
por la funcin (como por ejemplo en C). a la variable var y sta no es 0, entonces
Esta tcnica es engorrosa, pero al igual se dispara, se eleva, la excepcin >>> import os.path >>>
que todo, tiene sus virtudes y sus des- Var_Asignada. Si no controlamos la por- os.path.exists(texto.txt) True
ventajas. Pero Python hace uso de las cin de cdigo en la que se encuentra >>> os.path.extsts(algo-
excepciones en su lugar. set_variable() y aparece una excepcin, peludo-y-feo.txt) False
Cuando una funcin genera una el programa se detendr y acabar.
excepcin, decimos que eleva una excep- La idea detrs de las excepciones es Por lo tanto, si vamos a abrir un
cin. Es muy normal tener que controlar que es posible tratarlas y evitar males fichero, podemos asegurarnos de que ya
las excepciones en las operaciones que mayores, pudiendo en ocasiones incluso existe.
realicemos con recursos que pueden no recuperarnos de ellas. Para ello est la Si en lugar de leerlo lo que queremos
estar disponibles. Por eso las vamos a estructura tryexcept, con la cual rodea- es crearlo, deberemos invocar al cons-
ver, puesto que aqu vamos a trabajar mos el cdigo que puede disparar excep- tructor de file con los parmetros:
con archivos y conexiones a Internet. ciones (Vase el Listado 3).
Crearemos un objeto que gestione un A partir de ahora, y hasta que no expli- >>> archivo = file(texto.txt,U
recurso que puede no estar disponible. quemos con ms profundidad el tema de w)
En este caso el objeto gestiona una varia- las excepciones, cuando digamos que
ble (vase el Listado 1). una funcin genera una excepcin, signi- Este segundo parmetro opcional nos
Alguien puede crear un objeto de la ficar que ese cdigo deber estar rode- permite definir el tipo de acceso que
clase obj_variable y llamar al mtodo ado con una estructura tryexcept. vamos a realizar al fichero. Tenemos
set_variable(23), pero cmo puede estar varias posibilidades: podemos leer (r),
seguro de que la variable var tiene el Trabajo con Ficheros escribir (w), aadir al final del fichero
valor 23 despus de la llamada? Puede Ya que hemos conseguido cierta soltura (a) y tambin tenemos el acceso de lec-
que var no tuviese el valor inicial de 0, con los conceptos de objetos en Python, tura/escritura (r+w). Disponemos tam-
porque otra llamada anterior ya podra ahora vamos a ver cmo se manejan los bin del modificador b para indicar
haberla asignado. Lo nico que podra- accesos a ficheros en l. acceso binario. Por defecto, Python con-
10 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Ficheros INTRODUCCIN
sidera todos los ficheros de texto. Vemos la cadena hasta el EOF. En cambio, si y cuando la funcin fuese a borrar el
todas las combinaciones en el Listado 4. slo leemos el EOF, entonces obtenemos directorio dos, se encontrara con que
Si todo ha ido bien, con cualquiera de una null. Esto es importante para com- no puede porque existe dentro de l un
estas llamadas tendramos en archivo un probar que hemos acabado con el directorio llamado cuatro y parara.
objeto que gestiona el archivo indicado. fichero. As, un bucle que escriba por Imaginemos ahora que necesitamos
Ahora podemos operar sobre l. pantalla el contenido del fichero compro- cambiar el directorio en el que estamos
Las operaciones ms tpicas son las de bara en cada vuelta si la cadena que trabajando. En el momento de arrancar
leer desde el archivo y escribir en l. Para devuelve readline() es null. el programa, el llamado directorio de
ello, el objeto file dispone de los mtodos Ahora que ya sabemos crear archivos, trabajo es decir, el directorio donde de
read(), readline(), write() y writeline(). tenemos que aprender a borrarlos. Esto manera predeterminada se realizarn
Todos ellos operan con cadenas de carac- se realiza mediante la funcin remove() todos los cambios es el directorio que
teres: readline() y writeline() trabajan de la librera os. Esta funcin acepta la alberga el programa o bien el directorio
con lneas de texto (acabadas en retorno ruta de un fichero y lo borra. Si en lugar desde el que se ejecut. Pero, claro, no
de carro), mientras que read() y write() de un fichero le pasamos un directorio siempre querremos que el programa uti-
lo hacen con cadenas sin restricciones. elevar una excepcin OSError. lice ese directorio.
Lo que vemos en el Listado 5 son Hay que tener en cuenta que, a no ser
algunas manipulaciones sobre un >>> import os que utilicemos rutas absolutas, cualquier
fichero. Lo primero que tenemos que >>> os.remove (texto.txt) referencia a un fichero se tomar con
hacer es crear el fichero, para lo cual lo >>> relacin al directorio de trabajo inicial.
abrimos en modo de escritura, w, que lo Para poder cambiar el directorio de tra-
crear o truncar el existente (lo borrar Directorios y Sistema de Ficheros bajo, el mdulo os tiene la funcin
para crearlo de nuevo. Si lo hubiramos Con estos pocos mtodos tenemos ya a chdir(). Si lo invocamos dentro de nues-
querido aadir al final, habramos usado nuestro alcance la manipulacin bsica tro programa:
a). Posteriormente escribimos en l una de ficheros. Pero vamos a necesitar para
cadena con un retorno de carro en mitad nuestro programa la posibilidad de crear >>> os.chdir(/tmp)
(para hacer nuestras pruebas) y cerra- directorios. Cmo lo haremos? Pues
mos el fichero. Es importante cerrar los mediante la funcin mkdir(), que acepta Desde ese momento, cualquier referencia
ficheros cuando dejemos de usarlos, una cadena y crea un directorio con ese a un fichero ser direccionada a /tmp.
pero en este caso la razn para cerrarlo nombre. Si queremos crear un directorio Ahora podemos:
es que vamos a volver a abrirlo en modo que est dentro de otros directorios tam- abrir, cerrar, modificar ficheros
de lectura. bin nuevos tenemos que usar make- crear, eliminar un directorio
Ahora volvemos a abrir el fichero en dirs(). Ambas funciones pertenecen al cambiar el directorio de trabajo
modo de lectura, y leemos 4 bytes que mdulo os, por lo que para usarlas ten- Vamos a ir un poco ms all.
almacenamos en la variable cadena. dremos que hacer:
Cuando leemos con read(), avanzamos Llamadas a Otros Programas
en el fichero, siendo esta la razn de que >>> import os A veces es ms sencillo usar una utilidad
readline() que viene a continuacin lea >>> os.mkdir(uno) del sistema operativo que crearla noso-
la cadena mundo\n en lugar de Hola >>> os.makedirs(dos/tres)
mundo. Tambin vemos que se para en Listado 2: Uso de Excepciones
el retorno de carro en lugar de continuar. Para borrar esos directorios usaremos las
01 class Var_Asignada(Exception):
El segundo readline() ya nos permite funciones rmdir() y removedirs(). La pri-
02 Excepcin que se dispara al
leer la cadena Adis mundo. mera borra un directorio, mientras que intentar asignar una variable ya
Pero qu ocurrira si en una de las la segunda borra una ruta de directorios. asignada en obj_variable
03 pass
lecturas nos encontrsemos con el fin de Vamos a ver esto con ms detenimiento.
04
fichero? En el caso de que leysemos una 05 class obj_variable:
cadena con el fin de fichero (EOF), al >>> os.rmdir(uno) 06 Administra una variable
final simplemente nos quedaramos con >>> os.removedirs(dos/tres) 07 def __init__(self):
08 self.var = 0
09
Listado 1: Una Clase Python rmdir() borrar el directorio uno, que
10 def set_variable(self, valor):
no contiene ningn otro objeto en su
01 class obj_variable: 11 if (self.var == 0):
interior (ni directorios, ni ficheros). En 12 self.var = valor
02 __init__(this):
03 var = 0 caso de tenerlo, la llamada devolvera un 13 else:
04 error. La funcin removedirs() comenza- 14 raise Var_Asignada
05 set_variable(this, valor): ra a borrar desde el directorio que est 15 def reset_variable(self):
06 if (var == 0): ms a la derecha de la ruta (tres) hacia 16 self.var = 0
07 var = valor el que est ms a la izquierda (dos). 17
08 18 a = obj_variable()
Pero imaginemos que dentro de dos
09 reset_variable(this): 19 a.set_variable(12)
10 var = 0 tambin hay un directorio cuatro. 20 a.set_variable(34)
Entonces se borrara el directorio tres,
12 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Ficheros INTRODUCCIN
Listado 6: Agarrafotos.py
001 #!/usr/bin/python 064 os.makedirs(componentes[0])
002 065 os.chdir(componentes[0])
003 # ---NOTA-------------------------------------- 066 print Creando directorio + componentes[0]
004 # El fichero que debe ser pasado como argumento 067
005 # debe consistir en un listado con una url por 068 def descarga_urls(lista):
006 # lnea. 069 # Recorre la lista de urls usando el objeto
007 # --------------------------------------------- 070 # Lista_URLs, las descarga y despus las
008 071 # guarda en ficheros con el mismo nombre que
009 class Lista_URLs: 072 # el de la imagen.
010 Recibe un fichero y carga sus cadenas en una 073
lista. Provee de mtodos para obtener de nuevo las 074 lista.rebobina()
cadenas desde la lista.
075
011
076 while( not lista.fin() ):
012 def __init__(self,nombre):
077 url = lista.siguiente()
013 # La lista donde guardaremos las URLs
078
014 self.lista= []
079 # dividimos la url en dos partes
015 # El contador que usaremos para comprobaciones
080 # lo que descargamos y la url http
016 self.contador = 0
081
017
082 # Componentes es una lista que contiene
018 # pasamos el nombre del fichero menos el ltimo 083 # las cadenas resultantes de trocear la
carcter
084 # cadena de texto de la URL usando /
019 self.archivo = file(nombre)
085 # como separador. Por ejemplo:
020 self.cadena = self.archivo.readline()
086 # http://www.python.org/index.html
021
087 # componentes = [http:, , www.python.org,
022 while(self.cadena != \n):
088 # index.html]
023 #Metemos la cadena en la lista
089 componentes = url.split(/)
024 self.lista.append(self.cadena)
090 servidor = componentes[2]
025 self.cadena = self.archivo.readline()
091
026 self.archivo.close()
092 # Construimos la ruta de la imagen, que
027
093 # consiste en toda la ruta si eliminamos
028
094 # al servidor y a http://
029 def rebobina(self):
095 ruta_imagen = /
030 # Hace que se comience de nuevo
096 for i in range( 3, len(componentes)):
031 # por el principio en la lista.
097 ruta_imagen = ruta_imagen + / + componentes[i]
032 self.contador = 0
098
033
099 # Descarga el fichero y lo guarda con el nombre.
034
100 # El nombre se saca de la URL.
035 def siguiente(self):
101 # url[:-1] es la cadena url menos el ltimo carcter.
036 # Devuelve el siguiente elemento o
102 print Descargando imagen: + url[:-1]
037 # en caso de llegar al final.
103 conexion = httplib.HTTPConnection(servidor)
038 if ( self.contador >= len(self.lista)):
104 conexion.request(GET, ruta_imagen)
039 return
105 respuesta = conexion.getresponse()
040 else:
106 # datos contiene ahora la imagen y la guardamos
041 self.valor = self.lista[self.contador]
107 datos = respuesta.read()
042 self.contador = self.contador + 1
108 conexion.close()
043 return self.valor
109
044
110 # el nombre del fichero es el ltimo elemento
045 def fin(self):
111 # de la lista componentes
046 # Comprueba que hemos llegado al final
112 nomb_fichero = componentes[len(componentes) -1]
047 # de la lista. Preguntamos si hemos llegado
113 # eliminamos el \n final
048 # al final antes de avanzar.
114 nomb_fichero = nomb_fichero[:-1]
049 return (self.contador == len(self.lista))
115
050
116 # Abrimos el fichero, escribimos y cerramos
051 def crea_directorio(cadena):
117 archivo = file(nomb_fichero ,w)
052 # Comprueba si el directorio especificado por
118 archivo.write(datos)
053 # cadena existe, en caso contrario lo crea
119 archivo.close()
054 # y cambia el directorio de trabajo
120
055 # al directorio creado.
121 def genera_index(lista):
056
122
057 componentes = cadena.split(.)
058 123 # Crea un fichero index.html.
059 if(os.path.exists(componentes[0])): 124 # Genera la cabecera, recorre la lista de URLS
060 print Error: el directorio ya existe 125 # y por ltimo escribe el pie.
061 sys.exit() 126 # Es posible mejorarlo introduciendo separadores
062 else: 127 # o ttulos entre las imgenes ;)
063 # Creamos el directorio 128
W W W. L I N U X - M A G A Z I N E . E S PYTHON 13
INTRODUCCIN Ficheros
Una vez que hayamos acabado de leer Leer las URLs. con un objeto. Es en este momento
el fichero, lo cerraremos y entraremos Crear Directorio y cambiar el directo- cuando se deja al lector que explore la
en la segunda parte del programa. rio de trabajo. posibilidad de sustituir el objeto por una
Crearemos un directorio con el nom- Descargar las URLs. variable global y las funciones de lista.
bre del archivo que nos hayan dado. Generar el archivo HTML. Este programa es muy simple, pero de
Cambiaremos el directorio de trabajo a Seguiremos estos puntos para crear las nuevo retamos a los lectores a mejorarlo
ese directorio. funciones. Las URLs las almacenaremos y a introducirle, por ejemplo, control de
Descargaremos cada una de las URLs en una lista. Deberamos usar objetos? excepciones.
dentro del directorio. Esta es una de las cosas maravillosas que Suerte.
Generaremos un archivo index.html ofrece Python: NO estamos obligados a
que muestre las imgenes. usar objetos. Y no digo que los objetos Recursos
Mucho trabajo? Para eso estn los pro- sean malos, sino que en ocasiones pue-
[1] La infraestructura Django para aplica-
gramas. Evidentemente no realizaremos den llegar a ser engorrosos. Por ejemplo, ciones web:
todas las comprobaciones que seran podramos crear un objeto Lista_URLs https://www.djangoproject.com/
necesarias, ya que en tal caso el pro- que aceptase como parmetro en su
[2] El programa administrador de listas
grama se alargara demasiado, por lo que constructor el nombre de un fichero y de correo Mailman: http://www.gnu.
se deja al lector la opcin de incluir que despus nos permitiese ir cogiendo org/software/mailman/
mejoras. Pensemos ahora en su diseo. las URLs una detrs de otra. Tambin
[3] El programar para administracin de
Tenemos varias partes: podemos hacer lo mismo usando una Torrente BitTorrent:
Comprobar y almacenar la opcin con funcin que cargue las URLs en una http://bittorrent.com/
el nombre del archivo. variable global. Aqu vamos a hacerlo
14 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Debugging INTRODUCCIN
ser nuestro peor enemigo. Veamos cmo podemos emplear herramientas para derrotarlo
Equivocarse es humano, y a pesar de pesada la programacin en otros lengua- programas Python, y en particular a la
todo el mito que rodea a los programado- jes como por ejemplo C. Pero no todo el que viene de serie con Python: el PDB,
res, hasta el mejor de ellos comete erro- monte es organo. Tambin hay una Python DeBugger (podemos ver la docu-
res diariamente. En muchas ocasiones es parte negativa: Python no es un lenguaje mentacin de PDB en el Recurso [3]).
mucho ms complicado eliminar un BUG demasiado estricto. Podemos hacer lo
que crear el propio programa. Cuenta le que queramos con las variables sin que Un Bug, Dos Bugs, Tres Bugs
leyenda que el nombre de BUG viene de el intrprete se queje hasta el ltimo Los lenguajes dinmicos, como deca-
la misma palabra que en ingls significa momento. Esta caracterstica impide la mos antes, tienen sus propias virtudes y
bicho. Dicen que los primeros ordenado- posibilidad de verificar automticamente desventajas. Los programadores ms
res eran grandes mquinas que genera- todo el cdigo en el momento en que es duros suelen decir que programar con
ban gran cantidad de calor, por lo que compilado. Un cdigo totalmente err- lenguajes dinmicos es como jugar con
innumerables insectos y otras alimaas neo, en el que por ejemplo se suman juguetes: no hay bordes cortantes con
se introducan en ellos. De vez en letras y nmeros, puede pasar desaperci- los que cortarse ni partes pequeas con
cuando, alguno tocaba dos cables y que- bido en nuestro programa hasta el da las que atragantarnos. Vamos, que son
daba frito, provocando un fallo en el sis- que se ejecuta y genera un error que poco menos que una versin infantil de
tema. Actualmente se conoce como BUG dejar al usuario con la boca abierta, y los lenguajes serios. Lo cierto es que
a todo error o situacin no controlada ciertas dudas sobre nuestra vala como hay mucha gente que no entra en estos
que impida a un programa realizar tu programadores. debates. Yo, por lo menos, prefiero hacer
tarea con normalidad. Lo cierto es que Casi a la vez que surgieron los lengua- un programa tan rpido como sea posi-
estamos bastante acostumbrados a que jes de programacin aparecieron unos ble y espero que funcione casi a la pri-
los BUGS sean parte de nuestra vida. programas que han ido unidos a ellos: mera.
Ventanas que no se cierran, programas los debuggers. Exiten muchos debuggers De dnde salen los BUGS? Lo ms
que consumen todo el espacio en memo- diferentes. GNU desarroll DDD, pero probable es que haya siempre una varia-
ria o videojuegos que se quedan blo- hace tiempo que no se ve actividad en ble implicada. La explicacin es simple:
queados. este proyecto (ver Recurso [1]). Valgrind las variables son la nica parte del pro-
Python es un lenguaje dinmico, como ha conseguido mucha fama en proyectos grama que realmente no controlamos.
muchos otros. La principal ventaja es que emplean C++ ( ver Recurso [2]). Mientras el resto del cdigo hace exacta-
que nos permite programar a alto nivel, En este artculo vamos a echar un vis- mente lo que le indicamos que haga, por
desentendindonos de toda la gestin de tazo a las herramientas que podemos ejemplo abrir un fichero, en las variables
recursos a bajo nivel que hace tan usar para localizar los fallos en nuestros suceden todo tipo de cosas mientras el
W W W. L I N U X - M A G A Z I N E . E S PYTHON 15
INTRODUCCIN Debugging
16 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Debugging INTRODUCCIN
(Pdb) h l
l(ist) [first [,last]]
List source code for the current
file.
Without arguments, list 11 lines
around the current line Figura 3: El depurador de IDLE.
Figura 2: IDLE no es bello, pero es prctico. or continue the previous listing.
With one argument, list 11 lines (Pdb) s
Muy bien, el PDB comienza a hacer su starting at that line. > /home/josemaria/p.py(7)
trabajo. En lugar de no hacer nada, como With two arguments, list the given vacaciones()
hara la funcin vacaciones() si el pro- range; -> for i in range(1,31):
grama se limitase a ejecutarla, entramos if the second argument is less than (Pdb) s
en lo que parece el prompt del shell de the first, it is a count. > /home/josemaria/p.py(8)
PDB. Esta shell tiene sus propios coman- (Pdb) vacaciones()
dos, no tiene nada que ver con Python. -> encontrado = False
Para ver los comandos disponibles pode- El comando l sirve para mostrar visual- (Pdb) s
mos emplear el comando h: mente en qu parte del cdigo estamos > /home/josemaria/p.py(9)
en un momento dado; como nos pica la vacaciones()
(Pdb) h curiosidad ejecutamos l: -> max = len(l)
(Pdb)
Documented commands (type help (Pdb) l
<topic>): [EOF] Hemos avanzado 4 pasos y puede que
================================ nos hallamos perdido. Dnde estamos?
EOF break condition disable help Vaya, resulta que no hemos comenzado Qu estamos haciendo? Hacia dnde
list q step w an, por lo que no estamos en ninguna vamos? El comando l resuelve todas
a bt cont down ignore n quit parte. El comando que probablemente nuestras dudas:
tbreak whatis usemos ms a menudo es s Por qu?
alias c continue enable j pues porque es el comando que hace que (Pdb) l
next r u where PDB avance una lnea y la ejecute: 4
args cl d exit jump p return 5 def vacaciones (l):
unalias (Pdb) s 6 cadena =
09 b clear debug h l pp s up --Call-- 7 for i in range(1,31):
> /home/josemaria/p.py(5)U 8 encontrado = False
Miscellaneous help topics: vacaciones() 9 -> max = len(l)
========================== -> def vacaciones (l): 10 k=0
exec pdb 11 while(not(encontrado)
Muy bien, comenzamos a ejecutar el or k<max):
Undocumented commands: trozo de cdigo Python que pasamos a 12 rango = l[k]
====================== pdb.run(). Por el momento no pasa nada 13 inf,sup=rango
retval rv interesante, aunque estara bien ver qu 14 if ((i >= inf) and
contiene la variable l, para ello podemos (i <= sup)):
(Pdb) usar el comando p que hace las funciones (Pdb)
de print:
Buff! estos son demasiados comandos. Ya me sito, acabamos de entrar en el
Como suele ocurrir la primera vez que (Pdb) p l bucle for, avancemos un poco ms:
un principiante en Linux pulsa dos [(1, 3), (6, 10)]
veces tabulador en BASH, lo que vemos (Pdb) s
nos asusta. En este caso no son tantos Efectivamente, l contiene el parmetro > /home/josemaria/p.py(10)U
comandos (en un Linux estndar hay que hemos pasado a la funcin. Ya esta- vacaciones()
miles de ejecutables), pero s ms extra- mos en ruta, as que avancemos unos -> k=0
os. Debuggear es algo que SIEMPRE se cuantos pasos ms: (Pdb) s
hace bajo presin, por lo que todo el > /home/josemaria/p.py(11)U
tiempo que ahorremos es oro. As que (Pdb) s vacaciones()
los creadores de PDB nos ahorran > /home/josemaria/p.py(6) -> while(not(encontrado) orU
segundos reduciendo los comandos a vacaciones() k<max):
letras. -> cadena = (Pdb)
W W W. L I N U X - M A G A Z I N E . E S PYTHON 17
INTRODUCCIN Debugging
18 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Funciones Lambda AVANZADO
s
tyl
ep
Sin
ho
tog
rap
hs
12-
3R
F.c
om
Nombre
Existe un gran misticismo en torno a cin especial, para la que us la letra >>> a = lambda x : x + 1
los conceptos de funcin lambda y al lambda. Las funciones lambda que vere- >>> a(2)
concepto de cierre. Siempre que aparece mos comparten slo algunas de las 3
un nuevo lenguaje de programacin caractersticas que Alonzo defini para >>>
suele venir acompaado de una discu- las suyas, y podemos decir que lo que las
sin que demuestra que el nuevo len- define es que son annimas: las funcio- Recordemos que en Python las variables
guaje es mejor porque incorpora alguno nes lambda no tienen nombre. no son ms que nombres que asignamos
de estos dos conceptos. Quien est un Cmo es esto posible? Para qu que- a cosas y no contenedores de esas cosas.
poco al tanto de los ltimos avances rramos algo as? Son slo dos preguntas Esta diferencia es vital para comprender
habr escuchado decir que C# incorpora que trataremos de resolver en este art- por qu podemos asignar una funcin a
las funciones lambda y que la prxima culo mientras desmitificamos un con- una variable y posteriormente asignar un
versin java al fin las tendr entre su cepto tan abstracto a primera vista. valor a la misma (ver Figura 1).
arsenal. En este sencillo ejemplo hemos creado
Las funciones lambda reciben su nom- Las Funciones Lambda una funcin que suma el nmero 1 al
bre de la teora del clculo lambda de Las funciones lambda son el concepto nmero que pasemos como argumento.
Alonzo Church [1], que junto a Alan ms sencillo de los que vamos a ver en La definicin de una funcin lambda
Turing, sentaron las bases de la teora de este artculo. Python las soporta desde siempre comienza con la palabra lambda
computacin. Mientras Turing utiliz en hace un buen tiempo, y se encuentran seguida de los argumentos que vamos a
su teora una mquina abstracta e imagi- integradas en la librera base de Python. aceptar. Detrs de los argumentos usa-
naria a la que se llam Mquina de Tambin conocidas como funciones an- mos el smbolo : para separar la defini-
Turing, Alonzo utiliz un enfoque ms nimas, no son ms que funciones sin cin del cuerpo de la funcin. Las fun-
tradicional, creando una serie de reglas nombre que podemos crear en cualquier ciones lambdas, al ser annimas, deben
que permitan realizar computaciones. momento y pasar como argumento a almacenarse en una variable si quere-
Su sistema requera de un tipo de fun- otras funciones: mos reutilizarlas, y se comportarn
W W W. L I N U X - M A G A Z I N E . E S PYTHON 19
AVANZADO Funciones Lambda
como una funcin tradicional a la que >>> d = lambda x,y: x*y 06 self.nombre = nombre
podremos llamar pasndole parmetros >>> d(2,3) 07 self.edad = edad
entre dos parntesis (). 6 08
Existen varias restricciones en el uso >>> 09 def __eq__(self, otro):
de las funciones lambda. La primera es 10 return cmp(self.edad,
que siempre deben devolver un valor. Podemos, de forma limitada, emplear otro.edad)
Son funciones en el sentido estricto de sentencias condicionales, puesto que 11
las matemticas, aceptan valores, los Python nos permite usar la frmula 12 def __lt__(self, otro):
transforman y devuelven algn valor. En if...else como si fuese una expresin: 13 return self.edad <
Python podemos devolver varios valores otro.edad
si lo deseamos: >>> d = lambda x: Yuju U 14
if x > 2 else ooooh 15 def __str__(self):
>>> b = lambda x: (x,x+1) >>> d(2) 16 return self.__repr__
>>> b(2) ooooh 17
(2,3) >>> d(3) 18 def __repr__(self):
>>> Yuju 19 return u({0} tiene {1})
.format(self.nombre,
La segunda restriccin es que slo pue- Pero Para qu Sirven? self.edad)
den contener una expresin. Esta restric- Las limitaciones a las funciones lambda 20
cin limita bastante el poder de las fun- en Python tienen un objetivo bien defi- 21 l = [Edad(Luis, 65),
ciones lambda en Python. En Ruby, por nido: evitar el mal uso que se puede 22 Edad(Juan,28),
ejemplo, las funciones lambda (tambin hacer de ellas. Se restringe su uso a 23 Edad(Montse, 33),]
llamadas bloques) pueden contener tan- aquellas funciones donde es necesario 24
tas expresiones como deseemos. En pasar operaciones sencillas que el dise- 25 print sorted(l)
Python se decidi aadir esta restriccin ador original de una funcin no puede
para que los desarrolladores terminaran predecir de antemano. Por ejemplo, si O bien definimos una funcin que nos
empleando las funciones lambda all queremos ordenar una lista, la funcin permita extraer el valor a comparar de
donde una funcin tradicional podra de ordenacin sorted() intentar compa- los objetos:
valerles (en Javascript es algo que se rar los elementos de la misma usando los
hace habitualmente). Cuando violemos mtodos que existen por defecto. Pero >>> def mi_ordenacion (x): U
una de estas restricciones, Python gene- qu ocurre si los datos a ordenar son return x[1]
rar una excepcin: algo especiales? Imaginemos que tene- >>> sorted(l, key = U
mos una lista de datos donde cada ele- mi_ordenacion)
>>> c = lambda x: y = x+1 mento es un tupla con el nombre y la [(Juan,28),(Montse, 33), U
File <stdin>, line 1 edad de una serie de personas: (Luis, 65)]
c = lambda x: y = x+1 >>>
^ >>> l = [(Luis, 65), U
IndentationError: unexpected U (Juan,28),U O bien podemos emplear una funcin
indent (Montse, 33)] lambda para generar los valores a com-
parar:
En este caso hemos tratado de realizar Cmo podemos indicar a sorted que
una asignacin dentro de una funcin queremos ordenar la lista por edades? El >>> sorted(l, key = U
lambda. Lo que s podemos hacer es diseador de sorted no puede predecir lambda x: x[1])
pasar ms de un parmetro a la fun- todas las posibles estructuras de datos [(Juan,28),(Montse, 33), U
cin: que se pasarn a la funcin. Existen tres (Luis, 65)]
opciones, u obligamos a la >>>
persona que pasa los datos
a encapsularlos en objetos La primera opcin, ms clsica de len-
con un mtodo que nos guajes como Java o C#, y (supuesta-
permita comparar dos mente) ms limpia, tiene un gran pro-
objetos: blema. Qu ocurre si queremos ordenar
los datos de varias maneras diferentes?
01 from functools import El diseador de sorted slo emplear una
total_ordering de ellas. Es un enfoque bastante inflexi-
02 ble, es preferible que la funcin que
03 @total_ordering selecciona el criterio de ordenacin sea
04 class Edad(object): externa al objeto a ordenar. Adems,
05 def __init__(self, como se puede observar, esta opcin es
Figura 1: Las variables en Python son nombres. nombre,edad): bastante ms compleja.
20 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Funciones Lambda AVANZADO
W W W. L I N U X - M A G A Z I N E . E S PYTHON 21
AVANZADO Funciones Lambda
22 PYTHON W W W. L I N U X - M A G A Z I N E . E S
OpenOffice INTEGRACIN
Python no hay
ms que UNO
Has visto alguna vez a los brokers de bolsa? Recuerdas sus sofisticados y caros
programas para ver las cotizaciones de las empresas en bolsa en tiempo real? Nos-
sonas supone ya una locura slo por el Pero los sistemas de componentes
hecho de asegurarse que todos cobren. tambin se emplean en software libre y
Pero vayamos a nuestro mundillo han dado buenos resultados. Quizs el
cmo podemos organizarlos para que ms desconocido es UNO, de Universal
el desarrollo no acabe en un fiasco? Network Objects, el sistema que emplea
Esta es la gran cuestin no resuelta OpenOffice, ver Listado [1], y que SUN
de la informtica, pero, aunque no desarroll para su precursor: StarOffice.
hayamos encontrado una solucin
fiable, s se disponen de tcnicas que PyUNO
aumentan la probabilidad de que, al Un sistema de componentes con el que
menos, se cree algn software til. slo se pueda programar en un
No es ni ser la ltima vez que desde Una de estas tcnicas consiste en lenguaje no tiene mucha utilidad. Por
esta seccin recordemos que la idea ori- emplear un sistema de componentes eso en OpenOffice se han asegurado de
ginal de Stallman era la de que cada como base para el desarrollo. Un com- fomentar la creacin de interfaces a
programa libre estuviese construido ponente es una cantidad de software distintos lenguajes de programacin.
sobre libreras de funciones, de manera que ofrece un servicio bien definido y Podemos acceder a UNO usando
que su cdigo fuese reutilizable por que es reutilizable. Adems debe ser Javascript, Java, Ruby, Perl o Python
cualquier otro programa. posible reutilizarlo de verdad: desde (ver Recurso [2]).
Quizs en un programa pequeo no cualquier lenguaje y cualquier sitio. PyUNO es el nombre de la interfaz y
sea muy til este tipo de diseo, pero Cualquiera que tenga conocimiento podremos encontrarlo sin problemas en
qu pasa con esos monstruos consum- sobre cmo funcionan los lenguajes de nuestra distribucin de Linux. Eviden-
idores de memoria que rondan por programacin a bajo nivel sabr que temente, necesitamos tambin tener
nuestros discos duros? Nos referimos a esto es muy muy complicado. Por ello instalado OpenOffice. En este artculo
programas o entornos del calibre de se han desarrollado infraestructuras hemos realizado los programas usando
Gnome, KDE, Mozilla u OpenOffice. que nos permiten interactuar con los OpenOffice 2.0, que cambi la interfaz
Todo el mundo se queja de su tamao componentes de manera indirecta. A respecto a la versin 1.0, y la versin
excesivo, su alto consumo de recursos este software se le suele llamar mid- de PyUNO 0.7.0.
y su inexplicable complejidad. dleware (algo as como software de
Quizs con este artculo desminta- en medio). Un Ejemplo Rpido
mos este mito y hagamos que el lector Ejemplos famosos de Middleware son Vamos a crear el famoso Hola mundo
mire con nuevos ojos a estos maravi- J2EE, que muchos conocern, y con PyUNO. Para ello primero debemos
llosos programas. CORBA, que a muchos les gustara no arrancar OpenOffice con el siguiente
conocer. Ambos son sistemas enormes comando desde el directorio donde est
Grandes Sistemas de Componentes y costosos que relegan al programador instalado:
El diseo de un gran programa puede a mera herramienta en manos de inge-
llevar aos y cientos o miles de progra- nieros, denominados arquitectos, que $> ./sofficeU
madores. Organizar tal cantidad de per- conocen su compleja infraestructura. "-accept=socket,U
W W W. L I N U X - M A G A Z I N E . E S PYTHON 23
INTEGRACIN OpenOffice
El proceso es el siguiente:
Listado 1: Programa Hola Mundo Obtenemos un contexto local (un
01 import uno sitio donde guardar los datos de la
02 conexin)
03 localContext = uno.getComponentContext()
Arrancamos el componente UnoUrl-
04 resolver = localContext.ServiceManager.createInstanceWithContext
(com.sun.star.bridge.UnoUrlResolver, localContext ) Resolver que nos sirve para acceder
05 ctx = resolver.resolve( uno:socket,host=localhost,port=2002;urp; a otro OpenOffice en otro equipo
StarOffice.ComponentContext ) (en nuestro caso accederemos a
06 desktop = ctx.ServiceManager.createInstanceWithContext( nuestro propio equipo)
com.sun.star.frame.Desktop,ctx)
07 doc = Emplearemos el objeto resolver para
desktop.loadComponentFromURL(private:factory/swriter,_blank,0,()) acceder al OpenOffice remoto
08 cursor = doc.Text.createTextCursor() Arrancamos un Desktop (escrito-
09 doc.Text.insertString( cursor, Hola Mundo, 0 ) rio) de OpenOffice (esto es, una
10 ctx.ServiceManager
instancia de OpenOffice vaca)
Arrancamos un SWriter (es decir, el
host=localhost,U OpenOffice no abre el socket, de ma- procesador de textos) en el escrito-
port=2002;urp;" nera que no podrn controlar nuestro rio
OpenOffice sin nuestro consentimiento. Obtenemos un cursor, con el que
Al arrancar OpenOffice se arranca su OpenOffice incorpora de serie varios podremos posicionarnos dentro del
sistema de componentes. Podemos pen- intrpretes de lenguajes, entre ellos texto
sar en este proceso como en el uno de Python que ya viene preconfig- e insertamos texto en el cursor
arranque de un servidor, slo cuando urado para poder hacer uso de la libr- El resultado, no muy espectacular,
est funcionando podrn los clientes era UNO. Est junto al resto de eje- podemos verlo en la Figura [1]. Ya te-
trabajar con l. cutables de OpenOffice, as que lo eje- nemos nuestro hola mundo insertado
Las opciones que pasamos son para cutaremos desde all. El programa que en SWriter.
que se cree un socket y se escuche en usaremos se encuentra en el Listado Demasiado cdigo? Piensa por un
localhost en el puerto 2002. Por defecto [2]. momento lo que estamos haciendo.
Listado 2: OfficeBroker
01 import uno setString(entrada)
02 import random 27 else:
03 import time 28 self.s1.getCellByPosition(i,fila).setValue
04 import httplib (float(entrada))
05 import csv 29
06 30 i = i + 1
07 class Calc: 31
08 def __init__(self): 32 def getSimbolo(simbolo):
09 self.conecta() 33 c = httplib.HTTPConnection(finance.yahoo.com)
10 34 c.request(GET,
/d/quotes.csv?s=+simbolo+&f=sl1d1t1c1ohgv&
11 def conecta (self): e=.csv)
12 self.local = uno.getComponentContext() 35 r = c.getresponse()
13 self.resolver = self.local.ServiceManager. 36 cad = r.read()
createInstanceWithContext
(com.sun.star.bridge.UnoUrlResolver, self.local) 37 reader = csv.reader([cad])
14 self.context = 38 resultado = []
self.resolver.resolve(uno:socket,host= 39 for row in reader:
localhost,port=2002; 40 resultado = row
urp;StarOffice.ComponentContext)
41 return resultado
15 self.desktop = self.context.ServiceManager.
createInstanceWithContext 42
(com.sun.star.frame.Desktop, self.context) 43 if __name__ == __main__:
16 #self.doc = self.desktop.getCurrentComponent() 44
17 self.doc = self.desktop.loadComponentFromURL 45 simbolos = [GOOG,MSFT,RHAT]
(private:factory/scalc,_blank,0,()) 46
18 self.hojas = self.doc.getSheets() 47 c = Calc()
19 self.s1 = self.hojas.getByIndex(0) 48
20 49 while(1):
21 def actualiza(self, cotizacion, fila): 50 i = 0;
22 51 for s in simbolos:
23 i = 0 52 c.actualiza(getSimbolo(s),i)
24 for entrada in cotizacion: 53 i = i + 1
25 if (i == 0) or (i == 2) or (i ==3): 54
26 self.s1.getCellByPosition(i,fila). 55 time.sleep(10)
24 PYTHON W W W. L I N U X - M A G A Z I N E . E S
OpenOffice INTEGRACIN
Figura 1: Un documento de Write de OpenOffice con el ineludible Figura 2: El programa examina los valores de la bolsa NASDAQ de
Hello World generado a partir de PyUNO. Yahoo a intervalos regulares y los inserta en una hoja de clculo.
Hemos levantado dos componentes y lar ese servicio a algn componente Ahora ya tenemos los datos, tenemos
hecho acceso remoto a otro OpenOf- grfico, como por ejemplo un botn o que mandarlos a SCalc. Hemos creado
fice. Este segundo OpenOffice puede men. un objeto llamado Calc para gestionar
estar en una mquina al otro lado del Comenzaremos por realizar un pro- el acceso. Hemos metido en el mtodo
mundo. Es algo bastante impresionan- grama que funcionar de manera constructor (__init__) el cdigo que
te, pero por el momento poco til. externa a OpenOffice, y despus creare- conecta con OpenOffice, puesto que
Veamos un poco ms sobre UNO antes mos un componente con l y lo inte- slo lo haremos una vez. Una hoja de
de realizar un programa ms til. graremos en OpenOffice. clculo posee varias hojas, as que
tendremos que solicitar una usando el
Arquitectura de UNO Nuestro Programa de Stocks mtodo getSheets(), que nos devuelve
OpenOffice est implementado en Comencemos con la parte til, ver Lis- una lista con las distintas hojas. Dentro
C++. UNO se usa internamente para tado [2]. Vamos a crear un sistema que de esta lista usaremos getByIndex()
realizar cualquier cosa. Bsicamente, nos permita controlar las acciones de para seleccionar la primera hoja, que
OpenOffice no es ms que una gran una serie de empresas que estn en es la que se ve cuando arrancamos
cantidad de componentes que interac- bolsa dentro de un ndice tecnolgico, SCalc.
tan entre s. Todo dentro de OpenOf- el Nasdaq (para algo estamos en una El mtodo actualiza() admite una
fice es un componente, as que revista de informtica), usando la hoja lista con los datos de cotizacin y
podemos acceder a cualquier parte de de clculo SCalc y un programa Python. nmero que representa la fila donde
la aplicacin, incluso reconstruir Nuestro programa acceder usando aparecer en SCalc. Una hoja de clculo
OpenOffice en Python! Internet a un sitio web donde podr se compone de celdas, y stas tienen un
Los sistemas de componentes usan recoger los datos en CSV (Valores Sepa- tipo. La funcin getCellByPosition() nos
un registro de componentes al que se le rados por Comas), los procesar y los permite acceder a una celda pasndole
puede pedir que arranque compo- introducir en SCalc. la columna y la fila (al revs de lo nor-
nentes. El registro localiza el compo- Comenzaremos por crear una fun- mal, as que cuidado).
nente en disco y lo carga en memoria, cin que recoja el fichero CSV y lo pro- Una vez localizada la celda, tenemos
de manera que puede ser usado. Las cese. Lo que hacemos es conectarnos varias funciones para poder asignar un
llamadas a las funciones no se realizan con la pgina web finance.yahoo.com. valor:
directamente, sino que se suele Yahoo tiene un sitio web bastante setString(): para poner una cadena
emplear algn sistema no dependiente avanzado sobre cotizaciones de bolsa, setValue(): para poner un nmero
de lenguaje o plataforma, como puede y uno de sus servicios nos permite setFormula(): para poner una fr-
ser XML o un formato ASCII. recoger los datos de cotizacin de una mula
El registro tambin debe ser capaz de empresa en tiempo real en formato El dato cotizacin es la lista de
gestionar los recursos que consume el CSV. Sin embargo, Yahoo no nos per- parmetros de cotizacin, pero vienen
componente, descargndolo de memo- mitir acceder a los datos demasiado a dados como cadenas de caracteres. Las
ria cuando ya no sea necesario. menudo, ya que dispone de un servi- posiciones 0, 2 y 3 son realmente cade-
Los componentes pueden ser progra- cio de pago para ello, as que puede nas, pero el resto son nmeros. Por eso
mados en cualquier lenguaje con el que cortarnos el grifo en cualquier tenemos que convertir ciertos valores
se tenga interfaz. Un componente es un momento si hacemos demasiadas con- al tipo float() mediante la funcin
conjunto de ficheros que proporcionan sultas por minuto. Por eso recogere- float().
un servicio. Se acompaan de un mos los datos cada 10 segundos. La El resultado se puede ver en la Figura
fichero XML que describe su funcional- funcin getSimbolo() se encargar de [2]. Observamos cmo se abre una ven-
idad. Lo mejor es que podemos vincu- ello. tana de SCalc y se rellena con los val-
W W W. L I N U X - M A G A Z I N E . E S PYTHON 25
INTEGRACIN OpenOffice
ores de las contizaciones, adems de paquetes que OpenOffice admite tienen una entrada de un men Ver Listado
cmo se actualizan cada 10 segundos. una estructura fija. Son ficheros ZIP [3].
Si creamos un grfico que use esos va- que contienen los ficheros con el La sintaxis del fichero parece bas-
lores, se actualizar con ellos. cdigo fuente, recursos (como im- tante complicada, cuando en realidad
Pero este es un programa externo genes) y un fichero de configuracin no es muy difcil de entender. Bsica-
estara bien que pudisemos hacer eso XML. mente decimos que queremos que nue-
pulsando un botn Los ficheros deben tener nombres stro componente se asocie con una
especiales. El fichero de configuracin entrada en el men Addons que est
Creamos un Componente UNO debe llamarse Addons.xcu y permite en Tools o Herramientas en castellano.
Los componentes UNO no son ms que asignar el cdigo fuente del paquete Nuestro componente tiene una ruta que
cdigo debidamente empaquetado. Los con el widget que deseemos, un botn, especificaremos despus y que es:
Listado 3: Addons.xcu
01 <?xml version=1.0 encoding=UTF-8?> 13 <value/>
02 <oor:node 14 <value xml:lang=en-US>Stock Market</value>
xmlns:oor=http://openoffice.org/2001/registry 15 <value xml:lang=es>Cotizacin en Bolsa</value>
03 xmlns:xs=http://www.w3.org/2001/XMLSchema 16 </prop>
04 oor:name=Addons 17 <prop oor:name=Target oor:type=xs:string>
oor:package=org.openoffice.Office>
18 <value>_self</value>
05 <node oor:name=AddonUI>
19 </prop>
06
20 <prop oor:name=ImageIdentifier
07 <node oor:name=AddonMenu> oor:type=xs:string>
08 <node oor:name= 21 <value>private:image/3216</value>
org.openoffice.comp.pyuno.linuxmagazine.Stock
oor:op=replace> 22 </prop>
09 <prop oor:name=URL oor:type=xs:string> 23
10 <value>service:org.openoffice.comp.pyuno. 24 </node>
linuxmagazine.Stock?insert</value> 25 </node>
11 </prop> 26 </node>
12 <prop oor:name=Title oor:type=xs:string> 27 </oor:node>
Listado 4: stock_comp.py
01 import uno 30 model = desktop.getCurrentComponent()
02 import unohelper 31
03 32 self.hojas = model.getSheets()
04 import random 33
05 import time 34 self.s1 = self.hojas.getByIndex(0)
06 import httplib 35
07 import csv 36 simbolos = [GOOG,MSFT,RHAT]
08 37 i = 0;
09 from com.sun.star.task import XJobExecutor 38
10 39 for s in simbolos:
11 def getSimbolo(simbolo): 40 self.actualiza(getSimbolo(s),i)
12 c = httplib.HTTPConnection (finance.yahoo.com) 41 i=i+1
13 c.request(GET,/d/quotes.csv?s=+simbolo+ 42
&f=sl1d1t1c1ohgv&e=.csv) 43 def actualiza(self, cotizacion, fila):
14 r = c.getresponse() 44 i=0
15 cad = r.read() 45 for entrada in cotizacion:
16 reader = csv.reader([cad]) 46 if (i == 0) or (i == 2) or (i ==3):
17 resultado = [] 47 self.s1.getCellByPosition(i,fila).setString
18 for row in reader: (entrada)
19 resultado = row 48 else:
20 return resultado 49 self.s1.getCellByPosition(i,fila).setValue
21 (float(entrada))
22 class StockJob( unohelper.Base, XJobExecutor ): 50
23 def __init__( self, ctx ): 51 i = i + 1
24 52
25 self.ctx = ctx 53 g_ImplementationHelper =
unohelper.ImplementationHelper()
26
54
27 def trigger( self, args ):
55 g_ImplementationHelper.addImplementation( StockJob,
28 desktop = org.openoffice.comp.pyuno.linuxmagazine.Stock,
self.ctx.ServiceManager.createInstanceWithContext (com.sun.star.task.Job,),)
(com.sun.star.frame.Desktop, self.ctx )
29
26 PYTHON W W W. L I N U X - M A G A Z I N E . E S
OpenOffice INTEGRACIN
Yv
on
ne
Les
s-
123
RF.
com
No has encontrado tu lector RSS? Hazte uno t mismo con Jython.
Muchos os preguntaris qu es Jython. que es capaz de generar Bytecode Java idea de su funcionamiento y disponer de
Bien, empecemos desde el principio. Un (aunque s necesitamos tener Java, la API de Java, disponible en la web de
grupo de programadores, Jim Hugunim obviamente). Aunque ciertamente no Sun [2], para saber qu queremos hacer
(su creador) y Guido van Rossum (perso- todo es positivo. Las aplicaciones desa- y cmo lo queremos hacer, pero la sin-
nalidad dentro del mundo de Python) rrolladas con Jython suelen ser bastante taxis y la forma de programar es muy
entre otros, decidieron que la simpleza y ms lentas que las desarrolladas con diferente. Programar en Java sin la API
la limpieza del cdigo de Python hara Java, algo de lo que se quejan muchos de Sun resulta, en la mayor parte de los
que programar en Java fuera perfecto, programadores, pero an as, la potencia casos, imposible. En cambio, para pro-
as que se pusieron manos a la obra y y rapidez de los ordenadores de hoy hace gramar en Jython s es necesario saber
crearon Jython. Jython es la implemen- que apenas se note la diferencia. programar en Python, as pues, damos
tacin de Python en la plataforma Java, Muchos os preguntareis si hace falta por sabido todo lo que hayis aprendido
combinando la potencia de los paquetes saber Java para programar Jython. En en los artculos anteriores de esta
de Java, como JavaBeans, con la facili- principio, no. S es conveniente tener revista.
dad y rapidez de desarrollo de aplicacio-
nes de Python. Recordad que desarrollar Listado 1: Tres Botones
una aplicacin es por lo menos dos veces
ms corto en Python que en Java. 01 import javax.swing as swing 15
02 import java.awt as awt 16 win.contentPane.add(pnl-
Jython posee las mismas caractersti- Botones)
03
cas de Python y adems posee la carac- 17 win.size=(300,300)
04 cuadroTexto =
terstica de poder trabajar con las libre- swing.JTextField(10) 18 win.pack()
ras de Java, de forma que, por ejemplo, 05 19 win.show()
podemos disponer del bonito swing de 06 def __init__(): 20
Java o utilizar JavaBeans e incluso pro- 07 win = swing.JFrame(Ejemplo con 21 def accion(event):
botones) 22 accionBoton = event.getAction-
gramar applets. En la Web de Jython en 08 acciones = [uno, dos, Command()
[1] aparecen algunos ejemplos de tres] 23 if accionBoton == uno:
applets desarrollados en Jython. Esto 09 24 cuadroTexto.setText(UNO)
hace de l un lenguaje muy potente, ya 10 pnlBotones = 25 elif accionBoton == dos:
swing.JPanel(awt.FlowLayout())
que nos ahorramos tiempo, lneas de 26 cuadroTexto.setText(DOS)
11
cdigo y resulta menos engorroso de leer 27 else:
12 pnlBotones.add(cuadroTexto)
que Java. Incluso podemos compilar el 28 cuadroTexto.setText(TRES)
13 for cadaBoton in acciones:
29 root = __init__()
cdigo para no tener la necesidad de 14 pnlBotones.add (swing.JBut-
instalar Jython antes de ejecutar nuestra ton(cadaBoton,actionPerformed=a
ccion))
aplicacin en cualquier ordenador, ya
28 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Java INTEGRACIN
vectores, entre otras cosas. Para el ejem- nador. Podemos usar el Java Runtime
plo de este artculo nos valdremos de Edition (j2re) o el Java Developers
una aplicacin externa ligeramente Kit(j2sdk), en su version 1.4.2 como
modificada (el cdigo original lo encon- mnimo, descargables desde [2]. Adems
traris en la web de xml.com en [3]) necesitamos instalar el intrprete de
desarrollada en Python, para que podis Jython disponible en [1], en su ltima
echarle un ojo al cdigo si os apetece, versin estable (la jython-2.1) y, por
desde la cual parsearemos el xml de un ltimo, para ejecutar nuestra aplicacin,
documento RSS para leer las ltimas deberemos tener instalado el intrprete
noticias de los blogs que ms frecuente- de Python (versin 2.3).
Figura 1: Nuestra utilidad busca-palabras en marcha. mente visitemos. Ms adelante expli- Una vez hemos descargado el intr-
caremos esto detalladamente. prete de Jython, debemos proceder a la
En este artculo aprenderemos a usar instalacin del mismo. Ejecutamos java
elementos bsicos de Java en Jython, Instalacin de Jython jython-21 y nos saldr el instalador
trabajaremos con swing, y usaremos Para trabajar con Jython, necesitamos (Figura 1), que nos pedir confirmar una
algunos objetos de Java como son los tener Java instalado en nuestro orde- serie de opciones y un directorio, y ya
Listado 2: JyRSS.py
001 #!/usr/bin/jython 042
002 043 for cadaBoton in acciones:
003 import javax.swing as swing 044 self.pnlBoton.add(swing.JButton(cadaBoton,
004 import java.lang as lang actionPerformed=self.accionMenu))
005 import java.awt as awt 045
006 import java.util as util 046 def menu(self):
007 import os 047 opciones = [Guardar]
008 048 self.menu = swing.JMenuBar()
009 class Lector: 049 archivo = swing.JMenu(Archivo)
010 def exit(self, event): 050 for eachOpcion in opciones:
011 lang.System.exit(0) 051 archivo.add(swing.JMenuItem(eachOpcion, action-
Performed=self.accionMenu))
012
052 self.menu.add(archivo)
013 def __init__(self):
053
014
054 def listaRSS(self):
015 self.vectorrss = util.Vector()
055 self.lstLista = swing.JList()
016 self.vectorurl = util.Vector()
056 self.jscplista = swing.JScrollPane(self.lstLista)
017 self.listaRSS()
057 self.jscplista.setSize(100,100)
018 self.listaNoticias()
058
019 self.pnlBotones()
059 def listaNoticias(self):
020 self.menu()
060 self.lstNoticias = swing.JEditorPane()
021 if os.path.exists(listarss.txt):
061 self.jscpNoticias = swing.JScrollPane(self.lst-
022 self.leeFicheroRss() Noticias)
023 self.win = swing.JFrame(JyRss, size=(300, 062
300),windowClosing=self.exit)
063 def leeFicheroRss(self):
024 self.win.setJMenuBar(self.menu)
064 f = open(listarss.txt,r)
025 self.win.contentPane.add(self.pnlBoton,awt.Bor-
derLayout.NORTH) 065 fu = open(listaurl.txt, r)
026 self.win.contentPane.add(self.jscplista, awt.Bor- 066 linea = f.readline()
derLayout.WEST) 067 lurl = fu.readline()
027 self.win.contentPane.add(self.jscpNoticias, 068 while linea:
awt.BorderLayout.CENTER) 069 self.vectorrss.add(linea)
028 self.win.setSize(600, 400) 070 self.vectorurl.add(lurl)
029 self.win.show() 071 linea = f.readline()
030 072 lurl = fu.readline()
031 def pnlBotones(self): 073 f.close()
032 self.pnlBoton = swing.JPanel(awt.FlowLayout()) 074 fu.close()
033 acciones = [Agregar,Borrar,Leer] 075 self.lstLista.setListData(self.vectorrss)
034 self.txtUrl = swing.JTextField(10) 076
035 lblNombre = swing.JLabel(Nombre) 077 def leeFicheroNoticias(self):
036 self.txtNombre = swing.JTextField(10) 078 fg = open(news.txt,r)
037 lblUrl = swing.JLabel(Url) 079 texto = fg.read()
038 self.pnlBoton.add(lblNombre) 080 fg.close()
039 self.pnlBoton.add(self.txtNombre) 081 self.lstNoticias.setText(texto)
040 self.pnlBoton.add(lblUrl) 082
041 self.pnlBoton.add(self.txtUrl) 083 def guardarFichero(self):
30 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Ahora vamos a mezclar un poco de cada (Figura 2). Para
ello voy a crear tres botones, a cada uno lo llamaremos de
una forma distinta y les aadiremos un listener (para coger
los eventos que produce cada botn), de forma que al pul-
sar en cada uno, se escriba su nombre en un cuadro de
texto. Veamos cmo se hace esto en el Listado 1.
Es sencillo verdad?, si os dais cuenta, para crear los
botones he usado cdigo propio de Python usando una lista
con los nombres de los botones y crendolos con un bucle
for, dentro del cual llamo al constructor de JButton, pasn-
dole unos argumentos, y aadindolos en el panel mediante
el mtodo .add() que implementa JPanel. Bueno, espero
que os haya gustado el ejemplo, porque ahora viene nuestra
aplicacin en serio.
W W W. L I N U X - M A G A Z I N E . E S
INTEGRACIN Java
direcciones. El vector de nombres se lo Pongo los nombres de las clases y ciones) a la hora de programar.
pasaremos a la ocurrencia JList para paquetes de Java que se van a usar, para Actualmente no he encontrado an
que aada todos los nombres de los que os vayan sonando cuando vayis ninguno que sea exclusivamente para
sitios en pantalla. Usaremos el paquete leyendo el cdigo. As podris buscar desarrollar en Jython. Lo que s existe,
java.lang para implementar la funcin ms rpido en la API de Java y no ten- son plugins que instalamos en otros
de salir de la ventana al pulsar la x de dris problemas para encontrarlas. IDEs y que nos permiten trabajar con
nuestra aplicacin (no se implementa Vuelvo a hacer hincapi en que es nece- este lenguaje. Podemos encontrar dife-
por defecto). sario que lo tengis. rentes plugins para dos de los IDEs ms
De Python, haremos uso del paquete populares, uno para Netbeans (ver [4]),
os, desde el que nos valdremos de Mejoras para JyRSS que os podis bajar desde la aplicacin
os.path.exists() para comprobar si existe Es obvio que a este cdigo le faltan de actualizacin que lleva implementa-
el fichero de nombres al arrancar la apli- muchas cosas, adems de que debe tener da. Y luego tenis otro para Eclipse (ver
cacin y de os.system(), que ejecutar el varios bugs, como por ejemplo que al [5]) llamado Red Robin, que podis
script Python que leer las noticias. ste pulsar el botn Leer cuando no hay encontrar en [6]. Tanto en la web de
guardar las noticias en un fichero, que ninguna url y/o ningn nombre, Java Netbeans como en la web de Red
luego leer nuestra aplicacin. No os lanza una excepcin. Os animamos a que Robin, se explica cmo debemos insta-
preocupis si veis que tarda un poco, eso lo depuris. larlos.
es por dos motivos, tiene que descargar Os sugerimos que le hagis algunas
el fichero de Internet, y adems tiene mejoras, ya que de esta manera os Recursos
que parsearlo, y las libreras que utiliza servir para practicar con el cdigo que
[1] Pgina de Jython:
(minidom) son bastante lentas. os dejamos. Por ejemplo, hacer que el http://www.jython.org
Usaremos tambin las utilidades de cuadro JEditorPane os cambie la aparien-
[2] Descarga de Java:
escritura y lectura de ficheros (open(), cia del texto (negrita, cursiva, etc),
http://java.sun.com
write(), read(), etc) para manejarnos que cada vez que pulsis sobre un nom-
[3] Cdigo original del programa:
con ellos. Podemos ver el resultado en la bre en la JList lea la noticia directamente
http://www.xml.com/lpt/a/2002/12/18/
Figura 3. (deberis trabajar con el listener de dive-into-xml.html
Como vis, programar java con JList), aadir la opcin de guardar las
[4] Plugins de Netbean:
Jython no resulta para nada difcil, al noticias del sitio que ms os gusten,
http://www.netbeans.org
contrario, resulta muy cmodo, y desde etc
[5] IDE Eclipse:
luego mucho mas sencillo que Java. En
http://www.eclipse.org
el Listado 3 encontraris el cdigo Entornos de Programacin Jython
[6] Plugin Jython para Eclipse:
Python de la pequea aplicacin exter- Mucha gente prefiere trabajar con IDEs
http://home.tiscali.be/redrobin/jython/
na. (interfaz para el desarrollo de aplica-
Listado 3: lrss.py
01 from xml.dom import minidom 23
02 import urllib 24 def textOf(node):
03 25 return node and .join([child.data for child in
04 DEFAULT_NAMESPACES = \ node.childNodes]) or
05 (None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0 26
06 http://purl.org/rss/1.0/, # RSS 1.0 27 if __name__ == __main__:
07 http://my.netscape.com/rdf/simple/0.9/ # RSS 0.90 28 import sys
08 ) 29 rssDocument = load(sys.argv[1])
09 DUBLIN_CORE = (http://purl.org/dc/elements/1.1/,) 30 fn = open(news.txt,w)
10 31 Noticia=
11 def load(rssURL): 32 for item in getElementsByTagName(rssDocument,
item):
12 return minidom.parse(urllib.urlopen(rssURL))
33 Noticia = Title: __ + textOf(first(item,
13 title))+ __\n
14 def getElementsByTagName(node, tagName, possible- 34 Noticia = Noticia + Link: \n + textOf(first(item,
Namespaces=DEFAULT_NAMESPACES): link))+ \n
15 for namespace in possibleNamespaces: 35 Noticia = Noticia + Description: \n\n +
16 children = node.getElementsByTagNameNS(namespace, textOf(first(item, description))+ \n
tagName) 36 Noticia = Noticia + \nDate: + textOf(first(item,
17 if len(children): return children date, DUBLIN_CORE))+ \n
18 return [] 37 Noticia = Noticia + \nAuthor: + textOf(first(item,
19 creator, DUBLIN_CORE))+ \n
20 def first(node, tagName, 38 Noticia = Noticia +
possibleNamespaces=DEFAULT_NAMESPACES): ---------------------------------------\n
21 children = getElementsByTagName(node, tagName, pos- 39 fn.write(Noticia)
sibleNamespaces) 40 fn.close()
22 return len(children) and children[0] or None
32 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Ajax INTEGRACIN
Limpieza
Total
AJAX es la palabra de moda, Google usa AJAX, Yahoo usa
W W W. L I N U X - M A G A Z I N E . E S PYTHON 33
INTEGRACIN Ajax
Listado 1: server.py
01 #!/usr/local/bin/python 29 else:
02 30 self.envia_fichero(,404.html)
03 import BaseHTTPServer 31
04 import os 32 def envia_fichero(self,ruta,fichero):
05 import cgi 33 # No usamos ruta, pero as simplificamos el cdigo
06 34 p = Pagina(fichero)
07 class AJAXHTTPRequestHandler (BaseHTTPServer. 35 self.enviar_respuesta(p.tipo(), p.contenido())
BaseHTTPRequestHandler): 36
08 37 def envia_comando(self,ruta,comando):
09 Responde a peticiones HTTP 38 c = Comando(comando)
10 39 self.enviar_respuesta(c.tipo(), c.contenido())
11 def do_GET(self): 40
12 Gestiona los GET 41 def enviar_respuesta(self, tipo, contenido):
13 42 self.enviar_cabecera(tipo)
14 acciones = { 43 self.wfile.write(contenido)
15 / : [envia_fichero,index.html], 44
16 /ps.xml : [envia_comando, ps afx], 45 def enviar_cabecera(self, tipo):
17 /df.xml: [envia_comando, df], 46 self.send_response(200)
18 /who.xml: [envia_comando,who], 47 self.send_header(Content-type,text/ + tipo)
19 /uname.xml: [envia_comando,uname -a]} 48 self.end_headers()
20 49
21 if self.path in acciones.keys(): 50 class Pagina:
22 accion = acciones[self.path] 51 def __init__(self,nombre):
23 (getattr(self,accion[0]))(self.path,accion[1]) 52 self.nombre = nombre
24 else: 53 self.texto =
25 if (self.path[-3:] == .js or 54 fichero = file(self.nombre)
26 self.path[-4:] == .css): 55 self.texto = fichero.read()
27 self.envia_fichero(,self.path[1:]) 56 fichero.close()
28 57
34 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Ajax INTEGRACIN
CSS nos permite otorgar propiedades sin tener que cambiar ninguno de los AJAXHttpRequestHandler, ver Listado 1
visuales a los elementos de HTML. otros elementos. (todos los listados de este artculo pue-
Javascript es el encargado de actuar den descargarse del articulo [4] del cua-
en la mquina cliente, en el navegador, La Parte de Python: dro de Recursos.
y puede modificar tanto el HTML como BaseHTTPRequest Un servidor HTTP recibe distintos
las propiedades visuales que CSS defi- Python dispone en sus libreras estndar tipos de comandos, pero el que nos inte-
ne. Con la llamada XMLHttpResponse de muchos esqueletos para distintos resa es el comando GET. El cual se usa
sus atribuciones se han disparado. tipos de servidores. Entre ellos encontra- para solicitar informacin al servidor.
Ahora se ve como un lenguaje de pro- mos BaseHttpRequest. Esta clase nos Cada vez que se realice una peticin GET
gramacin de pleno derecho. En los permite construir servidores HTTP sin se invocar el mtodo do_GET de
prximos aos puede que adquiera excesivo esfuerzo, as que la empleare- BaseHTTPRequestHandler, as que lo
mucha ms importancia de la que ha mos. vamos a redefinir en nuestra clase.
tenido hasta ahora. Pero no debemos usarla directamente, Cuando se invoque do_GET, en la
XML es el nuevo lenguaje estndar de sino a travs de la clase BaseHttp variable de instancia self.path se encuen-
intercambio de informacin. RequestHandler, que es la encargada de tra la ruta solicitada por el cliente.
Prcticamente cualquier lenguaje dispo- gestionar los eventos que se suceden en Nosotros contrastaremos esta ruta contra
ne ya de libreras para generar y analizar el servidor. Por tanto, heredaremos de las que aceptamos. Si no se encuentra
documentos XML. Dentro del mundillo, ella y crearemos una clase llamada entre ellas, devolveremos la clebre pgi-
AJAX se ha convertido en el estndar
para el intercambio de informacin con Listado 2: Fichero index.html
el servidor y para la serializacin de
01 <html> 14 <input type=button
objetos con protocolos como JSON. name=button value=Disco
02 <head>
Y, como no, Python. En nuestro caso 03 <title>Pruebas con AJAX</title> 15 onclick=javascript:haz
se va a encargar tanto de realizar las Peticion(df.xml); />
04 <link rel=stylesheet
href=estilo.css 16 <input type=button
tareas de servidor HTTP, como de reco- name=button value=Usuarios
type=text/css />
lectar informacin importante y confec- 17 onclick=javascript:haz
05 <script language=Javascript
cionar con ella ficheros XML. Peticion(who.xml); />
06 src=ajax.js>
Tenemos que compenetrar todos estos 18 <input type=button
07 </script> name=button value=Mquina
elementos para realizar nuestro proyec- 08 </head> 19 onclick=javascript:haz
to. El objetivo es que los componentes 09 <body> Peticion(uname.xml); />
HTML, Javascript, CSS y XML sean tan 10 <div id=documento> 20 <div id=contenedor>
estticos como sea posible, debido a que 11 <h3 id=titulo>Informacin 21 <div id=datos></div>
del sistema</h3> 22 </div>
todos ellos interactan con el usuario.
12 <input type=button 23 </div>
Es en el servidor Python donde debe- name=button value=Procesos
24 </body>
mos aportar la flexibilidad necesaria 13 onclick=javascript:haz
Peticion(ps.xml); /> 25 </html>
como para aadir nuevas caractersticas
W W W. L I N U X - M A G A Z I N E . E S PYTHON 35
INTEGRACIN Ajax
36 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Figura 3: Nuestra pgina devolver los resultados de la consulta
sin recargar.
Gestores de Servicios
Para gestionar los servicios se han creado las clases Pagina
y Comando, que responden a los mismos mtodos. La pri-
mera, Pagina, se encarga de las peticiones de ficheros de
texto, que en nuestro programa se reducen al fichero
index.html y sus ficheros supletorios, fichero Javascript y
CSS. Bsicamente, los carga en una variable y, mediante el
mtodo contenido, las dems clases tienen acceso a los mis-
mos. En este caso, el parmetro ruta no afecta a esta clase,
pero se ha definido para que guarde compatibilidad con la
clase Comando.
La clase Comando ejecuta el comando especificado y per-
mite el acceso al texto devuelto por l mismo mediante el
mismo mtodo que la clase Pagina. De esta manera son
intercambiables.
Ambas clases poseen un mtodo tipo() que devuelve el
tipo de fichero que almacenan. En el caso de Comando,
siempre ser un fichero XML, pero Pagina debe adivinar
el tipo de los ficheros que devuelve. Para ello se comprueba
la extensin de los mismos. En aras de la simplicidad, slo
consideraremos tres extensiones.
Cuando un comando es ejecutado por Comando, se tiene
especial cuidado en utilizar la funcin cgi.escape sobre cada
lnea. Esta funcin realiza algunas conversiones dentro del
texto que se le pasa para que pueda ser correctamente
visualizado por un navegador web. El problema radica en
que ciertos caracteres, como pueden ser < or son
especiales y si no se escapan, si no se preceden de un \,
causarn problemas.
Y con esto, hemos definido un servidor web bsico.
Python nos permite realizar complejas tareas con poco cdi-
go y este es uno de esos casos. Vayamos ahora a por AJAX
para comprenderlo.
HTML
Quiz ste sea uno de los artculos donde Python tenga
menor protagonismo, pero con cinco actores suele ser com-
plicado. Veamos el HTML. La pgina index.html se puede
ver en el Listado 2.
W W W. L I N U X - M A G A Z I N E . E S
INTEGRACIN Ajax
Bsicamente, carga un fichero Nos referimos al ahora famoso no est disponible) y entonces obtiene
Javascript, un fichero CSS y muestra un XMLHttpRequest. el documento XML del objeto que gestio-
ttulo junto a unos cuantos botones. Si vemos el cdigo del Listado 3, vere- naba la conexin.
Estos botones invocan acciones en mos un lenguaje que quiz nos recuerda Pero antes invoca a vaciaContenido(),
Javascript. a Java. En realidad no tienen absoluta- que localiza toda etiqueta con las ids
Debemos fijarnos especialmente en el mente nada que ver, aparte del nombre. linea0 o linea1 y las elimina de la
uso del atributo id en numerosas eti- En nuestro ejemplo observamos tres fun- pgina. Hacemos esto porque a conti-
quetas HTML. Gracias a estos ids ciones: nuacin las volvemos a introducir en la
podremos manipularlas mediante hazPeticion() pgina, pero esta vez con los datos fres-
Javascript. modificaContenido() cos del servidor.
vaciaContenido() No queremos entrar en los detalles,
Javascript, desde Otra Perspectiva Javascript, adems de muchas de las ya que, en teora, esto es un artculo
Mucha gente ha tenido extraos encuen- caractersticas presentes en otros lengua- sobre Python, no Javascript, pero bsi-
tros con este lenguaje de programacin. jes (y algunas ausentes) dispone de una camente esto es lo que hace el fichero
Es raro y, hasta hace no demasiado, no coleccin de objetos que le permiten rea- ajax.js.
muy til. Te permita modificar colores lizar operaciones. A da de hoy los ms El fichero estilo.c, que aparece en el
en pginas web o poner insidiosos ban- importantes son: listado 4, simplemente configura los
ners. Por no hablar de las famosas venta- Manipulacin DOM colores y caractersticas de algunas de
nas emergentes. Manipulacin XML las etiquetas para que el aspecto mejore.
Esto ha hecho que se haya ganado una XMLHTTP Y se acab, aqu tenemos nuestra aplica-
fama muy mala, tal es as que casi todos DOM permite a Javascript manipular, en cin AJAX.
tenemos restricciones en nuestro navega- tiempo real, el contenido de la pgina El resultado final ser el que vemos en
dor en torno a qu acciones puede o no web. Puede aadir, modificar o quitar la figura 3. Cuando pulsemos cualquiera
realizar Javascript. Lo ms normal es etiquetas y atributos, por lo que pode- de los botones, se cargar la salida de
que tengamos uno de esos famosos blo- mos operar sobre el documento de cual- texto de la ejecucin asociada a cada uno
queadores de popups. quier forma posible. Javascript puede de ellos en pantalla, pero sin recargar la
Pero Javascript se ha reinsertado en la manipular un fichero XML de igual pgina. Si queremos aadir un nuevo
sociedad de los programadores por la forma que hace DOM. comando, slo tenemos que introducir la
puerta grande gracias a un solo objeto. Y la gran novedad, Javascript puede lnea correspondiente en acciones en ser-
realizar conexiones ASNCRONAS con el ver.py y aadir un nuevo botn como los
Listado 4: Fichero estilo.css servidor. Y resalto en mayscula la pala- que ya existen en index.html.
bra ASNCRONAS porque ah est la
01 #documento{
02 margin-left: 100px; clave. Conclusin
03 } Esto significa que podemos hace cone- Es tan complicado eso de AJAX? Por
04 xiones, traernos documentos XML del supuesto que no! Lo que ocurre es que
05 servidor y realizar operaciones DOM o es una palabra que se est convirtiendo
06 #titulo{ de cualquier otro tipo, cuando quera- en un mito, pero no deja de ser una astu-
07 text-decoration: underline; mos! ta combinacin de programacin en el
08 } El usuario carga su pgina web, y servidor y cliente adems del uso inten-
09
una vez cargada, sin necesidad de sivo de XMLHttpRequest.
10
recargarla, podemos modificarla a Poco a poco AJAX est poblando todas
11
12 #linea0 {
nuestro antojo en base a informacin las pginas webs y la mayora de los
13 margin: 0px; que podemos pedir al servidor en cual- currculos vitae. Quin sabe, lo mismo
14 padding-left: 20px; quier momento. dentro de dos aos esa palabra tenga
15 background: #e0e0e0; Volviendo a nuestras funciones, la fun- tanto poder como otra palabra de cuatro
16 font-family: monospace; cin hazPeticion() recibe una url, crea el letras: J2EE.
17 } objeto XMLHttpRequest y despus de
18 algunas comprobaciones, asigna una Recursos
19 #linea1 { funcin para que sea invocada cuando el
20 margin: 0px; [1] Jesse James Garret define AJAX:
fichero que esa url especifica sea com- http://adaptivepath.com/ideas/
21 padding-left: 20px;
pletamente descargado. ajax-new-approach-web-applications
22 font-family: monospace;
23 } Esto significa que mientras leemos
[2] Explicacin de AJAX en Wikipedia:
24 nuestra web, Javascript estar bajando http://en.wikipedia.org/wiki/AJAX
25 #contenedor{ un fichero y, cuando finalice, llamar a
[3] Sarissa: http://sarissa.sourceforge.net/
26 border-style: dashed; la funcin modificaContenido.
doc/
27 border-width: 1px; Y qu hace esta funcin? Comprueba
28 width: 600px; [4] Listados de este artculo: http://www.
el estado de la peticin, (el estado 200 el
29 border-color: black; linux-magazine.es/Magazine/
de todo correcto y el 404 el de lo sen- Downloads/Especiales/06_Python
30 }
timos mucho, pero el fichero solicitado
38 PYTHON W W W. L I N U X - M A G A Z I N E . E S
.Net INTEGRACIN
De Serpientes
y Primates
.NET est avanzando, y Python no se ha quedado atrs. En lugar de combatirla, ha entrado
en simbiosis con ella. Con Ironpython podremos hacer uso de toda la potencia de .NET desde
bastante del tamos instalarlo. IronPython es una imple- todo aquel que haya trabajado mucho en la
e -
comentario porque mentacin de Python sobre .NET, por lo que consola de Linux, porque Control z sirve
123R
ya haba creado un necesitamos una implementacin de .NET para mandar a un programa a background.
F
W W W. L I N U X - M A G A Z I N E . E S PYTHON 39
INTEGRACIN .Net
40 PYTHON W W W. L I N U X - M A G A Z I N E . E S
.Net INTEGRACIN
para crear aplicaciones grficas. Una vez Calculamos el tamao de la ventana en proceso es repetitivo: texto de etiqueta, posi-
que aadamos las referencias a estas libre- base al de la pantalla. Conseguimos los cin, altura y anchura.
ras, podemos usarlas como cualquier libre- datos de la pantalla mediante el mtodo Finalmente, aadimos la etiqueta al panel
ra de Python. Screen.GetWorkingArea(), y hacemos que y el panel a la ventana (esto ltimo
Importamos todos los widgets necesa- nuestra ventana tenga un quinto de la mediante self.Controls.Add()). Con estas
rios: Application, BorderStyle, Button altura (Height) y ancho (Width) de la ltimas sentencias terminamos de definir
Para hacer referencias a posiciones en la pantalla. Podramos haber indicado el nuestra clase.
pantalla emplearemos la clase Point de tamao mediante un nmero, digamos Para poder hacer uso de ella creamos una
System.Drawing, expresando la posicin en 100 pixels. instancia de HolaMundo y se la pasamos a
pixels. Creamos un panel que pasar a contener Application.Run(), que es un bucle sin fin
Con todas las libreras cargadas, pode- todos los widgets que utilicemos. De nuevo que se dedicar a gestionar los eventos
mos comenzar inicializando nuestra clase ajustamos su altura y anchura, as como su sobre la ventana.
HolaMundo, que representa la ventana de posicin dentro de la ventana. Como quere- La explicacin es bastante ms larga
la aplicacin. Comenzamos dndole mos que ocupe toda la superficie de la ven- que el texto, pero el lector se habr dado
ttulo, con self.Text, a la ventana. Defini- tana lo posicionamos en (0,0), y le damos el cuenta de lo simple que es realmente el
mos el tipo de ventana que utilizaremos mismo ancho y la misma altura que la ven- proceso. Incluso llega a ser aburrido por
con FormBorderStyle indicando que ser tana. He aadido un mtodo, para simplifi- repetitivo.
fijo, nuestra ventana no se podr redi- car el cdigo, que genera una etiqueta Pero hemos logrado nuestro objetivo, rea-
mensionar. donde realizamos el saludo. De nuevo el lizar una aplicacin grfica con un mnimo
W W W. L I N U X - M A G A Z I N E . E S PYTHON 41
INTEGRACIN .Net
42 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Qt INTEGRACIN
Desarrollo
Rpido!
y es necesario resolverlo en tiempo rcord. La desesperacin se palpa en el ambiente y todos los ojos miran a
tu persona. Devuelves una mirada de confianza y dices con tono tranquilo: No te preocupes, tengo un arma
Algunos deciden dejar la habitacin, Posee un entorno de desarrollo rpido cual debemos crear en primer lugar una
otros prefieren quedarse a tus espaldas, de interfaces profesional: designer ventana normal y corriente (llamada en
nerviosos, con los brazos cruzados y la Estas caractersticas hacen de Qt4 una ingls MainWindow), como la que
mirada fija en ti. El problema est claro: librera perfecta para el desarrollo rpido aparece en la Figura 2, y con la que tra-
viene en camino un gran envo, proba- de programas. Adems es una librera bajaremos durante todo el artculo. Por
blemente llegue hoy, con una gran canti- totalmente multiplataforma, podemos defecto viene con un barra de estado y
dad de productos que se deben controlar desarrollar una sola vez y ejecutar donde otra de men, con la que comenzare-
porque en unos das saldrn con destino queramos. mos. Para ello hay que pulsar dos veces
a un cliente. La ltima vez se hizo todo
el proceso con hojas de clculo, pero fue Designer
un desastre. Esta vez quieren estar pre- Una de las ventajas de
parados. Qt4 (ver Recurso [1])
Es necesario desarrollar una aplica- es su designer. Es una
cin y que funcione en menos de 2 herramienta, curtida en
horas. desarrollos profesiona-
Qt4 es la mejor opcin. les, que nos permite
comenzar diseando el
Qt4 aspecto grfico de la
Qt4 es la librera sobre la que se basa el aplicacin. Para ello
escritorio KDE4. Con licencia GPL, es slo tenemos que eje-
una alternativa perfecta para desarrollar cutar el comando
software libre. Posee algunas ventajas designer-qt4, y apare-
envidiables: cer un programa com-
Es muy completa (incorpora cdigo de puesto por distintas
acceso a base de datos, tratamiento ventanas como las que
svg, generacin de PDF) aparecen en la Figura
Es integrada (slo necesitas QT, no 1.
cientos de minipaquetes) Designer sirve para Figura 1: Designer permite crear interfaces de aplicaciones rpida-
PyQT es un proyecto maduro crear ventanas, para lo mente.
W W W. L I N U X - M A G A Z I N E . E S PYTHON 43
INTEGRACIN Qt
mos que Qt4 genere teclas rpidas para cido a lo que podemos ver en la Figura 4.
ellas. Por ejemplo, al poner un & Queda mal, no? Lo ideal sera que ocu-
delante de Archivo hacemos que su pase todo el espacio visible, para lo cual
primera A sirva como tecla rpida, tenemos que asignar un Layout (disposi-
activando el men cuando pulsemos cin) al espacio en el que pondremos
alt-a. El resultado sera el que vemos en nuestro Table View. Hay que pulsar con
la Figura 3. el botn derecho sobre el espacio gris
Vamos a trabajar con datos, as que lo que rodea al Table View, ver Figura 5, y
Figura 2: Nuestro MainWindow vaca y sin mejor que podemos hacer es emplear el pulsar en la ltima opcin del men: Lay
widgets. widget Table View, que nos permite tra- out. En ella escogeremos Lay out Verti-
bajar con datos tabulares y que podre- cally, y nuestro Table View ocupar todo
con el ratn sobre Type Here y escribir mos conectar, ms adelante, con nuestra el espacio.
&Archivo. De esta forma habremos base de datos de forma casi directa. Para Pulsamos dos veces con el ratn sobre
creado nuestro primer men. Dentro de ello tenemos que ir a la ventana principal el Table View y aparecer una ventana
este men introduciremos, de igual de Designer y buscar en Item Views el que nos permitir cambiar su nombre.
forma, la accin &Salir. El smbolo & widget Table View. Debemos arrastrarlo Esto es muy importante, ya que poste-
delante de las palabras indica que quere- hasta la ventana, quedando algo pare- riormente nos referiremos a Table View
44 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Qt INTEGRACIN
W W W. L I N U X - M A G A Z I N E . E S PYTHON 45
INTEGRACIN Qt
46 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Qt INTEGRACIN
W W W. L I N U X - M A G A Z I N E . E S PYTHON 47
INFRAESTRUCTURAS Pyramid
Pyramid
basic_package: A basic U
setuptools-enabled package
paste_deploy: A web application U
deployed through paste.deploy
pyramid_alchemy: pyramid U
SQLAlchemy project using traversal
pyramid_jinja2_starter: U
pyramid jinja2 starter project
pyramid_routesalchemy:U
Uno de los rivales de peso de Django est creciendo en popularidad poco a poco. pyramid SQLAlchemy project using U
url
Por Jos Mara Ruz
dispatch (no traversal)
pyramid_starter:pyramid starter U
Django es el framework que ms est donde vamos aadiendo rutas, vistas y project
contribuyendo a la extensin del uso de (como ya veremos) muchos otros tipos de pyramid_zodb: U
Python. Al igual que ocurri con Ruby y componentes. Configurator es la base sobre pyramid ZODB starter project
Ruby on Rails, Django se ha convertido la que montamos nuestro sitio web.
en una gran baza para la comunidad El concepto de vista es sencillo, al igual Con la opcin --list-templates podemos ver
Python y la excusa perfecta para probar que en Django, pudiendo usarse una funcin los proyectos que paster puede generar.
Python. Est bien documentado, dispone cualquiera que admita como parmetro un Pyramid nos ofrece varias alternativas,
de gran nmero de extensiones y el res- objeto Request con la informacin de la peti- desde la ms tradicional, empleando routes
paldo de grandes empresas por qu cin. Se distingue entre declarar una vista y y sqlalchemy, hasta otras ms exticas here-
querra alguien crear un competidor? emplearla en distintas rutas. Cada ruta tiene dadas de Zope, como pyramid_zodb o pyra-
La comunidad Python dista mucho de ser un nombre, route_name, que nos permite mid_alchemy. La diferencia entre ambas
monoltica, aparecen mltiples alternativas conectarla con cualquier ruta. As, los mto- posibilidades est en la forma en que se
para casi todo. Lo curioso es que el novato en dos add_route y add_view trabajan conjunta- estructuran las urls y en la base de datos a
los frameworks web es Django! Antes de su mente para definir el comportamiento de la usar.
aparicin ya existan otros distintos, y Pyra- web. Zope permite el uso de un sistema llamado
mid es el descendiente directo de algunos de Una vez hemos acabado con la traversal que genera automticamente las
ellos [1]. configuracin, podemos arrancar el servidor. urls empleando para ello las relaciones entre
Para este sencillo ejemplo hacemos uso de la los modelos de datos usados. La mayora de
Un hola mundo Minimalista funcin serve() de paste, que implementa un frameworks web, en casi todos los lenguajes
Podemos instalar Pyramid de muchas for- servidor web en Python que acepta como de programacin, se decantan en su lugar
om
mas, pero la ms cmoda desde el punto de parmetro una aplicacin WSGI, que obtene- por la definicin de las urls de forma expl-
.c
ile
ef
vista de Python consiste en crear un virtua- mos llamando a make_wsgi_app() de Confi- cita, para as tener ms control sobre ellas.
gu
or
m
lenv e instalar en su interior Pyramid: gurator. Nosotros nos conformaremos con el enfo-
Las rutas pueden contener parmetros en que tradicional, por lo que podemos crear el
$ virtualenv --no-site-packages U su interior que podemos capturar de distintas proyecto con:
--distribute pruebas-pyramid formas, como ya veremos.
$ cd pruebas-pyramid Para poder arrancar el servidor slo tene- $ paster create -t U
$ source bin/activate mos que ejecutar el fichero como un pro- pyramid_routesalchemy U
(pruebas-pyramid)$ pip U grama Python cualquiera e ir a la direccin ejemplo
install pyramid 127.0.0.1:8080.
Como resultado obtendremos un directorio
Con estos cuatro pasos dispondremos de un Creando un Proyecto llamado ejemplo que albergar nuestro pro-
virtualenv con las libreras que Pyramid La generacin de cdigo fuente, el llamado yecto, y en su interior un mdulo Python
necesita para funcionar. Es posible crear un scaffolding, es, a da de hoy, un elemento llamado tambin ejemplo. Para poder arran-
proyecto Pyramid con el comando paster (un indispensable de la mayora de los frame- car el proyecto tenemos que generar pri-
proyecto como los que creamos con Django), works web. Pyramid no provee directa- mero un fichero de configuracin e instalar
pero como vamos a generar una primera mente un sistema de scaffolding, lo que ira los paquetes necesarios mediante el
aplicacin minimalista, slo necesitamos en en contra de su poltica de reutilizacin. En comando:
principio un fichero con el contenido que lugar de ello hace uso de paster, un sistema
aparece en el Listado 1. independiente de scaffolding que compar- $ cd ejemplo
A diferencia de Django, Pyramid es un sis- ten otros proyectos. Cuando instalamos $ python setup.py develop
tema bastante estructurado y centrado en Pyramid con pip se instal paster como
componentes. La configuracin se efecta a dependencia, por lo que podemos usarlo Pyramid trae dos configuraciones: develop
travs de una instancia de Configurator, directamente: para desarrollo y production para el entorno
48 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Pyramid INFRAESTRUCTURAS
Renderers, config.include(pyramid_jinja2)
Vistas y config.add_renderer(.html,U
Plantillas pyramid_jinja2.rendererU
Pyramid permite _factory)
configurar dife- config.add_static_view(staticU
rentes renderers , ejemplo:static)
que pueden convi- config.scan()
vir en el mismo config.add_route(portada, /)
proyecto. Por ejem-
plo, podemos con- La llamada a add_renderer() es la que nos
figurar varios siste- permite indicar a Pyramid que las plantillas
mas de plantillas a con extensin .html debern ser renderizadas
la vez (Mako, Cha- empleando Jinja2. Adems llamamos a
maleon, Jinja2,) scan(), que se encargar de buscar las vistas
Figura 1: Pgina por defecto de Pyramid y debug_toolbar. y hacer que Pyra- que definamos y nos ahorrar el tener que
mid seleccione el aadirlas una a una con add_view(), como
de produccin. Cada una aparecer como un correcto basndose en la extensin de la vimos en el Listado 1. Pero para que esto sea
fichero con extensin .ini que nos permitirn plantilla a usar. posible, nuestra vista debe cambiar la forma
configurar el proyecto. Mientras que otros fra- En este ejemplo usaremos Jinja2, un sis- de trabajar; debemos poner el siguiente
meworks, como Django, prefieren que la tema de plantillas muy parecido al empleado cdigo en ejemplo/ejemplo/views.py:
configuracin se haga usando cdigo Python, por Django pero ms flexible y potente. Pri-
en Pyramid decidieron optar por seguir mero tenemos que instalar la extensin de from pyramid.view import U
usando ficheros de configuracin .ini. Pyramid para Jinja2: view_config
Una vez haya finalizado el proceso pode- @view_config (route_name = U
mos arrancar el servidor web con paster: $ pp install pyramid_jinja2 portada, renderer = U
ejemplo:templates/portada.html)
$ paster serve U Una vez instalada debemos indicar a Pyra- def portada(request):
development.ini mid que cargue la extensin y con qu fiche- return {saludo:Hola mundo!!}
ros queremos que use Jinja2 (en nuestro
Podemos ver la pgina generada en la ruta caso los que acaben en .html). Debemos Para indicar el route_name y la plantilla que
http://localhost:6543. Esta pgina incluye a la modificar el fichero ejemplo/ ejemplo/ usaremos en la vista portada usaremos el
derecha una pestaa que nos da acceso al __init__. py, que alberga la configuracin decorador @view_config(). En l podemos
development toolbar de Pyramid, el cual nos para nuestro proyecto, y poner dentro de definir todos los parmetros que necesita
proporcionar informacin muy valiosa main: Pyramid para usar la vista. Con el parmetro
durante el desarrollo de la aplicacin, as renderer indicamos que queremos la plantilla
como enlaces a la documentacin de Pyra- config = U portada.html, que debe estar dentro del direc-
mid. Configurator(settings=settings) torio templates del mdulo ejemplo. Cada
50 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Pyramid INFRAESTRUCTURAS
ms conocidas son FormEncode y FormAl- En el Listado 5 podemos ver el cdigo de mostrar htop como en la url
chemy [5] [6] . En nuestro caso he decidido la plantilla htop.html. En ella cargamos tanto http://127.0.0.1:6543/htop como si se estu-
procesar a mano la peticin. jquery como la librera socket.io.js, que se viese ejecutando en l! Es fcil imaginar las
encarga de establecer un canal continuo de posibilidades de esta tecnologa (ver Listado
Un Ejemplo Ms Potente comunicacin entre el navegador y el servi- 7 para configuracin).
De verdad compensa la flexiblidad que nos dor. Si el navegador soporta websockets, los
aporta Pyramid? Con Django es todo mucho usar, pero en caso contrario tratar de inter- Conclusin
ms sencillo, puesto que las decisiones sobre actuar usando otros mecanismos. Lo mejor Si bien Django es el framework web domi-
qu libreras emplear ya han sido tomadas. de socket.io es que nos permite programar nante en Python, Pyramid puede ser una
Adems, todas las libreras estn controladas toda la interaccin mediante mensajes. alternativa muy interesante si necesitamos
por el proyecto, por lo que su integracin es Cuando recibimos un mensaje showdata, realizar una aplicacin web que no sea tradi-
perfecta. cambiamos el texto de la etiqueta con id htop cional. Su sistema basado en componentes
Personalmente creo que Pyramid por el que recibimos del servidor. Realmente nos da acceso a libreras de alta calidad y
comienza a rendir cuando necesitamos hacer sencillo verdad? No tenemos que ser cons- realmente potentes que normalmente son
cosas que no son tradicionales. Uno de los cientes ni siquiera sobre cmo se recibe el un fastidio integrar. En este artculo slo
problemas de Django consiste en que fue mensaje o cmo se procesa. hemos rascado la superficie de Pyramid
diseado en un entorno muy bien definido: El Listado 6 muestra el cdigo donde real- que cuenta con libreras realmente avanza-
un peridico. Django no se encuentra muy mente ocurre la magia. Creamos una sub- das para autenticacin, por ejemplo pero
bien preparado para el entorno actual, donde clase de SocketIOContext, donde conecta- espero que el lector haya podido dar sus pri-
tecnologas como HTML5 o websockets mos y mandamos un mensaje connected al meros pasos con el framework que no ha
comienzan a ser cada vez ms importantes. navegador remoto. Seguidamente definimos sido construido por aliengenas! [8].
Como ejemplo final de Pyramid vamos a la funcin sendhtop, que ser ejecutada por
crear una pgina que emplear socket.io [7] gevent como si fuese una hebra indepen- Recursos
para mandar datos a nuestro navegador en diente para cada conexin que recibamos.
[1] Pyramid: https://docs.pylonsproject.
tiempo real, lo que definitivamente no es la En dicha funcin ejecutamos htop con dos org/projects/pyramid/dev/
tpica pgina web tradicional. parmetros que le indican que slo nos [2] Pylons: https://www.pylonsproject.
Instalamos las libreras necesarias: muestre el estado de los procesos una vez y org/
pare su ejecucin. De esta manera podemos [3] Turbogear: http://turbogears.org/
pip install gevent U obtener una instantnea de la situacin de [4] Repoze.bfg: http://bfg.repoze.org/
gevent-websocket gevent-socketio nuestro ordenador. La salida de htop la man- [5] FormEncode: http://www.formencode.
damos en un mensaje showdata al navega- org/en/latest/index.html
stas nos permitirn arrancar nuestro pro- dor e indicamos a gevent que espere 1 [6] FormAlchemy: http://code.google.
yecto con un servidor basado en gevent en segundo. com/p/formalchemy/
lugar de usar paster, lo que nos permitir res- Todo esto se ejecutar en un bucle infinito [7] Socket.io: http://socket.io/
ponder a consultas continuadas sin necesi- mientras el navegador est conectado, cosa [8] Pyramid, not built by aliens!: https://
pylonsproject.org/denials/pyramid.
dad de cerrar el canal de comunicacin con que sabremos con el resultado de self.io.con- html
el navegador. nected(). De esta forma nuestro navegador
W W W. L I N U X - M A G A Z I N E . E S PYTHON 51
INFRAESTRUCTURAS Django
Guitarrazos
Los creadores del proyecto Django nos hablan de la formacin de la Django Software Foundation. Y
mostramos cmo comenzar con esta infraestructura web. Por Frank Wiles
En el verano de 2005 surgi en el mundo (tenemos entendido que Google lo usa tam- Comencemos
del cdigo abierto un nuevo web framework bin internamente en algunas tareas). La publicacin de la versin 1.0 oficial de
[1]. Slo tres aos despus desde su publi- Django es, adems, la fundacin del gestor Django se produjo el da 2 de Septiembre de
cacin, Django tiene ya el suficiente atrac- de contenidos comercial Ellington, usado en 2008, tal y como estaba planeado en su hoja
tivo como para alentar la formacin de la varias organizaciones de gran tamao del de ruta.
Django Software Foundation [2]. Con la for- mundo de las noticias, como por ejemplo el Siempre podemos obtener, usando Sub-
macin de la DSF, Django pasa a formar Washington Post. version, el cdigo ms reciente:
parte de una impresionante lista de proyec- Jacob Kaplan-Moss, presidente de la
tos con fundacin propia, entre los que se Django Software Foundation y uno de los svn checkout U
encuentran Apache, Perl y Python. creadores de Django, dijo que la fundacin http://code.djangoproject.com/U
fue creada con el fin de que el proyecto svn/django/trunk/
Qu es Django? pudiese dar el siguiente paso en su ciclo de
Django es un framework para el desarrollo vida como proyecto de cdigo abierto. Independientemente de la versin que use-
web con Python. Se trata de un juego de Obviamente hemos tenido xito a la hora mos, la instalacin de Django es muy senci-
libreras que permiten al desarrollador tra- de atraer a una comunidad grande, vibrante, lla. Estando conectados a Internet, ejecuta-
bajar en las partes de una aplicacin que por lo que sentimos que era hora de que mos como root:
verdaderamente importan sin tener que pre- Django perteneciese a la comunidad. Con
ocuparse por la infraestructura subyacente. la fundacin se garantiza su perpetuidad, python setup.py install
Django usa el patrn MVC como otros incluso aunque algunas personas o algunas
muchos frameworks (Ruby on Rails y los compaas perdiesen inters, coment. para instalar Django en el directorio site-
distintos frameworks en Perl y PHP). Kaplan-Moss seala que el proyecto packages o donde sea que tengamos la ins-
Una de las funcionalidades punteras de acepta ahora donaciones para mejorar talacin de Python. En nuestro ejemplo usa-
Django es su increble interfaz de adminis- Django y, en un futuro prximo, la fundacin remos SQLite como base de datos. De todas
tracin, que se construye automticamente soportar Django mediante reuniones de formas, Django soporta perfectamente Post-
para nosotros. En este artculo recorremos desarrolladores, mtines y otras actividades gresSQL y MySQL.
los pasos necesarios para la creacin de una comunitarias. Muchas de estas reuniones de Para usar SQLite, instalamos el paquete
pequea aplicacin de tipo Twitter, con la desarrolladores han tenido lugar antes de la pysqlite2 [5] y seguimos las instrucciones de
que veremos en accin esta interfaz de publicacin de Django 1.0 -- y Kaplan-Moss la instalacin.
administracin. comenta que la fundacin ayudar a que las Django distingue entre proyectos y aplica-
Son muchos los sitios web de alto nivel personas ms indispensables puedan colabo- ciones. Por ejemplo, si hicisemos un sitio
que emplean Django en su desarrollo [3], rar al tiempo que asisten a las reuniones. Si web de gran tamao, con una seccin for-
como EveryBlock.com, Pownce.com o Tab- la fundacin ayuda a Django a avanzar, aun- mada por un blog, un foro o comercio
blo.com. Adems, es el framework predeter- que slo sea un poco ms rpido, con eso me online, entonces el sitio en s sera el pro-
minado incluido en el AppEngine de Google bastar, dijo Kaplan-Moss. yecto, mientras que el blog, el foro y el e-
52 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Django INFRAESTRUCTURAS
Figura 1: La interfaz de administracin de Django. Figura 2: Para aadir informacin a nuestra aplicacin personal.
comercio seran las aplicaciones. En realidad pleta a miprueba/prueba.db, el archivo de definimos el mtodo especial __unicode__,
slo es una forma de organizar los subpro- SQLite en el que vamos a guardar nuestra que le dice a Model cmo mostrar una ins-
yectos dentro del proyecto general. base de datos. La ruta completa depende del tancia del objeto en formato de cadenas (en
Para iniciar un nuevo proyecto ejecuta- directorio en el que hemos ejecutado el este caso, slo imprime la fecha y la entrada
mos startproject inicial. Aadimos dos elementos completa). Esta ser la informacin que
a la lista INSTALLED_APPS: django.con- usar el admin en el momento de mostrar
django-admin.py startproject U trib.admin para la interfaz de administra- los listados con las entradas de la base de
miprueba cin y la aplicacin miprpueba.Prueba, ase- datos. La clase vaca Admin indica a Django
gurndonos de que aadimos las comas. que queremos hacer uso de la interfaz de
con lo que se crea el directorio miejemplo Despus de definir qu base de datos administracin.
con unas pocas herramientas y archivos de vamos a usar, tenemos que construir nues- Para comprobar lo que llevamos hecho,
configuracin predeterminados. Luego tro modelo (Model), que es un objeto de validamos los modelos mediante:
necesitamos que Django genere los de la Python que define las tablas y columnas de
aplicacin, que llamaremos Prueba. Para SQL y su relacin. Puesto que la aplicacin python manage.py validate
ello, ejecutamos desde el directorio slo va a tener una tabla, slo definimos
miprueba: una clase. El archivo miprueba/Prueba/ Si todo est bien, debera devolvernos 0
models.py debera parecerse al que se mues- errors found. Django ya puede montar las
python manage.py startapp Prueba tra en el Listado 1. tablas de la base de datos. Para ello, introdu-
Primero importamos los asistentes de cimos
En miprueba/settings.py, colocamos DATA- modelo de Django y definimos la clase
BASE_ENGINE = sqlite3 y a Prueba, que contiene una columna de fecha python manage.py syncdb
DATABASE_NAME le ponemos la ruta com- y otra de texto para la entrada real. Luego
Vemos varias lneas con Creating table,
Listado 1: miprueba/Prueba/models.py algunas de las cuales pertenecen a permi-
sos de usuario/grupo, otras a admin y la
01 from django.db import models
ltima para la tabla Prueba. Es ahora
02
cuando Django nos insta a crear el super-
03 class Prueba(models.Model):
usuario para la interfaz de administracin.
04 fecha = models.DateField(Date`)
Debemos recordar el nombre de usuario y
05 entrada = models.CharField( max_length=`500` )
la contrasea, ya que las vamos a necesitar
06
luego.
07 def __unicode__(self):
Despus de crear las tablas para el
08 return %s %s` % (self.fecha, self.entrada)
modelo y la base de datos, habilitamos la
interfaz de administracin. Lo hacemos des-
Listado 2: Invertimos las Entradas comentando las tres lneas del archivo
miprueba/urls.py que se cre al ejecutar
01 from django.shortcuts import render_to_response
startproject. Las tres lneas estn etiqueta-
02 from models import Prueba
das, indicndonos que hay que descomen-
03
tarlas para que se habilite la administracin.
04 def todas_las_pruebas(request):
El archivo urls.py es con el que Django,
05 all_entries = Twit.objects.all().order_by(fecha).reverse()
mediante expresiones regulares, enlaza las
06 return render_to_response(todas_las_pruebas.html,{entradas:
diferentes URLs con las distintas partes de
todas_las_entradas })
nuestra aplicacin.
54 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Thrift INFRAESTRUCTURAS
W W W. L I N U X - M A G A Z I N E . E S PYTHON 55
INFRAESTRUCTURAS Thrift
56 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Thrift INFRAESTRUCTURAS
W W W. L I N U X - M A G A Z I N E . E S PYTHON 57
INFRAESTRUCTURAS Thrift
58 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Curses LIBRERAS
Cuaderno de
Bitcora
Te acuerdas de cuando cambiaste la versin de Firefox por ltima vez? Y de por qu instalaste ese programa tan raro que parece no servir
para nada ? Yo tengo mala memoria, as que uso un cuaderno de bitcora. Por Jos Mara Ruz y Pedro Orantes
Cuaderno de bitcora, fecha estelar tan de inters. Mucha gente incluso publi- consola de texto. Dichos interfaces an se
2123. ca sus ficheros de configuracin, de utilizan en numerosas aplicaciones, la
En todos los libros sobre administra- manera que siempre pueda acceder a razn es que son mucho ms simples de
cin de sistemas se nos recomienda llevar ellos. usar. Es ms fcil automatizar el pulsar
un pequeo cuaderno de bitcora donde Y que ocurre si solo lo queremos para tres veces TAB que mover el ratn y fun-
ir reflejando las acciones peligrosas que nosotros? Y si la mquina a la que esta- cionan mejor remotamente, an con
realicemos. De esta manera, se supone, mos accediendo no tiene un servidor web conexiones lentas.
podremos recrear paso a paso los eventos con el software adecuado configurado Vamos a disear y programar un cua-
que nos llevaron a un desastre y por tanto para tener un weblog? y si no queremos derno de bitcora en Python, que utilizar
ir deshacindolos en orden inverso. montar tanta parafernalia? ncurses para el interfaz texto y dbm para
La cruda realidad es que no todo el Algunas aplicaciones, como KPIM, almacenar las entradas por fecha.
mundo usa dichos cuadernos. Es pesado incorporan ya la opcin de llevar un dia-
tener que dejar el teclado y coger el bol- rio personal, pero no funcionan de forma Diseo del Cuaderno
grafo para escribir a mano! no estba- remota a no ser que tengamos una cone- Comencemos nuestro diseo echando un
mos en la era de los ordenadores? No xin de red con mucho ancho de banda. vistazo a las libreras en que nos vamos a
bamos a desterrar el papel? Qu opciones nos quedan? Podemos basar. ncurses fue desarrollada para abs-
Muchas personas usan un weblog en su volver nuestra mirada a la era antigua de traer, ocultar y simplificar la gestin de
propia mquina o en Internet para ir los ordenadores, cuando los interfaces terminales texto. Cada fabricante dotaba
apuntando detalles o noticias que le resul- funcionaban exclusivamente desde una a su terminal de texto de caractersticas
W W W. L I N U X - M A G A Z I N E . E S PYTHON 59
LIBRERAS Curses
Listado 2: almacen.py
01 #!/usr/local/bin/python 15 contenido = 29
02 self.contenido(clave) 30 def __len__(self):
03 #!/usr/local/bin/python 16 if palabra in contenido: 31 return len(self.entradas())
04 17 encontradas.push(clave) 32
05 import dbm 18 33 def __setitem__ (self, clave,
06 class Almacen: 19 return encontradas valor):
07 def __init__ (self,nombre): 20 34 self.bd[clave] = valor
08 self.bd = dbm.open(nombre,c) 21 def entradas (self): 35
09 22 a = self.bd.keys() 36 def __getitem__(self,clave):
10 def busca_palabra (self, pal- 23 if not a: 37 return self.bd[clave]
abra): 24 a = [] 38
11 claves = self.entradas() 25 return a 39 def __delitem__(self,clave):
12 encontradas = [] 26 40 del self.bd[clave]
13 27 def cierra (self):
14 for clave in claves: 28 self.bd.close()
60 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Curses LIBRERAS
W W W. L I N U X - M A G A Z I N E . E S PYTHON 61
LIBRERAS Curses
Listado 6: cuaderno.py
001 #!/usr/local/bin/python 057 self.decr_pos_fechas() 108
002 # -*- coding: ISO8859-1 -*- 058 self.redibuja() 109 else:
003 059 110 self.scr_fechas.addstr
004 import curses 060 self.refresca() (pos_x,1,fecha_temp, 0)
005 import curses.ascii 061 return 1 111
006 import curses.textpad 062 112 self.scr_fechas.addstr
(pos_x,len(fecha_temp),
007 import time 063 def fecha(self): self.datos[fecha],0)
008 import os.path 064 return time.strftime(%Y-%m-%d 113 pos_x = pos_x + 1
009 import string %H:%M)
114
010 import sys 065
115 self.refresca()
011 import almacen 066 def long_fecha(self):
116
012 067 caja_texto = 2 # el | izquierdo
y el | derecho 117 def editar(self):
013 class GUI: 118 Muestra un cuadro para
068 return len(self.fecha()) +
014 Interfaz con el usuario. caja_texto introducir el texto y lo guarda
015 069 119 if len(self.datos) == 0:
016 def __init__(self,datos): 070 def long_linea_texto(self): 120 return
017 071 return (80 - self.long_fecha()) 121 else:
018 self.registra_comandos() 072 122 self.banner( EDITANDO ! --
019 [control+g] guardar | [q] salir
073 def banner(self, texto): --)
020 self.datos = datos 074 Muestra el texto en la zona de 123 fechas = self.listado_fechas()
021 self.pos_fechas = banner
len(self.datos) - 1 124 texto = self.datos
075 self.scr_info.clear() [fechas[self.pos_fechas]]
022 076 self.scr_info.addstr(texto, 125 self.refresca()
023 self.genera_ventanas() curses.A_BOLD)
126
024 077 self.scr_info.refresh()
127 # Capturamos el nuevo texto.
025 self.banner(-- [n] nueva | [e] 078
editar | [q] salir --) 128
079 def dibuja_fechas(self):
026 129 ncols, nlineas = 25, 4
080 Genera el listado de fechas de
027 self.dibuja_fechas() la izquierda 130 uly, ulx = 15, 20
028 081 131 stdscr.addstr(uly-2, ulx, Usa
Ctrl-G para guardar.)
029 self.refresca() 082 self.scr_fechas.clear()
132 win = curses.newwin(nlineas,
030 083 pos_x = 3 ncols, uly, ulx)
031 def genera_ventanas(self): 084 133 curses.textpad.rectangle
032 Genera las ventanas iniciales 085 # 8 elementos por arriba y abajo (stdscr, uly-1, ulx-1, uly +
033 self.scr_fechas = stdscr. 086 min = self.pos_fechas - 8 nlineas, ulx + ncols)
subwin(23, 80, 0, 0) 087 max = self.pos_fechas + 8 134 stdscr.refresh()
034 self.scr_info = stdscr. 088 135 nuevo_texto=
subwin(1,80,23,0) curses.textpad.Textbox(win).
089 if max > len(self.datos): edit()
035
090 max = len(self.datos) 136 stdscr.refresh()
036
091 min = min + (max - 137
037 def registra_comandos(self): len(self.datos))
038 Almacena la letra y el comando 138 nuevo_texto =
092 if min < 0: nuevo_texto.replace(\n,)
asociado
093 max = max + ( -min) 139 # Guardamos el nuevo texto
039 self.comandos = [[d,bor-
rar], 094 min = 0 140 self.datos[fechas
040 [e,editar], 095 [self.pos_fechas]] =
096 if len(self.datos) > 0: nuevo_texto
041 [n,nueva_entrada],
097 # Marcamos con negrita la fecha 141
042 [q,salir],
sobre la que est el curso 142 self.banner(-- [n] nueva | [e]
043 [s,estado]] editar | [q] salir --)
098 # para ello iteramos escribi-
044 endo las fechas y cuando la 143
045 def ejecuta_comando(self, ch): 099 # encontramos le pasamos el 144 def borrar(self):
046 Procesa las teclas recibidas atributo de negrita 145 Elimina la entrada selec-
047 if curses.ascii.isprint(ch): 100 fechas = self.listado_fechas() cionada
048 for comando in self.comandos: 101 for fecha in fechas[min:max]: 146 if len(self.datos) > 0:
049 if comando[0] == chr(ch): 102 147 fechas = self.listado_fechas()
050 (getattr(self,comando[1]))() 103 fecha_temp = [+fecha+] 148 del self.datos
104 [fechas[self.pos_fechas]]
051 break
105 if fechas[self.pos_fechas] == 149 self.actualiza_pos_fechas()
052 else:
fecha: 150 self.redibuja()
053 if ch in (curses.ascii.DLE,
curses.KEY_UP): 106 # Hemos encontrado nuestra 151 self.refresca()
054 self.incr_pos_fechas() fecha!!! 152
055 self.redibuja() 107 self.scr_fechas.addstr 153 def redibuja(self):
(pos_x,1,fecha_temp ,
056 elif ch in (curses.ascii.SO, curses.A_BOLD | curses. 154 Redibuja la pantalla
curses.KEY_DOWN): A_UNDERLINE) 155 self.dibuja_fechas()
62 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Curses LIBRERAS
El objeto Almacen es pasado a GUI un terminal tiene 80 columnas de ancho y nmero fijo de entradas encima y debajo
como parmetro en su creacin. Y la 25 filas de alto. Dejaremos una fila abajo, de la nuestra. Como tenemos la posicin
misin de GUI no es otra que al de res- que ser la que usemos para mostrar de la entrada seleccionada, o resaltada,
ponder a los eventos que el usuario enve informacin. La 24 filas restantes se con un sencillo clculo podemos selec-
mediante un bucle infinito. encargarn de mostrar las entradas alma- cionar que entradas mostraremos.
cenadas. Las listas en Python tienen una funcio-
Dos ventanas nalidad que nos ser muy til. Usando la
Nuestro programa va a disponer de dos Desplazamiento por las entradas sintaxis lista[comienzo:fin] podemos
ventanas. La mayor har las veces de La ventana de datos nos permitir des- extraer los elementos entre comienzo y
tabln donde podemos ver las anota- plazarnos arriba y abajo por las entra- fin formando una nueva lista.
ciones realizadas por el momento. das. Cmo podemos conseguir recrear Simplemente tenemos que seleccionar
Podremos desplazarnos arriba y abajo por este movimiento? La solucin es captu- aquellos que estn a una distancia fija
l. Para indicar qu fecha es la que tene- rando las teclas de los cursores arriba del seleccionado y usarlos como comien-
mos seleccionada la distinguiremos ilumi- y abajo. Cuando una de ellas se pulse zo y fin.
nndola en negrita y subrayndola. incrementaremos o decrementaremos Podemos ver el cdigo que realiza esta
La segunda venta har las veces de una variable que establece la posicin accin en el mtodo dibuja_fechas(self)
barra de ayuda y estado. Cuando cambie- la entrada seleccionada en cada del GUI en el Listado 6.
mos el estado, por ejemplo al editar, se momento y volveremos a dibujar, o
reflejar ah. Es el mismo modo de trabajo escribir, la pantalla de datos. Pero no lo Textbox
del que hace gala VIM. haremos de cualquier forma. Python provee de una herramienta muy
Las ventanas deben partir la pantalla de Queremos que el efecto sea vistoso, as til para la edicin de textos dentro de
manera que no se solapen. La pantalla de que siempre intentaremos mostrar un curses. Desgraciadamente, a pesar de su
W W W. L I N U X - M A G A Z I N E . E S PYTHON 63
LIBRERAS Curses
potencia posee algunos inconvenientes de tidad de ifs anidados, cada uno de los car. De esta manera, nuestro gestor de
los que hablaremos ms tarde. cuales responde ante una tecla o combi- comandos se reduce a un cdigo que reci-
Esta herramienta es el objeto Textbox nacin distinta. El cdigo generado llegar be un carcter, lo compara con el primero
que se encuentra en la librera curses.text- a convertirse en ilegible en cuanto el elemento de cada entrada en su lista de
pad. Textbox nos permite editar un texto nmero de comandos sobrepasa los diez. comandos y si encuentra una coinciden-
dentro de una ventana y poder utilizar Hay una manera mucho ms elegante cia ejecuta el comando asociado. Ver
muchas de las combinaciones de teclas de atacar este problema, pero no es tan Listado 5.
que soporta EMACS. As por ejemplo con fcil hacer uso de ella en todos los lengua- Como podemos ver en el cdigo, se
control+e iremos al final de la linea jes. Afortunadamente Python nos permite comprueba si el carcter recibido es
que estemos editando y con control+d una implementacin muy sencilla. La imprimible y posteriormente se busca en
borraremos el carcter sobre el que nos idea es la siguiente: Cada comando estar la lista de comandos. En caso de coinci-
encontremos. asociado a una serie de acciones a reali- dencia se ejecuta usando como instancia
Utilizaremos un Textbox para recoger el zar. Englobaremos las acciones vincula- self. De esta manera, es posible manipular
texto que el usuario quiera introducir. das con cada comando a un mtodo de el funcionamiento ante qu caracteres res-
Desgraciadamente posee una limitacin nuestro objeto GUI. Hasta aqu todo es ponde el programa sin tener que modificar
debido su diseo: Si cuando estamos edi- bastante normal. Ahora viene la magia. el cdigo fuente. Esto nos da mucha flexi-
tando el texto, pulsamos repetidas veces Python nos permite invocar mtodos de bilidad y es menos propenso a errores.
el cursor izquierdo desplazndonos hasta objetos usando su nombre. Si declaramos
dar con el borde de la ventana, el progra- el objeto persona: Uso del Programa
ma fallar. El uso del programa se ha hecho lo ms
El soporte de curses de Python se basa >>> class Persona: simple posible, el aspecto del mismo se
en las libreras originales escritas en C, y ... def habla(self): puede ver en la Figura 4. Cuando se pulsa
como ya hemos dicho son de muy bajo ... print "hola mundo" n se crea una nueva entrada con la
nivel. La implementacin de Textbox es ... fecha y la hora, si existe ya una entrada
realmente bsica y no controla todas las >>> con la fecha y la hora no se hace nada.
circunstancias. An as servir. Con d se elimina una entrada y con e
Un ejemplo de utilizacin de Textbox Podemos invocar el mtodo habla usando se edita. Cuando se est introduciendo un
aparece en su propio cdigo fuente, ver una cadena con su nombre mediante el texto, al pulsar control+g se guarda.
Listado 4 y Figura 2. Este cdigo genera mtodo getattr(), que precisa de la instan- Para salir se pulsa q y con los cursores
un rectngulo con bordes (usando la fun- cia del objeto y el mtodo a invocar. arriba y abajo nos desplazamos por la
cin rectangle de curses.textpad) y nos Devuelve, por as decirlo, una referencia lista.
solicita que escribamos algo en el mismo. al mtodo en cuestin que funciona de la Al fichero de almacenado se le ha dado
Para acabar debemos pulsar control+g, misma manera. Como dicen por ah, una el nombre diario.db. Si no existe se
mostrndonos lo escrito ms abajo. Si lo imagen vale ms que mil palabras: crea, y si existe se emplea el existente.
probamos comprobaremos que no pode-
mos salir del rectngulo al editar. >>> pepe = Persona() Conclusin
En la Figura 3 vemos como hemos inte- >>> pepe.habla() Aunque el uso de Curses puede resultar
grado el Textbox en nuestro programa. hola mundo engorroso, Python nos provee de una
Hemos aumentado el nmero de colum- >>> (getattr(pepe, "habla"))() librera que las manipula dentro su insta-
nas para permitir introducir mensajes hola mundo lacin base. Una vez realizado el progra-
ms largos. >>> ma sabremos que cualquiera que instale
Python podr hacer uso de l.
El Gestor de Comandos Lo que haremos ser crear una lista de lis- Siempre es posible realizar una serie de
Existen muchas maneras de hacer un ges- tas, cada una de las cuales contendr dos objetos que realicen tareas de ms alto
tor de comandos. La ms tpica consiste elementos. El primero ser un carcter y nivel. Existen libreras que nos proporcio-
en hacer una sentencia switch o gran can- el segundo el nombre del mtodo a invo- nan barras de mens y widgets ms avan-
zados. An as, siempre es bueno estar lo
Tabla 1: Algunos mtodos especiales de Python ms cerca posible del estndar.
Mtodo Descripcin La prxima vez que tengas que hacer
un interfaz en modo texto puede que sea
__len__(self) devuelve la longitud de nuestro objeto. Se invoca cuando se ejecuta
len(miObjeto) una buena idea darle una oportunidad a
curses.
__setitem(self, clave,valor) se corresponde con la asignacin en un diccionario:
miObjeto[Algo] = otra cosa
Recursos
__getitem(self, clave) es el equivalente miObjeto[Algo] y devuelve la informacin alma-
[1] Descargas de los listados de este art-
cenada en Algo.
culo: http://www.linux-magazine.es
__delitem(self, clave) es del miObjeto[Algo] y se corresponde con la eliminacin de esa /Magazine/Downloads/Especiales/06_
entrada. Python
64 PYTHON W W W. L I N U X - M A G A Z I N E . E S
3D con VTK LIBRERAS
Grficas 3D
una pelcula de animacin, como por
ejemplo La Edad de Hielo. Si nos cen-
tramos en una nica escena y la describi-
mos, vemos personajes animados
(actores), luces de diferentes tonali-
dades, cmaras que modifican el punto
de vista, propiedades de los personajes
(color, forma, etc.). Aunque no lo creis,
Hoy por hoy, la representacin grfica 3D y su visualizacin forman todos estos conceptos son la base de la
visualizacin grfica. Veamos dicha
parte de nuestra vida cotidiana; basta fijarse en el mundo del estructura.
El toolkit de visualizacin VTK est
entretenimiento, en la industria del juego y en el soporte de hard- diseado a partir de dos modelos clara-
mente diferenciables: el modelo grfico y
ware y software para tales fines. Quin en su ordenador personal el modelo de visualizacin.
Modelo grfico. El modelo grfico
no ha instalado un juego o visto una pelcula renderizada en 3D? captura las principales caractersticas
de un sistema grfico 3D, de un modo
Por Ana M. Ferreiro Ferreiro y Jos A. Garca Rodrguez
fcil de entender y usar (ver Figura
1). La abstraccin se basa en la indus-
tria del cine. Los objetos bsicos que
La representacin grfica en 3D ofrece trial, reconstruccin de superficies a par- constituyen este modelo son: vtkRen-
la posibilidad de crear mundos virtuales tir de digitalizacin lser o nubes de derer, vtkRenderWindow, vtkLight,
en un ordenador, lo cual, unido a la puntos desorganizados, etc. vtkCamera, vtkProp, vtkProperty,
visualizacin permite al usuario explorar En lo que sigue veremos los conceptos vtkMapper, vtkTransform. En la Tabla
y entender, rpidamente, sistemas com- bsicos en los que se basa VTK para 1 se describen cada uno de estos obje-
plicados. Esto es posible gracias al poder generar una escena y, mediante tos.
avance de lenguajes orientados a obje- una serie de ejemplos desarrollados en Modelo de visualizacin. El papel del
tos, que ofrecen la posibilidad de crear Python, llegaremos a crear nuestras modelo grfico es transformar datos
software de mejor calidad y ms fcil de propias escenas de visualizacin. grficos en imgenes, mientras que el
mantener. del modelo de visualizacin trans-
Entre las diferentes herramientas de Instalacin forma informacin en datos grficos;
visualizacin, representacin 3D y Para poder realizar todas las pruebas que esto significa que el modelo de visual-
procesamiento de imgenes, cabe se van sugiriendo y las que se os ocu- izacin es el responsable de construir
destacar VTK (Visualization Toolkit), rran, es necesario tener instalado Python la representacin geomtrica que se
cdigo abierto cuyo ncleo est imple- y VTK con soporte para Python. Adems, renderiza mediante el modelo grfico.
mentado en C++ y que soporta la tarjeta grfica de nuestro ordenador VTK se basa en la aproximacin de los
envolturas (wrappers) para TCL, debe tener OpenGL funcionando. datos para transformar la informacin
Python y Java, permitiendo el desarrollo La instalacin de las libreras VTK en datos grficos. Hay dos tipos bsi-
de aplicaciones complejas de un modo (que no suelen estar instaladas de man- cos de objetos, descritos en la Tabla 2,
eficiente y mediante scripts sencillos. Por era predeterminada) es muy sencilla. involucrados en dicha aproximacin:
todo ello, VTK se emplea en la visua- Todas las distros mayoritarias cuentan vtkDataObject y vtkProcessObject.
lizacin mdica, la visualizacin indus- con los paquetes necesarios en sus
repositorios.
En Debian o Ubuntu, por ejemplo,
bastar con ejecutar
W W W. L I N U X - M A G A Z I N E . E S PYTHON 65
LIBRERAS 3D con VTK
Los diferentes tipos de datos que pueden ren=vtk.vtkRenderer() sus botones de minimizar, maximizar y
constituir un objetos son, entre otros, renWin=vtk.vtkRenderWindow() cerrar; y que slo se cierra cuando el
puntos, rectas, polgonos, puntos estruc- renWin.AddRenderer(ren) usuario lo estima oportuno (Figura 3).
turados, mallas estructuradas y no iren=vtk.U Esta ventana va a ser el contenedor de
estructuradas, etc. (ver Figura 2). vtkRenderWindowInteractor() nuestra pequea escena. Ntese que las
iren.SetRenderWindow(renWin) dos lneas de cdigo que acabamos de
Mi Primera Escena escribir deben de estar al final del
Ya estamos preparados para construir Para poder manipular la cmara median- fichero. Las dems lneas que escribamos
nuestra primera escena. Situaros en el te el ratn se ha instanciado el objeto a partir de este momento debemos situar-
papel de director de cine. En los si- vtkRenderWindowInteractor (denomi- las justo antes.
guientes ejemplos veremos el modo de nado en el cdigo como iren). Ntese Para crear nuestro primer actor no nos
emplear las clases que acabamos de que la ventana de renderizado renWin se vamos a complicar demasiado, porque
describir. Para ello, tal como se men- asocia al objeto de interaccin iren medi- ya queremos ver algo. VTK contiene una
ciona al comienzo, instanciaremos VTK ante el mtodo SetRenderWindow. En serie de clases que nos permiten crear
desde Python. este momento no se aprecia la utilidad objetos tridimensionales sencillos, como
Con cualquier editor de textos, del mismo, paciencia ya compren- son: esfera (vtkSphereSource), cono (vtk-
creamos el fichero cone.py. Lo primero deris su importancia cuando tengamos ConeSource), cilindro (vtkCilinder-
es importar desde Python el paquete un actor en nuestra escena. Source), etc. Para nuestro ejemplo hemos
VTK; esto es tan sencillo como escribir la Guardamos el fichero y en la lnea de escogido un cono, sin embargo, puedes
siguiente lnea: comandos ejecutamos el programa tecle- optar por cualquiera de los otros objetos.
ando python cone.py No ocurre nada! El siguiente cdigo nos permite crear
import vtk Esto es porque debemos inicializar la nuestro primer actor,
interaccin del usuario e indicar que la
Ahora que ya podemos instanciar ventana de renderizado permanezca visi- cone=vtk.vtkConeSource()
cualquier objeto de VTK, sin ms que ble hasta que el usuario finalice la ejecu- coneMapper=vtk.U
escribir vtk.nombre_clase, necesitamos cin de la misma cerrndola. Para ello vktPolyDataMapper()
crear nuestra ventana de renderizado basta escribir coneMapper.SetInput(cone.U
vtk.vtkRenderWindow, a la que llamare- GetOutput())
mos renWin y a la que asociamos un iren.Initialize() coneActor=vtk.vtkActor()
rea de renderizado vtk.vtkRenderer (que iren.Start() coneActor.SetMapper(coneMapper)
denominamos ren), mediante el mtodo
AddRenderer(). Escribamos las siguien- Si ejecutamos nuevamente el programa, Mediante el objeto vtk.vtkConeSource
tes lneas de cdigo: se abre una ventana de color negro con creamos una representacin poligonal
Listado 1: cono_esfera.py
01 import vtk 18 esferaActor.SetMapper 34 #Fijamos el color de fondo, el
02 (esferaMapper) tamao y hacemos zoom sobre
03 # Generamos la estructura para 19 esferaActor.GetProperty().Set- 35 #el area de Renderizado
ver un cono Color(0.7,0.0,0.25) 36 ren.SetBackground(1, 1, 1)
04 cone = vtk.vtkConeSource() 20 esferaActor.GetProperty(). 37 renWin.SetSize(450, 425)
05 coneMapper = vtk.vtk SetOpacity(0.75) 38 camera=ren.GetActiveCamera()
PolyDataMapper() 21 esferaActor.GetProperty(). 39 ##camera.Zoom(1.5)
06 coneMapper.SetInput(cone. SetLineWidth(1) 40
GetOutput()) 22 41 coneActor.RotateX(30)
07 coneActor = vtk.vtkActor() 23 # Creamos: Renderer, Render 42 coneActor.RotateY(45)
08 coneActor.SetMapper(coneMapper) Window, RenderWindowInteractor 43 conepro=coneActor.GetProperty()
09 24 ren = vtk.vtkRenderer() 44 conepro.SetColor(0,0.6,1)
10 # C r e a r f u e n t e d e e s f e r a , 25 renWin = vtk.vtkRenderWindow() 45 ##conepro.SetOpacity(0.5)
mapeador y actor 26 renWin.AddRenderer(ren) 46 conepro.SetLineWidth(2)
11 esfera = vtk.vtkSphereSource() 27 iren = vtk.vtkRenderWindow 47 ren.ResetCamera()
12 esferaMapper = vtk. Interactor() 48 ##camera=ren.GetActiveCamera()
vtkPolyDataMapper() 28 iren.SetRenderWindow(renWin) 49 camera.Zoom(1.5)
13 esfera.SetPhiResolution(10) 29 50
14 esfera.SetThetaResolution(20) 30 # Aadimos el actor en el rea 51 cone.SetResolution(40)
15 esfera.SetCenter(0.3,0.0,0.0) de renderizado (Renderer) 52
16 esferaMapper.SetInput(esfera. 31 ren.AddActor(coneActor) 53 iren.Initialize()
GetOutput()) 32 ren.AddActor(esferaActor) 54 renWin.Render()
17 esferaActor = vtk.vtkActor() 33 55 iren.Start():
66 PYTHON W W W. L I N U X - M A G A Z I N E . E S
3D con VTK LIBRERAS
vtkRenderWindow clase que representa el objeto dentro del cual se colocan una o ms reas
de renderizado (vtkRenderer).
vtkLight objeto que permite manipular las luces de la escena. Cuando se crea una
escena, por defecto se incluyen luces.
ren.AddActor(conoActor)
renWin.Render() Prueba a comentar la lnea Habrs observado que la ventana de
renWin.Render(). Qu ocurre? Como renderizado se abre con un tamao pre-
Si volvemos a ejecutar, visualizamos un habrs podido observar el cono ya no determinado. Para fijar el tamao de
cono de color gris (color que se muestra aparece, esto es porque cada vez que dicha ventana es necesario emplear el
por defecto) dentro de nuestra ventana aadimos un actor es necesario ren- mtodo SetSize, donde indicamos el alto
(Figura 5). Adems, es en este instante derizar la escena, ya que de lo contrario y el ancho en pixels,
cuando se aprecia la interaccin con el no se realiza un refresco de la misma y
ratn; con el botn izquierdo puedes es como si no hubisemos aadido un renWin.SetSize(450,325)
rotar la cmara, el botn central permite nuevo actor.
trasladarla, y con el botn derecho nos
acercamos o alejamos del objeto. Propiedades de Objetos
Adems, habrs observado que en la Si has seguido el tutorial hasta este
escena, por defecto se incluye una luz punto, habrs creado tu cono de color
para poder visualizar los objetos ilumi- gris. Pero probablemente no ests
nados. demasiado satisfecho, porque todos te-
nemos el mismo cono gris y t
lo queras blanco y el fondo
azul, por ejemplo. A lo largo
de este apartado veremos
cmo modificar la ventana de Figura 6: Comportamiento de los mtodos de
renderizado, la cmara, la cmara. a) Azimuth - flechas rojas; b)
propiedades del actor, etc. Al Pitch - flechas azul celeste; c) Yaw - flechas
final, podrs realizar todos azul oscuro; d) Elevation - flechas verdes; e)
Figura 4: Ventana de ren- Figura 5: Cono dentro de aquellos cambios que te Roll - flecha amarilla. La esfera blanca repre-
derizado por defecto. la escena. apetezcan. senta el foco.
W W W. L I N U X - M A G A Z I N E . E S PYTHON 67
LIBRERAS 3D con VTK
68 PYTHON W W W. L I N U X - M A G A Z I N E . E S
PIL LIBRERAS
Vigilantes
del Planeta
Quin no ha querido alguna vez sentirse como esos informticos de la NASA en su centro de control? Hoy
Cada vez que vemos el lanzamiento de posible recibir en tu propia casa imge- permita recoger y mantener actualizadas
un cohete, todos quedamos asombrados nes fascinantes del universo, de Marte o las imgenes que queremos en una espe-
ante la explosin del despegue, la atenta de la Tierra. cie de collage o mural. Construiremos
mirada de todos esos cientficos a los La temperatura del ocano, imgenes nuestro propio centro de control espa-
paneles de control, y la monstruosa cifra meteorolgicas, imgenes del campo cial.
que nos dicen que se han gastado en el magntico del sol o de las misiones a
proyecto. Marte son enviadas constantemente a la Recoger las Imgenes
Tierra desde estos engendros espaciales. Lo primero ser encontrar las imgenes y
Donde Van los Impuestos? Y el efecto es siempre el mismo, el espec- reunirlas. Vamos a usar como ejemplo
Es entonces cuando surge la pregunta y tador es deslumbrado por el presentador cuatro imgenes de carcter cientfico.
eso a m en qu me repercute? Un da, de televisin con unas imgenes incre- Se actualizan a distintos intervalos, de
estando en el despacho de la Rama del bles mientras se escuchan acordes de manera que podremos ver cmo evolu-
IEEE de Mlaga tuve una conversacin sintetizador. cionan las eventos que se registran.
en la que me contaron que la mayor Acaso no son esas imgenes de domi- Puedes encontrar las URLs en Recursos
parte de los satlites emiten al mundo nio pblico? Dnde puedo conseguirlas? [1].
las imgenes y los datos que recogen. Es En el presente artculo utilizaremos Debemos descargar las imgenes y
decir, si se posee el equipo necesario es Python para crear un script CGI que nos almacenarlas dentro de nuestro progra-
W W W. L I N U X - M A G A Z I N E . E S PYTHON 69
LIBRERAS PIL
>>> c = httplib.HTTPConnectionU
("www.linux-magazine.es")
>>>
70 PYTHON W W W. L I N U X - M A G A Z I N E . E S
PIL LIBRERAS
W W W. L I N U X - M A G A Z I N E . E S PYTHON 71
LIBRERAS PIL
72 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Mechanize LIBRERAS
Python y la Web
Enredados
Podemos automatizar comandos y programas grficos, por qu no
Digamos que llegas un da por la llos que se repitan pueden ser copiados y en la oficina en la que trabajaba. Haba
maana a la oficina. El jefe se acerca y te pegados) y cuando estuviese lista, hacer que rellenar un formulario web para dar
pide que vuelvas a pasar, otra vez!, un algo (magia vud?) y que se cargasen parte de las ventas. Esa tarea, debido a
montn de informacin a otra empresa a solos en la dichosa web. Y por supuesto, su volumen, requera que una persona
travs de la peor interfaz jams dise- sin que se enterase el jefe, as tendras perdiese toda una maana simplemente
ada: una web. ms tiempo para leer artculos como ste porque a nadie en la otra empresa se le
Carga la pgina, introduce tus datos de ;). ocurri la idea de hacer el proceso ms
acceso, pincha aqu, pincha all. Cuando Pues s, existe una manera de hacer rpido.
ests en la pgina con el formulario en exactamente lo que acabas de leer! Y As que ni corto ni perezoso mi jefe
cuestin debes introducir los datos y pin- vamos a explicarlo en este captulo. As cre un script en Perl que haca este tra-
char en un enlace o botn para enviar- podrs decirle a tu jefe que esta revista bajo a partir de un fichero de texto CSV.
los. Una y otra vez, una y otra vez. Quiz har a la empresa mucho ms produc- El problema es que lo hizo en Perl, y esta
durante horas. tiva. seccin va sobre Python. Hemos de
Acaso no hay una mejor manera de mudarnos todos a Perl para poder disfru-
hacer esto? Lo ideal sera poder usar tu Mechanize tar de este tipo de ventajas? No, gracias a
hoja de clculo preferida, rellenar los No es la primera vez que hago esto. Hace que John J. Lee decidi portar la librera
campos en ella de forma rpida (aque- algunos aos tuve este mismo problema Mechanize que Andy Lester cre en Perl
W W W. L I N U X - M A G A Z I N E . E S PYTHON 73
LIBRERAS Mechanize
(ver Recurso [1]) a Python (ver Recurso y a pedirle que busque la palabra usuario. La librera mechanize nos da lo
[2]). python para, a continuacin, conse- primero sin lo segundo. Nuestra inter-
Las distribuciones de Linux suelen per- guir una lista de las urls de los primeros faz de usuario sern llamadas a mto-
mitir instalarla como paquete. El pro- artculos que contengan esa palabra dos del objeto Browser.
blema es que la versin ms completa no (sern enlaces a ficheros PDF), ver Un problema que nos podemos encon-
est an liberada, y es recomendable Figura 1. De esta forma comprobaremos trar, ya desde el principio, es que nuestra
emplear la que se encuentra en el servidor cmo se trabaja con mechanize, ya que red disponga de un proxy para acceder a
de Subversion de John. El proceso es sim- tiene una forma peculiar de tratar el Internet. Este caso es bastante comn,
ple, instalamos el cliente de Subversion cdigo HTML. as que debemos indicrselo al objeto
que ms nos guste, aqu usar el estndar, Para ello debemos comenzar por almacenado en br:
y descargamos el cdigo fuente con: arrancar python e importar la librera
mechanize y re (expresiones regulares): >>> br.set_proxies(U
> svn co http://U {http : 192.168.1.254:8000,U
codespeak.net/svn/wwwsearch/U >>> import re ftp : 192.168.1.254:8000})
mechanize/trunk mechanize >>> import mechanize
Aqu he especificado un proxy para http
John emplea la librera setuptools de No ocurre nada particularmente vistoso, y otro para ftp, que suele ser lo normal.
Python para compilar e instalar la libre- a no ser que no hallamos instalado Ya tenemos nuestro navegador listo. Slo
ra, as que deberamos proceder a insta- correctamente la librera. Muy bien, tenemos que abrir una pgina:
larla antes de continuar. Despus slo seguidamente necesitamos crear un
debemos ejecutar: navegador: >>>> respuesta= br.openU
(http://www.linuxmagazine.es/)
> python setup.py build >>> br = mechanize.Browser()
> sudo python setup.py install Una vez abierta se nos devuelve un
Ahora ya lo tenemos en la variable br. objeto de respuesta. Este objeto contiene
Y listo. Ya tenemos nuestra librera No me refiero a un navegador grfico, todos los mtodos necesarios para poder
mechanize lista para trabajar. sino a todo lo que un navegador puede trabajar con la informacin devuelta por
hacer pero sin la parte grfica. Me el servidor web. Por ejemplo, podramos
Juguemos con una Web explico, un navegador posee un motor imprimir el contenido HTML de la
Comencemos con algo simple. Vamos a que interacta con los servidores web y pgina:
conectar con la web de Linux Magazine una interfaz grfica que interacta con el
>>>> printU
Listado 1: Nuestra Araa web respuesta.read()
<html>....
01 import re 20
02 import mechanize 21 #eliminamos duplicados
No pongo aqu la informacin devuelta
03 22
porque podra ocupar una pgina com-
04 br = mechanize.Browser() 23 urls =
pleta. Adems es de poca utilidad. Lo
05 dict(zip(urls,urls)).keys()
interesante de mechanize es que genera
06 br.set_handle_robots(False) 24
la pgina y nos permite acceder a las par-
07 25
tes jugosas de la misma de forma muy
08 respuesta = 26 r =
sencilla. Digamos que queremos saber
br.open(http://www.linux- re.compile(.*/(\d+)/(.*)$)
qu formularios contiene la pgina:
magazine.es/) 27
09 28
>>> for form in br.forms():
10 br.select_form(nr=1) 29 for url in urls:
... print form
11 30
...
12 br[words]=python 31 m= r.match(url)
<POST http://U
13 32 nombre =
www.linux-magazine.es/Readers/U
14 br.submit() m.group(1)+-+m.group(2)
Newsletter/reply application/U
15 33 print nombre
x-www-form-urlencoded
16 # Estamos en la pgina de 34
<HiddenControlU
resultados 35 respuesta = br.open(url)
(subject=subscribe)U
17 36 datos = respuesta.read()
(readonly)>
18 #primer resultado 37
<TextControl(email=Tu email)>
19 urls = [url.absolute_url for 38 fichero = open (nombre,w)
<SubmitControl(<None>=OK)U
url in 39 fichero.write(datos)
(readonly)>>
br.links(url_regex=re.com- 40 fichero.close()
<POST http://U
pile(rpdf$))]
www.linux-magazine.es/U
74 PYTHON W W W. L I N U X - M A G A Z I N E . E S
Mechanize LIBRERAS
search application/U >>> br.select_formU do hasta aqu: queremos los enlaces con
x-www-form-urlencoded (name = miformulario) la palabra python. Ya tenemos nuestro
<TextControl(words=)>> formulario relleno, ahora debemos pul-
Pero como no es este nuestro caso, lo sar el botn. Pero cmo? Pues con el
Mechanize tiene su propio lenguaje para seleccionaremos por posicin: mtodo submit:
representar partes de la pgina, y aqu
podemos ver un ejemplo del mismo. >>> br.select_form(nr = 1) >>> respuesta = br.sumbit()
Nos dice que hay dos formularios, que
emplean POST como mtodo de comuni- Empleamos el nmero 1, porque los for- Lo que acabamos de hacer es ms com-
cacin con la pgina. Muy bien, noso- mularios estn numerados comenzando plejo de lo que parece, qu ha ocurrido?
tros queremos acceder al segundo en 0. Con este mtodo ya tenemos selec- Al ejecutar submit hemos enviado los
puesto, que es el que emplea la url cionado el formulario, pero ste se com- datos del formulario al servidor, que nos
http://www.linuxmagazine.es/s earch. pone a su vez de varios elementos habr respondido redirigindonos a la
Este formulario tiene un campo de texto incrustados. Cmo podemos seleccio- pgina con los resultados. El contenido
llamado words. Al principio cuesta un narlos? Por suerte para nosotros, John, el de esta interaccin se almacena en res-
poco entender este lenguaje, pero con desarrollador, ha empleado toda la puesta, que no es ni ms ni menos que
un poco de prctica no es tan compli- potencia de Python y ha realizado un otro objeto que envuelve un documento
cado. truco de magia: hacer que el objeto HTML. Debemos recoger todos los enla-
De acuerdo, tenemos que acceder al almacenado en br se comporte como un ces que nos interesan.
segundo formulario, as que le indicamos tipo diccionario Python. Si el elemento Y aqu viene otro punto fuerte de
a br, nuestro navegador virtual, que input donde hay que escribir las palabras mechanize: su integracin con las expre-
emplee este formulario. Es posible realizar a buscar se llama words, entonces siones regulares. Desde luego que John
la seleccin por posicin o por nombre. El todo lo que tenemos que hacer es: no nos iba a fallar en este aspecto. Pode-
nombre vendra indicado por el parmetro mos elegir un enlace usando una expre-
HTML name, que el desarrollador de la >>> br[words]=python sin regular, de forma que no tenemos
web de Linux Magazine ha decidido igno- que ir buscando a tontas y a locas. Con
rar, al fin y al cabo no es obligatorio. As de simple! Es o no maravilloso este saber ms o menos qu formato tendr
Si se diese el caso de que el formulario mdulo? Esto s que es cdigo compacto el enlace que deseamos, podremos con-
tuviese un nombre, podramos seleccio- en estado puro. Despus de la euforia seguir la informacin que contiene. Pero
narlo con: debemos volver al asunto que nos ha tra- antes veamos qu deberamos hacer si
W W W. L I N U X - M A G A Z I N E . E S PYTHON 75
LIBRERAS Mechanize
no supiramos muy bien qu buscamos. expresin regular), que no hace otra en cuenta que en un diccionario no pue-
Al igual que con los formularios, los cosa que localizar cadenas acabadas en den existir dos llaves iguales, el resul-
enlaces se pueden recorrer como si fue- la letras pdf, y para ello podemos el tado es que al extraer las llaves obtene-
sen una lista: smbolo $ al final de pdf. Como mos la misma lista pero eliminando los
decamos, re.compile() devuelve un duplicados.
>>> for link in br.links(): objeto que reconoce la expresin regu- Complicado? S, como las lneas ante-
... print link lar, lo que podramos llamar una expre- riores, pero indudablemente til y que
... sin regular compilada, y lo almacena- requiere muy pocas pulsaciones del
Link(base_url=http://U mos en el argumento con nombre teclado.
www.linux-magazine.es/,U url_regex. La funcin br.links() lo reco- De acuerdo, ya tenemos los enlaces
url=/,text=logoOL.gif[IMG],U noce y sabe que debe buscar enlaces Y qu hacemos con ellos ahora? Pues
tag=a, attrs=[(href, /)]) que al reconocerlos con la expresin podramos descargarlos: recorriendo la
Link(base_url=http://U regular devuelvan True. lista y usando la funcin br.open() para
www.linux-magazine.es/,U br.links() generar as una lista de cargarlos, y la respuesta.read() para leer
url=/,text=logoOR.gif[IMG],U enlaces, y aqu entra en funcin la clu- el contenido del fichero, guardndolos
tag=a, attrs=[(href, /)]) sula for ... in ..., que no hace otra cosa en un fichero con nombre igual a la
.... que recorrer la lista y devolver los enla- ltima parte de la URL. Por desgracia,
ces bajo el nombre de variable url. La muchos de ellos se llaman
Aqu slo se muestran los dos primeros. lista de compresin se compone de cada Python.pdf, as que vamos a usar el
Si pruebas esto mismo en tu equipo uno de esos enlaces, con nombre url, de nmero de esa revista en el nombre.
vers que hay un nmero respetable de lo que nos quedamos con su atributo Puedes ver el cdigo completo en el Lis-
enlaces en esta pgina en concreto. De absolute_url: su ruta completa. Y con tado 1.
nuevo mechanize nos muestra lo que esto acabamos. Todo se reduce a una Pero, con este cdigo slo podemos
entiende por un enlace. Pero como noso- sola lnea de Python, escribimos poco conseguir los primeros resultados no?
tros sabemos lo que queremos, podemos pero vale por decenas de lneas! S, para mejorarlo y que descargue todos
pasar directamente a la accin con las An tenemos un problema, la web de los resultados slo tendramos que loca-
expresiones regulares: resultado de bsqueda de Linux Maga- lizar el enlace a siguiente resultado y
zine devuelve los resultados duplicados. pulsar en l con el mtodo
>>> urls =U Aplicando un poco de Kung Fu Python br.follow_link(). Dejo al lector que
[url.absolute_url for url inU podemos deshacernos de ellos en una piense cmo hacerlo, dando una sola
br.links(url_regex=re.compileU lnea: pista: emplea un bucle hasta que no
(rpdf$))] encuentres links que se correspondan
>>> urls = dict(U con la expresin regular.
Python comprime en poco cdigo mucho zip(urls,urls)).keys()
trabajo, as que esta nica lnea requiere Conclusin
una explicacin. Comencemos por la Zip significa cremallera en ingls, y eso No es de extraar que Google utilice
lista de compresin. En Python es posi- es precisamente lo que hace la funcin Python. De hecho, el propio Guido Van
ble crear listas a partir de definiciones de zip(). Cierra dos listas como si fuese una Rossum cre una araa web con una de
lo que se supone que va en las mismas. cremallera: las primeras implementaciones de
En este caso hay que comenzar por el Python ya hace algunos aitos. Hemos
cdigo: >>> zip([uno,dos,U podido comprobar cmo podemos usar
tres],[1,2,3]) una pgina web como si estuvisemos
br.links(url_regex=U [(uno,1),(dos,2),U delante de un navegador mediante la
re.compile(rpdf$)) (tres,3)] magnfica, y an en estado Beta, librera
mechanize, y empleando un nmero de
Este cdigo localiza todos aquellos enla- Esto puede resultar muy conveniente, lneas de cdigo realmente minsculo.
ces que se puedan identificar con el porque precisamente una lista con tuplas La prxima vez que el lector se enfrente
argumento que pasemos al mtodo de 2 valores es lo que necesitamos para a un trabajo tedioso con una pgina web,
br.links(). Es posible usar un nmero, crear un diccionario. puede que tenga un par de ideas para
como hicimos con el formulario ante- hacer que el ordenador trabaje por l
riormente, pero en lugar de eso vamos a >>> dict(zip([uno,dos,U gracias a cierta serpiente.
emplear una expresin regular. As que tres],[1,2,3]))
usamos la funcin re.compile(), que no {dos: 2, tres: 3,U Recursos
hace otra cosa que generar un objeto uno: 1}
[1] Mechanize para Perl: http://search.
que contiene un reconocedor de la cpan.org/dist/WWW-Mechanize/
expresin regular que pasamos como Y del diccionario podemos obtener las
[2] Mechanize para Python: http://
parmetro. En nuestro caso es pdf$, llaves usando el mtodo keys(). Si hace-
wwwsearch.sourceforge.net/
(la r de delante le indica a la funcin mos todo esto con un lista, cerrndola mechanize/
que la cadena se corresponde con una con ella misma en cremallera, y teniendo
76 PYTHON W W W. L I N U X - M A G A Z I N E . E S
ReportLab LIBRERAS
ReportLab
Hoy en da se hace imprescindible disponer de herramientas que permitan generar informes en PDF de alta
calidad rpida y dinmicamente. Existen diferentes herramientas para esta finalidad, entre ellas cabe destacar
ReportLab, biblioteca gratuita que permite crear documentos PDF empleando como lenguaje de programa-
La biblioteca ReportLab crea directa- que hay que seguir para instalar y confi- mar ejemplo1.py, las siguientes lneas
mente documentos PDF basndose en gurar ReportLab. de cdigo:
comandos grficos y sin pasos interme- El paquete pdfgen es el nivel ms bajo
dios, generando informes en un tiempo para generar documentos PDF, que se from reportlab.pdfgenU
extremadamente rpido y basa esencialmente en import canvas
siendo de gran utilidad en una secuencia de instruc- c=canvas.Canvas("primer.pdf")
los siguientes contextos: ciones para dibujar cada c.drawString(50,500, " MiU
generacin dinmica de pgina del documento. El PRIMER PDF")
PDFs en aplicaciones web objeto que proporciona las c.drawString(250,300,U
(empleado con Zope), operaciones de dibujo es "Coordenada=(250,300) ")
generacin de informes y el Canvas. El Canvas mide c.drawString(350,200,U
publicacin de datos igual que una hoja de "(350, 10)")
almacenados en bases de papel blanco, con puntos c.drawString(150,400,U
datos, embebiendo el sobre la misma identifica- "Aprendiendo REPORTLAB")
motor de impresin en dos mediante coordenadas c.showPage()
aplicaciones para conse- cartesianas (X,Y), que por c.save()
guir la generacin de defecto tienen el origen
informes a medida, etc. Figura 1: Coordenadas carte- (0,0) en la esquina infe- Probamos el programa y vemos que en
sianas de una hoja. rior izquierda de la pgi- el mismo directorio ya se ha creado un
Primeros Pasos na. La coordenada X va fichero llamado primer.pdf, anlogo al
Lo primero es tener instalados Python y hacia la derecha y la coordenada Y que se muestra en la Figura 2, sin nece-
ReportLab para realizar todas las prue- avanza hacia arriba (ver Figura 1). sidad de realizar ningn otro paso inter-
bas que van surgiendo y las que se nos Para crear nuestro primer PDF basta medio. Mediante la lnea from repor-
ocurran. En [1] se detallan los pasos escribir en un fichero, que podemos lla- tlab.pdfgen import canvas importamos
W W W. L I N U X - M A G A Z I N E . E S PYTHON 77
LIBRERAS ReportLab
78 PYTHON W W W. L I N U X - M A G A Z I N E . E S
ReportLab LIBRERAS
Figura 4: Colocando imgenes con Figura 5: Modo en que se rota, traslada y Figura 6: Ejemplo de rotacin, traslacin y
drawImage. escala un objeto Drawing. escalado de imgenes.
figura con sus dimensiones originales). se instancia la clase; texto contiene el ,style)
Mediante las siguientes lneas podemos texto del prrafo, en el que se eliminan 12 story.append(P2)
crear un fichero similar al de la Figura 4. los espacios en blanco innecesarios;
bulletText indica si el prrafo se escribe El paquete reportlab.lib.styles contiene
c.drawImage("Tux2.png",0,0) con un punto al inicio del mismo; la estilos predefinidos. Con getSample
c.drawImage("Tux2,png",200,300,U fuente y otras propiedades del prrafo y Style Sheet obtenemos un estilo ejem-
width=30,height=60) el punto se indican mediante el argumen- plo. Tenemos un estilo para la cabecera
to style. Veamos cmo aadir un prrafo: y otro para el texto normal. Mediante
Si lo que pretendemos es rotar imgenes h1.pageBreakBefore=0 decimos que no
o escalarlas, debemos emplear los obje- 01 from reportlab.lib.styles queremos un salto de pgina cada vez
tos Image(x,y,ancho,alto,path_imagen) import getSampleStyleSheet que se escriba una cabecera h1, en caso
y Drawing(ancho,alto) que se importan 02 styleSheet=getSampleStyle contrario basta escribir 1. Los diferentes
mediante from reportlab.graphics.shapes Sheet() prrafos se van almacenando en la lista
import Image, Drawing. El objeto Dra- 03 story=[] story porque posteriormente se aaden
wing puede escalarse, rotarse y trasla- 04 h1=styleSheet['Heading1'] al pdf a travs el paquete SimpleDoc
darse; pero hay que tener en cuenta que 05 h1.pageBreakBefore=0 Template de reportlab.platypus:
todas estas operaciones son acumulati- 06 h1.keepWithNext=1
vas (ver Figura 5). En el Listado 2 pode- 07 h1.backColor=colors.red doc=SimpleDocTemplate(U
mos ver cmo emplear correctamente 08 P1=Paragraph("Estilo Cabecera "paragrahp.pdf", pagesize=A4,U
estos objetos (Figura 6). Obsrvese que - h1 ",h1) showBoundary=1)
ahora el PDF no se genera a partir de un 09 story.append(P) doc.build(story)
Canvas, sino que se genera mediante 10 style=styleSheet['BodyText']
renderPDF.drawToFile (d,"canvas_ 11 P2=Paragraph("Estilo En este caso se genera un PDF con tan-
image 2.pdf"), donde d=Drawing BodyText" tas pginas como sea necesario.
(A4[0] ,A4[1]). Podemos probar a modi-
ficar los valores de los distintos mtodos Listado 2: Jugando con Imagenes (ejemplo3_2.py)
scale, rotate, translate; observaremos
01 from reportlab.graphics.shapes 11 IMAGES.append(d)
que a veces la imagen puede desapare-
import Image, Drawing 12 d=Drawing(80,100)
cer del folio, eso es debido a que los
02 from reportlab.graphics import 13 d.add(img)
valores que se dan hacen que nos salga-
renderPDF 14 d.translate(10,0)
mos de las dimensiones de la pgina.
03 from reportlab.lib.pagesizes 15 d.scale(2,2)
import A4 16 d.rotate(-5)
Creacin de Prrafos y Tablas
04 inpath="Tux2.png" 17 IMAGES.append(d)
La clase reportlab.platypus.Paragraph
05 IMAGES=[] 18 d=Drawing(A4[0],A4[1])
permite escribir texto formateado (justifi-
06 d=Drawing(80,100) 19 for img in IMAGES:
cado, alineado a la derecha o izquierda,
07 img=Image(200,0,80,100,inpath) 20 d.add(img)
centrado) en un aspecto elegante, ade-
08 d.add(img) 21 renderPDF.drawToFile(d,"can-
ms de modificar el estilo y color de tro-
09 d.rotate(45) vas_image2.pdf")
zos de la lnea a travs de XML. Mediante
10 d.scale(1.5,1.5)
Paragraph(texto,style, bullet Text=None)
W W W. L I N U X - M A G A Z I N E . E S PYTHON 79
LIBRERAS ReportLab
['Enero',1000, 2000],U
['Febrero',3000,100.5],U
['Marzo',2000,1000],U
['Abril',1500,1500]]
t.setStyle([U
('TEXTCOLOR',(0,1),(0,-1),U
colors.blue), ('TEXTCOLOR',U
(1,1), (2,-1),colors.green)])
80 PYTHON W W W. L I N U X - M A G A Z I N E . E S
SERVICIO Autores / Contacto
Linux Magazine
Linux New Media Spain, S.L.
Edfco. Hevimar, Planta 2, Ofic. 16
C/Graham Bell n 6
29590 - Mlaga
ESPAA
info@linux-magazine.es
Tel.: (+34) 952 020 242
(+34) 951 235 904
Fax.: (+34) 951 235 905
www.linux-magazine.es - Espaa
www.linux-magazine.com - Mundo
www.linux-magazine.co.uk - Reino Unido
www.linux-magazine.com.br - Brasil
www.linux-magazine.pl - Polonia
Si bien se toman todas las medidas posibles para
garantizar la precisin del contenido de los artculos
publicados en Linux Magazine, la editorial no se
hace responsable de imprecisiones aparecidas en la
revista. Asimismo, Linux Magazine no comparte
necesariamente las opiniones vertidas por sus
colaboradores en sus artculos. El riesgo derivado
del uso del DVD y el material que contiene corren
por cuenta del lector. El DVD es estudiado escrupu-
losamente para confirmar que est libre de virus y
errores.
Copyright y Marcas Registradas 2012 Linux New
Media Spain, S.L. Linux New Media Spain S.L.
prohbe la reproduccin total o parcial de los con-
tenidos de Linux Magazine sin su permiso previo y
por escrito. Linux es una Marca Registrada de Linus
Torvalds.
82 PYTHON W W W. L I N U X - M A G A Z I N E . E S