Cómo detectar errores no manejados en diferido originados desde reactor.stop ()

Soy nuevo en Twist y tengo problemas con el siguiente script.

Cuando corro lo siguiente:

#!/usr/bin/env python from twisted.internet import defer from twisted.web.client import getPage, reactor def success(results): print 'success' def error(results): print 'error' return results def finished(results): print 'finished' reactor.stop() tasks = [] d = getPage('thiswontwork').addCallback(success).addErrback(error) tasks.append(d) dl = defer.DeferredList(tasks) dl.addCallback(finished) reactor.run() 

Me sale el siguiente resultado:

 error finished Unhandled error in Deferred: Unhandled Error Traceback (most recent call last): Failure: twisted.internet.error.ConnectionRefusedError: Connection was refused by other side: 61: Connection refused. 

Mi pregunta es ¿por qué recibo un error no manejado cuando parece que detecté el error con mi callback de error?

El problema es que en su definición de error devuelve un result que, dado que fue devuelto por un error, es un objeto de error, y devolver un objeto de error es uno de los dos criterios para volver a elevar el estado de error. Vea la siguiente reseña de la introducción retorcida de krondo – parte 9 :

Ahora, en el código síncrono podemos “volver a generar” una excepción usando la palabra clave raise sin ningún argumento. Al hacerlo, se genera la excepción original que estábamos manejando y nos permite tomar alguna acción en un error sin manejarlo por completo. Resulta que podemos hacer lo mismo en un errback. Un aplazado considerará que un callback / errback ha fallado si:

  • La callback / errback genera cualquier tipo de excepción, o
  • La callback / errback devuelve un objeto de error.

Dado que el primer argumento de un error es siempre un error, un error puede “volver a generar” la excepción devolviendo su primer argumento, después de realizar cualquier acción que quiera tomar.

Sí, solo lo intenté, si cambias:

 def error(results): print 'error' return results 

a

 def error(results): print 'error' return 

No volverás a elevar el estado de error, por lo que no se filtrará de nuevo al reactor, y no causará que el rastreo te moleste.

PD: ¡No puedo recomendar la presentación torcida de Krondo lo suficiente! Puede que sea realmente largo, pero si puedes superarlo, serás capaz de producir código en forma torcida y este tipo de comportamiento no será un misterio.

PPS Veo que tiene una pregunta SO anterior (el informe de callback de Python DeferredList cuando los aplazados genera un error ) acerca de los aplazados, podría ser la razón por la que creó el código de esta manera. Creo que puede tener un malentendido fundamental sobre el valor de retorno / valor de callback de las defensas involucradas en los diferidos (en particular, los errores). Echa un vistazo a la parte 9 (aunque es posible que tengas que hacer una copia de seguridad de la parte 7 o incluso anterior para realizar un seguimiento) de krondo, realmente debería ayudar a aclarar las cosas.