martes, 8 de junio de 2010

Problema con StoneageHTML y cssutils

Si has llegado a este post por realizar una busqueda en tu buscador favorito, lo mas probable que sea porque te has topado con el mismo problema que me hizo renegar unas buenas horas. Y es ese el motivo por el cual agrego esta entrada a mi blog, quizas a alguien mas le ahorra un par de horas.


Time 2010/05/31 14:28:38.352 GMT-3
User Name (User Id) xxxxxxxx (xxxxxxxx)
Request URL
http://xxxxxxxxxxxxxxxx:8080/[…]/newsletter-stats.html
Exception Type AttributeError
Exception Value 'list' object attribute 'append' is read-only

Traceback (innermost last):

* Module ZPublisher.Publish, line 119, in publish
* Module ZPublisher.mapply, line 88, in mapply
* Module ZPublisher.Publish, line 42, in call_object
* Module plone.z3cform.layout, line 49, in __call__
* Module Shared.DC.Scripts.Bindings, line 313, in __call__
* Module Shared.DC.Scripts.Bindings, line 350, in _bindAndExec
* Module Products.PageTemplates.PageTemplateFile, line 129, in _exec
* Module Products.PageTemplates.PageTemplate, line 89, in pt_render
* Module zope.pagetemplate.pagetemplate, line 117, in pt_render
* Module zope.tal.talinterpreter, line 271, in __call__
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 891, in do_useMacro
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 891, in do_useMacro
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 949, in do_defineSlot
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 957, in do_defineSlot
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 891, in do_useMacro
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 957, in do_defineSlot
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 534, in do_optTag_tal
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 949, in do_defineSlot
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 536, in do_optTag_tal
* Module zope.tal.talinterpreter, line 521, in do_optTag
* Module zope.tal.talinterpreter, line 516, in no_tag
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 949, in do_defineSlot
* Module zope.tal.talinterpreter, line 346, in interpret
* Module zope.tal.talinterpreter, line 586, in do_setLocal_tal
* Module zope.tales.tales, line 696, in evaluate
URL: controlpanel
Line 10, Column 4
Expression: Names: {'container': , 'context': , 'default':

,

'here': ,
'loop': {},
'nothing': None,
'options': {'args': ()},
'repeat': ,
'request': URL=http://xxxxxxxxxxxxxxxx:8080/[…]/newsletter-stats.html>,
'root': ,
'template': ,
'traverse_subpath': [],
'user': ,
'view': ,
'views': 0xb0e04a8c>}

* Module zope.tales.expressions, line 217, in __call__
* Module Products.PageTemplates.Expressions, line 161, in _eval
* Module Products.PageTemplates.Expressions, line 123, in render
* Module plone.z3cform.layout, line 58, in contents
* Module plone.z3cform.layout, line 66, in render_form
* Module z3c.form.form, line 189, in __call__
* Module plone.z3cform.crud.crud, line 381, in update
* Module plone.z3cform.crud.crud, line 229, in update
* Module z3c.form.form, line 186, in update
* Module z3c.form.action, line 99, in execute
* Module z3c.form.button, line 302, in __call__
* Module z3c.form.button, line 170, in __call__
* Module collective.dancing.browser.stats, line 124, in handle_process_jobs
* Module collective.singing.async, line 22, in process
* Module collective.singing.async, line 37, in __call__
* Module collective.dancing.browser.sendnewsletter, line 51, in _assemble_messages
* Module collective.singing.scheduler, line 117, in __call__
* Module collective.singing.scheduler, line 109, in render_message
* Module collective.dancing.composer, line 307, in render
* Module plone.memoize.volatile, line 272, in replacement
* Module collective.dancing.composer, line 297, in _render
* Module stoneagehtml.stoneagehtml, line 91, in compactify
* Module stoneagehtml.stoneagehtml, line 208, in compactify
* Module cssutils.css.cssstylesheet, line 106, in _setCssRules

AttributeError: 'list' object attribute 'append' is read-only

Bien, ahora, a que se debe esto ? bueno, basicamente, en las ultimas versiones del producto cssutils[0] (yo me tope con el problema en la version 0.9.7a4) en el archivo cssutils/css/cssstylesheet.py linea 104, se sobre-escribe el metodo setter del campo cssRules (atributo de la clase), en donde se intenta reemplazar el metodo 'append' de cssRules (parametro de entrada del metodo).

El problema radica, cuando en lugar de que cssRules (parametro del metodo) sea un cssutils.css.CSSRuleList, sea una lista (tipo built-in de python), lo que provoca que dicha excepcion se levante.

Esto ultimo, es provocado por la linea 208 del archivo stoneagehtml/stoneagehtml.py del producto StoneageHTML[1]:

sheet.cssRules = self.filterCSSDeclarations(sheet.cssRules)

ya que filterCSSDeclarations devuelve una lista (la cual se pasa al setter del cssRules, provocando el crash descripto arriba).

La solucion, seria que stoneageHTML se actualizara, para funcionar con las ultimas versiones de cssutils, pero al momento de escribir esto, dicha solcion no existe, con lo cual la siguiente solucion es hacer un downgrade de cssutils. En mi caso, lo hice a la 0.9.5 ya que es la que en fechas esta mas cerca del lanzamiento de stoneageHTML 0.1.5, luego de lo cual, el crash desaparecio y todo funciona bien de nuevo.

Ya me puse en contacto con el desarrollador de StoneageHTML para informarle de este bug, y ver si puede especificar la dependencia de cssutils para que su producto funcione, o que en su defecto saque una version mas nueva de StoneageHTML. Tratare de actualizar la entrada con la informacion que obtenga de el.

[0] - http://pypi.python.org/pypi/cssutils
[1] - http://pypi.python.org/pypi/StoneageHTML