lunes, octubre 31, 2005

Unas noticias de barrapunto:
Me ha vuelto a hablar JJ maravillas de Spring. He estado echanvo un vistazo a un artículo, sobre él, pero requiere mas tiempo del que tengo ahora. Es un poco espeso.
Me quedo con dos conceptos que mencionan:
  • 'Inversion of Control' (IoC)
  • 'Dependency Injection' (a flavour of IoC)
Con lo cual al buscar en google, lo primero que me ha salido es un artículo de Martin Fowler, Inversion of Control Containers and the Dependency Injection pattern.

Mas info aquí.
Por lo visto Apache Excalibur lo usa.

La idea es del concepto es:

"That's the basic concept of Inversion of Control; you don't create your objects, you describe how they should be created. You don't directly connect your components and services together in code, you describe which services are needed by which components, and the container is responsible for hooking it all together. The container creates all the objects, wires them together by setting the necessary properties, and determines when methods are invoked."
He habían comentado que en developerWorks (de IBM), había bastantes artículos sobre python, y efectivamente así es. Como muestra un botón, unos articulos sobre:
Despues de mirar lo de python, me puse a navegar un poco por la red, encontrando un artículo sobre la Web Semántica en la seccion web.

viernes, octubre 28, 2005

Interné en España


Estaba terminando hoy de ojear el ciberpais. En uno de los articulos sobre el estado de internet en España, comparado con otros paises en europa he visto que sólo ganamos en:
  • bajar musica
  • publicar en weblogs
Unas noticias de barrapunto:

jueves, octubre 27, 2005

Parsers SAX de html en python


Incluidos en python tenemos dos posibles parsers a usar:

Actualmente estoy usando HTMLParser.HTMLParser. Un problema que tenemos con este parser es que necesitamos detectar correctamente los inicios y los fines de tags, y hay tags que a veces no traen el fin de tag. Para evitar esto, y teniendo en cuenta que estamos en una etapa del proyecto totalmente de desarrollo (avanzando en funcionalidad), solventamos el problema usando tidy y generado xhtml.

El problema de esta solución es que tidy incrementa bastante el tiempo de procesamiento. Esto, unido a la idea de que haya parsers que puedan procesar html de una manera mas robusta que HTMLParser.HTMLParser y sean mas rápidos (por ejemplo hechos en C) me llevó a mirar libxml2.
Lo bueno de libxml2 es que tiene bindings a python, con lo cual algo (no sencillo) que nos quitamos del medio. Además hay una librería ya mas 'python-oriented', lxml. El problema con lxml, es que no es SAX.

Aparte de libxml2, hay un par de parsers candidatos a usar que no he evaluado:
Según he leído, en principio el segundo puede ser mejor.

Sobre libxml2



Las primeras pruebas que he realizado con el parser SAX incluido en libxml2 han sido muy satisfactorias (unas 10 veces mas rápido que HTMLParser).
Pero necesito hacer mas pruebas, sobre todo con html mal formado.

Los mayores inconvenientes que le he encontrado son:
  • Falta de documentación.
  • No cubre todo el API de C.
  • Mas delicado de usar (tenemos que gestionar nosotros mismos la memoria)
Ya haciendo mis pruebas, lo que no he podido hacer es abortar el procesamiento de un documento.
Si el motivo por el cual queremos parar el parseo es porque nos hemos excedido del tiempo, la solución es meter el documento en porciones (es lo mas sensato además).
En caso contrario, pues es un problema que espero averiguar...

Para acabar adjunto un ejemplo que viene incluido con la distribución:


#!/usr/bin/python -u
import sys
import libxml2

# Memory debug specific
libxml2.debugMemory(1)

log = ""

class callback:
def startDocument(self):
global log
log = log + "startDocument:"

def endDocument(self):
global log
log = log + "endDocument:"

def startElement(self, tag, attrs):
global log
log = log + "startElement %s %s:" % (tag, attrs)

def endElement(self, tag):
global log
log = log + "endElement %s:" % (tag)

def characters(self, data):
global log
log = log + "characters: %s:" % (data)

def warning(self, msg):
global log
log = log + "warning: %s:" % (msg)

def error(self, msg):
global log
log = log + "error: %s:" % (msg)

def fatalError(self, msg):
global log
log = log + "fatalError: %s:" % (msg)

handler = callback()

ctxt = libxml2.htmlCreatePushParser(handler, "b">
ctxt.htmlParseChunk(chunk, len(chunk), 0)
chunk = "ar
"
ctxt.htmlParseChunk(chunk, len(chunk), 1)
ctxt=None

reference = """startDocument:startElement html None:startElement body None:startElement foo {'url': 'tst'}:error: Tag foo invalid
:characters: bar:endElement foo:endElement body:endElement html:endDocument:"""
if log != reference:
print "Error got: %s" % log
print "Exprected: %s" % reference
sys.exit(1)

# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print "OK"
else:
print "Memory leak %d bytes" % (libxml2.debugMemory(1))
libxml2.dumpMemory()

koders: un buscador curioso, de código.

lunes, octubre 24, 2005

De WORD a XML y al reves


He encontrado un artículo al respecto, que lo confieso, no he leido.

Ojo con las trazas en python



En el proyecto que estoy actualmente hemos llegado a un punto en que lo que tenemos montado puede ser ya usado, funcionalmente. Pero nos quedaba una incógnita por resolver. ¿Es lo suficientemente rápido?

El sistema tiene que procesar documentos html, para lo cual en primer lugar usamos Tidy, luego se parsean, y los transformamos a nuestro formato interno.

El uso de Tidy es necesario ya que el parser de python (HTMLParser) no se traga cualquier cosa.

En un futuro seguramente usemos algún otro parser implementado en un lenguaje de mas bajo nivel y que valide, pero de momento el sistema actual nos ha servido para avanzar en el desarrollo.

Para la primera toma de tiempos usé simplemente la función time.time. Tomando tiempos con las trazas activadas y desactivadas. Mi sorpresa es que tidy no era lo que se llevaba mas tiempo (escribe el documento totalmente), sino que nuestra parte se llevaba mas.

Para seguir analizando, decidí usar el profiler de python, ya que nunca lo había usado.
La forma mas sencilla de uso es:



python profile.py <script> <args>



Su salida de texto, ya me sirvió para ver alguna cosilla sospechosa dentro del código (que no del parser).
De todas formas es mas potente usándolo dentro del código, ya que el fichero generado es binario:




import profile
profile.run(<funcion>,<fichero>)



Posteriormente a través del módulo pstats, se puede postprocesar:



import pstats
import sys

file = sys.argv[1]
p = pstats.Stats(file)
p.sort_stats('cumulative')
p.print_stats()



El profiler me orientó, sobre la zona del código con los problemas.
A partir de ahí usé una librería hecha a medida para la toma de tiempos. La ventaja de la librería sobre el profiler, es que el profiler te da el tiempo por llamada, y la librería de toma de tiempos te da mas libertad, ya que tu defines la porción de código que entra en la toma de tiempo.

Una vez tengamos este tipo de librería lo suyo es que dejemos el código instrumentado con ellas en sitios clave, y que mediante configuración podamos activar o desactivar la toma de tiempos.

Bueno que de desvío del tema... Con la librería vi que algo raro pasado. No era normal que una región de código que no hacía nada se llevase el tiempo que se estaba llevando. Hasta que me fijé en las dichosas trazas, que tenía desactivadas, y gualá. Di con el problema.

El problema de fondo es que vengo del desarrollo de C++ y allí normalmente cuando se desactivan las trazas, no se ejecuta ni la invocación.
Pero claro aquí estábamos con python, y con un recubrimiento del modulo de logging de python. La invocación ser realizaba, aunque la traza no se generase. Y lo que se estaba llevando el tiempo era la evaluación de los argumentos. Estaba pasando a string una estructura de datos bastante tocha.

Moraleja: ojito con la evaluación de los argumentos en las trazas.

De todas formas a posteriormente me he dado cuenta de que fui un gañán y que a veces no vemos lo que no queremos ver. Ya que en la salida del profiler salía que el logging era lo que se estaba llevando el tiempo. Pero claro como estaba desactivado el nivel DEBUG...

Diseño de librería de toma de tiempos



Continuando con este tema...

Como he indicado anteriormente la toma de tiempos se debe de poder activar y desactivar por configuración y a los tiempos se les asigna una marca o tag.

En el diseño original, la librería tenia dos métodos para una determinada marca; uno para el comienzo de toma de tiempo y otro para el final de toma de tiempo.
Esto tiene como problema el que se te puedan quedar marcas desbalanceadas.

Un diseño mejor, es que en lugar de definir un comienzo y fin de marca y se vayan acumulando los tiempos, lo que hagamos es para cada marca registrar el tiempo.
Una vez terminada la ejecución se pedirán los tiempos. Cuando se pidan los tiempos es cuando se calculan los acumulados. Para calcular los acumulados, será necesario indicar entre que marcas se van a hacer los cálculos.


viernes, octubre 21, 2005

Me ha comentado JJ que estan usando una Wiki, cuyo motor está en python, se trata de MoinMoin. En la wikipedia tienen hasta una entrada, sobre él.

En la wikipedia se puede seguir navegando sobre temas afines. Uno muy interesante es una comparación sobre 'wiki software'.

Según me comenta JJ, el mejor es MediaWiki.
Una noticia de barrapunto:

jueves, octubre 20, 2005

Ajax


Me ha extrañado que no hubiese escrito nada al respecto, ya que JJ me había comentado sobre ello. Ajax es una tecnología (o un conjungo) que usa entre otros google.
En el siguiente artículo dan una descripción muy clarita de él. El primer artículo sobre el mismo fue de un tal James Garret.

Según me comenta oreques, lo que no hay por ahí son muchos ejemplo disponibles (lo confieso, yo no he buscado), pero parece que ibm si tiene algo.
Me pasa my bro un proveedor de hosting que dice es interesante (no lo he mirado): bluehost.
Unas noticias de barrapunto:

lunes, octubre 17, 2005

Componentes electrónicos en madrid


Me han dicho que Conectrol es la caña (en Jorge Juan, al lado de Goya). Por lo visto tienen 2 tiendas (enfrente una de otra), una mas de informatica y otra de componentes electrónicos.

(1 día despues)

Antes de salir del curro me comentó JJ sobre Telkron, que me pilla mas cerca del curro, y como la otra, me pilla también de camino a casa (está en Avda. Donostiarra).
Me pasé por la primera y lo que buscaba lo tenían agotado, entonces probé con Conectrol. En la tienda de informatica si que lo tenían, pero como tenía que preguntar otra cosilla me fuí a la de electrónica. Vaya pasada....
Un par de noticias de barrapunto:

viernes, octubre 14, 2005

jueves, octubre 13, 2005

lunes, octubre 10, 2005

miércoles, octubre 05, 2005

Compilar codigo en python


Cuando se invoca a 'python' siempre se genera un fichero '.pyc', el cual contiene el bytecode correspondiente al codigo python. Este bytecode se ejecutará en la maquina virtual de python.

Si lo que queremos es generar el bytecode pero sin ejecutar, tenemos dos modulos que nos lo permiten: py_compile y compileall.

Ejecución dinamica en python


La funcion interna exec, nos permite ejecutar codigo python que obtenemos en tiempo de ejecución.
exec code[ in globals[,locals]]

code, puede ser una cadena, un fichero o bien un objeto compilado.
Hay otra función, rexec, que permite la ejecución en un entorno limitado (como en el caso de los Applets de Java).

Para compilar objetos podemos usar la función compile.

Y finalmente tenemos la función eval, que permite evaluar expresiones.

Mas información en la documentación de python.
El libreo de O'Really Python in a Nutshell, habla de exec en el punto 13.1 ('Dynamic Execution and the exec Statement') y en 13.2 sobre 'Restricted Execution'.
Barrapunto hoy viene cargadito:

martes, octubre 04, 2005

lunes, octubre 03, 2005