sábado, febrero 10, 2007
domingo, febrero 04, 2007
Hacer software es dificil
Veo en barrapunto una noticia que me interesa: El software es dificil.
Por supuesto que lo es. Creo que el siguiente post de slasdot lo resume muy bien (la noticia en slasdot está enlazada desde barrapunto:
"Why doesn't anyone complain about how hard brain surgery is? Why doesn't anyone complain about how hard building space exploration vehicles is? Why doesn't anyone complain about how hard creating a successful marketing campaign is? Software engineering is difficult because it's a complex subject that takes a combination of intelligent people and training to produce good results. Just because businesses are too stupid to realize this doesn't make the problem go away. You can't throw complex projects at untrained, stupid, incompetent people and expect them to produce quality software. You can't just invent some magic formula for software development that will work 100% of the time to maximize efficiency. Software engineering is NOT manufacturing. Accept it and move on for fuck's sake. "
Recuerdo los tiempos de la facultad, cuando te hablaban de las herramientas de cuarta generación. Si hay algo que tengo cada vez mas claro es que jamás se podrá sustituir la labor humana en la producción de software. Es utópico.
En un curro como el mio actual, donde continuamente tienes que estar 'inventandote' algoritmos... dime tu como vas a sustituir esa labor humana. Y buscando soluciones... Y descubriendo y evaluando productos o librerias.... ¿Lo puede hacer cualquiera? Desde luego que no. A ver si algúndía se dan cuenta los que mueven el cotarro que hay que dar una vuelta de tuerca al mercado del desarrollo del software. Se den cuenta de que no somos monos que pulsamos teclas.
Por supuesto que lo es. Creo que el siguiente post de slasdot lo resume muy bien (la noticia en slasdot está enlazada desde barrapunto:
"Why doesn't anyone complain about how hard brain surgery is? Why doesn't anyone complain about how hard building space exploration vehicles is? Why doesn't anyone complain about how hard creating a successful marketing campaign is? Software engineering is difficult because it's a complex subject that takes a combination of intelligent people and training to produce good results. Just because businesses are too stupid to realize this doesn't make the problem go away. You can't throw complex projects at untrained, stupid, incompetent people and expect them to produce quality software. You can't just invent some magic formula for software development that will work 100% of the time to maximize efficiency. Software engineering is NOT manufacturing. Accept it and move on for fuck's sake. "
Recuerdo los tiempos de la facultad, cuando te hablaban de las herramientas de cuarta generación. Si hay algo que tengo cada vez mas claro es que jamás se podrá sustituir la labor humana en la producción de software. Es utópico.
En un curro como el mio actual, donde continuamente tienes que estar 'inventandote' algoritmos... dime tu como vas a sustituir esa labor humana. Y buscando soluciones... Y descubriendo y evaluando productos o librerias.... ¿Lo puede hacer cualquiera? Desde luego que no. A ver si algúndía se dan cuenta los que mueven el cotarro que hay que dar una vuelta de tuerca al mercado del desarrollo del software. Se den cuenta de que no somos monos que pulsamos teclas.
miércoles, enero 31, 2007
martes, enero 30, 2007
Tipos set y Set
Me acabo de dar cuenta de que a partir de la versión 2.4 de python existe como 'built-in type' el tipo set.
En versiones anteriores había que usar el tipo Set del modulo sets.
Por lo que he podido leer es mas mejor ahora usar set.
En versiones anteriores había que usar el tipo Set del modulo sets.
Por lo que he podido leer es mas mejor ahora usar set.
Un post interesante de OjoBuscador de José R. Pérez Agüera: Todo el mundo tiene un buscador, pero ¿realmente lo tienen? Interesante echarle un ojo a los comentarios.
lunes, enero 29, 2007
Ejecutar comandos del sistema
Conocía os.system, pero hoy en la python-es han comentado un par de opciones mas; popen:
import os
data=os.popen('ls').read()
file=open('fichero.txt','w')
file.write(data)
file.close()
Y con commands:
import commands
out = commands.getoutput('ls')
f = file('lsout.txt', 'w')
f.write(out)
f.close()
import os
data=os.popen('ls').read()
file=open('fichero.txt','w')
file.write(data)
file.close()
Y con commands:
import commands
out = commands.getoutput('ls')
f = file('lsout.txt', 'w')
f.write(out)
f.close()
viernes, enero 26, 2007
Mas sobre cssutils
Antes de nada indicar que estoy usando la distribución 0.9.1b3 de cssutils.
Tests
En teoria los test podriamos ejecutarlos tras hacer una build del paquete, o incluso tras descomprimirlo. Mediante:
python setup.py test
Pero por lo que sea no me ha funcinado. Bueno no pasa nada... podemos lanzar los test desde el directorio de tests (../src/cssutils/tests) de la siguiente manera (en 'kk' tendremos la salida):
for i in test_*.py; do echo $i >> kk; python $i >> kk 2>&1; done
Veremos que aparecen trazas de error. No pasa nada. Lo importante es que el test nos devuelva OK.
encutils
cssutils tiene un paquete, encutils, a tener en cuenta.
La funcion principal es getEncodingInfo que devuelve informacion sobre le encoding. Esta informacion se extrae del elemento pasado: headers de HTTPResponse, XML declaration y lementos meta X/HTML.
Resumiendo podemos pasar un HTTPResponse o un texto como argumento.
Aunque no la he probado, parece currada.
csscapture
Permite extraer todos las hojas de estilo de una url determinada (incluyendo las que estan embebidas en la propia página html).
Usa HTMLParser.
El parseo (interioridades)
El parser desencadena el parseo al asignar el texto del css al objeto CSSStylesheet.
Para realizar el parseo se usa tokenizer.CSSTokenizer.
El único pero que veo a cssutils es que es un poco lento con el parseo. Necesitamos mas velocidad. No se si se podrá obtimizar algo... He estado echando un vistazo rápido pero el codigo no es sencillo.
Habrá que meteler el profiler, a ver si hay algo que canta.
Tests
En teoria los test podriamos ejecutarlos tras hacer una build del paquete, o incluso tras descomprimirlo. Mediante:
python setup.py test
Pero por lo que sea no me ha funcinado. Bueno no pasa nada... podemos lanzar los test desde el directorio de tests (../src/cssutils/tests) de la siguiente manera (en 'kk' tendremos la salida):
for i in test_*.py; do echo $i >> kk; python $i >> kk 2>&1; done
Veremos que aparecen trazas de error. No pasa nada. Lo importante es que el test nos devuelva OK.
encutils
cssutils tiene un paquete, encutils, a tener en cuenta.
La funcion principal es getEncodingInfo que devuelve informacion sobre le encoding. Esta informacion se extrae del elemento pasado: headers de HTTPResponse, XML declaration y lementos meta X/HTML.
Resumiendo podemos pasar un HTTPResponse o un texto como argumento.
Aunque no la he probado, parece currada.
csscapture
Permite extraer todos las hojas de estilo de una url determinada (incluyendo las que estan embebidas en la propia página html).
Usa HTMLParser.
El parseo (interioridades)
El parser desencadena el parseo al asignar el texto del css al objeto CSSStylesheet.
Para realizar el parseo se usa tokenizer.CSSTokenizer.
El único pero que veo a cssutils es que es un poco lento con el parseo. Necesitamos mas velocidad. No se si se podrá obtimizar algo... He estado echando un vistazo rápido pero el codigo no es sencillo.
Habrá que meteler el profiler, a ver si hay algo que canta.
martes, enero 23, 2007
Python bindings
Un par de productos para crear bindings entre python y otros lenguajes:
- boost.python. Para C++
- swig. [introducción]
lunes, enero 22, 2007
Parsers de CSS
He tenido que mirar que hay por ahí, para parsear CSS's en python. Lo primero que tengo que decir es que estoy realmente sorprendido. No he encontrado ningún producto maduro, y ni siquiera unos bindings en python.
Los dos parsers que he encontrado en python usan además DOM, por lo que no hay nada SAX (o en gerga CSS SAC).
Esto significa que alguien con interés, ganas y tiempo puede hacer algo útil para la comunidad del software libre...
Pero lo que mas me sorprende es no haber encontrado nada ni en python-es, ni en comp.lang.python.
Antes de entrar a comentar los parsers, comentar que CSS tiene tres versiones, CSS1, CSS2 y CSS3 (en desarrollo).
Todos los parsers implementan CSS1 y por lo que he podido ver CSS2 parcialmente.
Bueno al lio... los parsers de python encontrados son:
Si no nos convencen ninguno de los dos, no nos va a quedar mas remedio que implementar unos bindings a alguno existente en C (vamos lo normal en python... no lo vamos a hacer de uno implementado en Java; ummm, aunque no he dicho un disparate... siempre se puede usar jython ;)). En C he encontrado:
Finalmente se puede intentar usar el parser que use algún browser (implementando el binding correspondiente, claro). Entre los disponibles parece que el candidato más lógico sería usar del del firefox, Gecko.
Mas info sobre el parser de CSS de Gecko aquí.
Los dos parsers que he encontrado en python usan además DOM, por lo que no hay nada SAX (o en gerga CSS SAC).
Esto significa que alguien con interés, ganas y tiempo puede hacer algo útil para la comunidad del software libre...
Pero lo que mas me sorprende es no haber encontrado nada ni en python-es, ni en comp.lang.python.
Antes de entrar a comentar los parsers, comentar que CSS tiene tres versiones, CSS1, CSS2 y CSS3 (en desarrollo).
Todos los parsers implementan CSS1 y por lo que he podido ver CSS2 parcialmente.
Bueno al lio... los parsers de python encontrados son:
- cssutils (beta) y
- TechGame Framework CSS Parser and Engine (alpha)
Si no nos convencen ninguno de los dos, no nos va a quedar mas remedio que implementar unos bindings a alguno existente en C (vamos lo normal en python... no lo vamos a hacer de uno implementado en Java; ummm, aunque no he dicho un disparate... siempre se puede usar jython ;)). En C he encontrado:
- El SAC de w3.org.
- Libcroco: parser SAC y CSSOM like api para gnome.
Finalmente se puede intentar usar el parser que use algún browser (implementando el binding correspondiente, claro). Entre los disponibles parece que el candidato más lógico sería usar del del firefox, Gecko.
Mas info sobre el parser de CSS de Gecko aquí.
jueves, enero 11, 2007
Validad un DTD
Si queremos validar un DTD lo que podemos hacer es usar un validador de xml que use dicho DTD.
Al cargarlo detectará posibles errores.
Por ejemplo podemo susar xmllint:
xmllint --valid
Al cargarlo detectará posibles errores.
Por ejemplo podemo susar xmllint:
xmllint --valid
miércoles, enero 10, 2007
RSS Readers
Ya he comentado anteriormente sobre agregadores de feeds: [1],[2] y [3].
Me vuelve a surgir el tema porque tengo que obtener feeds de una intranet, por lo que los lectores web no me sirven. Voy a tener que usar el firefox o bien una aplicación local.
Para windows me recomiendan Omea Reader (Net 2.0) y para linux liferea (gnome) o kagregator. (kde)
Con el firefox voy a echarle un vistazo a sage y ver como funcionan los live bookmarks.
Me vuelve a surgir el tema porque tengo que obtener feeds de una intranet, por lo que los lectores web no me sirven. Voy a tener que usar el firefox o bien una aplicación local.
Para windows me recomiendan Omea Reader (Net 2.0) y para linux liferea (gnome) o kagregator. (kde)
Con el firefox voy a echarle un vistazo a sage y ver como funcionan los live bookmarks.
martes, enero 09, 2007
¿libxml2 leak in python (html sax-parsing)?
Me siento un poco fustrado con el parser de html de libxml2. Se nos va memoria a saco y no tengo ni idea de como evitarlo.
He preguntado a la lista, pero no ha servido de mucho. A ver si me aclaran algo mas... Actualizaré el post cuando sepa algo.
Tras detectar que en nuestro codigo el mayor problema con la memoria lo teníamos con el parser sax de html de libxml2, modifiqué el test que acompaña a la distribución (pushSAXhtml.py)para que en lugar de procesar 1 fichero, procese N, siendo N un número suficientemente grande para ver las perdidas de memoria...
Pues bien, en algo mas de 10 minutos procesando el proceso se cae por un segmentation fault.
El específico en el bucle para procesar el fichero por el parser es:
ctxt = libxml2.htmlCreatePushParser(handler, initdata, 0, inputFilePath)
ctxt.htmlParseChunk(data, len(data), 1)
ctxt = None
En el callback no hacemos nada:
class callback:
def startDocument(self):
print "."
def endDocument(self):
pass
def startElement(self, tag, attrs):
pass
def endElement(self, tag):
pass
def characters(self, data):
pass
def warning(self, msg):
pass
def error(self, msg):
pass
def fatalError(self, msg):
pass
¡Ojo! la fuga de memoria la vemos a nivel del sistema operativo (con top o mirando en /proc (por ejemplo con mem-monitor)), ya que las rutinas específicas de libxml2 nos indican que todo está OK.
En fin... que con este problema no podemos llevar nuestro codigo a producción. O solucionamos esto o tenemos que mirar otro parser (posible candidato beautifulsoup); cosa que no me gustaría.
Otra cosa que me ha frustado mucho es no encontrar nada en la web. ¿Es que nadie por ahí esta parseando html con libxml2 usando SAX? No me lo puedo creer...
Ah! un detalle que se me olvidada. En el código asignamos None al contexto. Es correcto. Eso provoca la invocación a xmlFreeParserCtxt(que es lo mismo que htmlFreeParserCtxt: esta llama a la anterior). Con lo cual no tenemos que liberar nada mas, ya que el documento no lo usamos. De hecho si intentamos obtener el documento los bindings de python nos devolverán una excepción.
Para terminar de cerrar el tema y asegurame de que no hay nada raro en mi entorno he hecho el ejemplo equivalente en C, y ha funcionado sin problemas. Ahí va el codigo:
Para hacerlo operativo modificar las constantes BUFFER_SIZE, NUM_ITERS, FILE_PATH, al gusto del consumidor.
He preguntado a la lista, pero no ha servido de mucho. A ver si me aclaran algo mas... Actualizaré el post cuando sepa algo.
Tras detectar que en nuestro codigo el mayor problema con la memoria lo teníamos con el parser sax de html de libxml2, modifiqué el test que acompaña a la distribución (pushSAXhtml.py)para que en lugar de procesar 1 fichero, procese N, siendo N un número suficientemente grande para ver las perdidas de memoria...
Pues bien, en algo mas de 10 minutos procesando el proceso se cae por un segmentation fault.
El específico en el bucle para procesar el fichero por el parser es:
ctxt = libxml2.htmlCreatePushParser(handler, initdata, 0, inputFilePath)
ctxt.htmlParseChunk(data, len(data), 1)
ctxt = None
En el callback no hacemos nada:
class callback:
def startDocument(self):
print "."
def endDocument(self):
pass
def startElement(self, tag, attrs):
pass
def endElement(self, tag):
pass
def characters(self, data):
pass
def warning(self, msg):
pass
def error(self, msg):
pass
def fatalError(self, msg):
pass
¡Ojo! la fuga de memoria la vemos a nivel del sistema operativo (con top o mirando en /proc (por ejemplo con mem-monitor)), ya que las rutinas específicas de libxml2 nos indican que todo está OK.
En fin... que con este problema no podemos llevar nuestro codigo a producción. O solucionamos esto o tenemos que mirar otro parser (posible candidato beautifulsoup); cosa que no me gustaría.
Otra cosa que me ha frustado mucho es no encontrar nada en la web. ¿Es que nadie por ahí esta parseando html con libxml2 usando SAX? No me lo puedo creer...
Ah! un detalle que se me olvidada. En el código asignamos None al contexto. Es correcto. Eso provoca la invocación a xmlFreeParserCtxt(que es lo mismo que htmlFreeParserCtxt: esta llama a la anterior). Con lo cual no tenemos que liberar nada mas, ya que el documento no lo usamos. De hecho si intentamos obtener el documento los bindings de python nos devolverán una excepción.
Para terminar de cerrar el tema y asegurame de que no hay nada raro en mi entorno he hecho el ejemplo equivalente en C, y ha funcionado sin problemas. Ahí va el codigo:
/* libxml2 C HTML Parser Example
* gcc-I -L -lxml2
*/
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 100000
#define NUM_ITERS 10000
#define FILE_PATH ""
/*****************************************************************************/
/*
* Foo context structure
*/
typedef struct
{
int foo;
} Context;
/*
* libxml start element callback function
*/
void startElement(void *voidContext,
const xmlChar *name,
const xmlChar **attributes)
{
return;
}
/*
* libxml end element callback function
*/
void endElement(void *voidContext,
const xmlChar *name)
{
return;
}
/*
* Text handling helper function
*/
void handleCharacters(Context *context,
const xmlChar *chars,
int length)
{
return;
}
/*
* libxml PCDATA callback function
*/
void characters(void *voidContext,
const xmlChar *chars,
int length)
{
return;
}
/*
* libxml CDATA callback function
*/
void cdata(void *voidContext,
const xmlChar *chars,
int length)
{
return;
}
htmlSAXHandler saxHandler =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
startElement,
endElement,
NULL,
characters,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
cdata,
NULL
};
/*****************************************************************************/
char buffer[BUFFER_SIZE];
int main(void)
{
htmlParserCtxtPtr ctxt;
Context context;
char *filepath=FILE_PATH;
FILE *f = NULL;
long fileLen = 0;
long retRead = 0;
int i=0;
/*---- Reading the data */
/*
struct stat myStat;
stat(filepath,&myStat);
if (myStat.st_size >= BUFFER_SIZE)
{
print("El fichero no cabe en el buffer\n");
return 1;
}
*/
f = fopen(filepath, "r");
if ( f == NULL ) /* Could not open file */
{
printf("Error opening %s: %s (%u)\n", filepath, strerror(errno), errno);
return 1;
}
fseek(f, 0L, SEEK_END); /* Position to end of file */
fileLen = ftell(f); /* Get file length */
rewind(f); /* Back to start of file */
if (fileLen >= BUFFER_SIZE)
{
printf("El fichero no cabe en el buffer: %d\n",fileLen);
return 1;
}
retRead = fread(buffer,fileLen,1,f);
if (retRead != 1)
{
printf("Error haciendo el read");
return 1;
}
fclose(f);
/*---- We parser the file */
for(i=0;i < NUM_ITERS; ++i)
{
ctxt = htmlCreatePushParserCtxt(&saxHandler, &context, "", 0, "",
XML_CHAR_ENCODING_NONE);
htmlParseChunk(ctxt, buffer, fileLen, 0);
htmlParseChunk(ctxt, "", 0, 1);
htmlFreeParserCtxt(ctxt);
printf(".\n");
}
return 0;
}
Para hacerlo operativo modificar las constantes BUFFER_SIZE, NUM_ITERS, FILE_PATH, al gusto del consumidor.
miércoles, enero 03, 2007
Uso de etiquetas en blogger
Hace poco he migrado todos mis blogs a la nueva versión de blogger. Mi mayor interés para ello era el poder etiquetar los posts.
Pero una vez hecho, la template usada se mantenía (no se mostraban las labels). Tras estar indagando un poco he visto que es necesario actualizar la template, pudiendo modificar el diseño a golpe de ratón, cosa que antes no se podía. Es una gran mejora.
¡¡¡Ojo!!! Si en la template anterior habeis hecho modificaciones a mano se perderán, si no las meteis en la nueva template antes de guardarla.
Ya con respecto a las etiquetas indicar un par de cosas:
Y ya para acabar indicar que si estamos en blogger, cuando estamos visualizando nuestro blog, nos permite editar los elementos compositivos de la template (por ejemplo añadir un enlace a la lista de enlaces).
Resumiendo: ha mejorado mucho blogger con esta nueva versión.
Pero una vez hecho, la template usada se mantenía (no se mostraban las labels). Tras estar indagando un poco he visto que es necesario actualizar la template, pudiendo modificar el diseño a golpe de ratón, cosa que antes no se podía. Es una gran mejora.
¡¡¡Ojo!!! Si en la template anterior habeis hecho modificaciones a mano se perderán, si no las meteis en la nueva template antes de guardarla.
Ya con respecto a las etiquetas indicar un par de cosas:
- se muestran como una lista, bien ordenada alfabéticamente o por frecuencia
- se pueden hacer feeds por las etiquetas; mas información aquí.
Y ya para acabar indicar que si estamos en blogger, cuando estamos visualizando nuestro blog, nos permite editar los elementos compositivos de la template (por ejemplo añadir un enlace a la lista de enlaces).
Resumiendo: ha mejorado mucho blogger con esta nueva versión.
martes, enero 02, 2007
Suscribirse a:
Entradas (Atom)