[Twisted-Python] strange bug with... something :)

Сергей Магафуров smagafurov at naumen.ru
Thu Aug 5 21:15:11 MDT 2010


Example code 1

{{{
class Example(object):
     def __init__(self, connection):
         self.connection = connection
         self.counter = 0
         self.requests = {}

     def generate_request_id(self):
         self.counter += 1
         return self.counter

     def request(self, data, timeout=10):
         deferred = defer.Deferred()
         request_id = self.generate_request_id()
         self.requests[request_id] = deferred

         # ATTENTION: I want to see current traceback when timeout occurs
         # therefore raise and catch here
         try:
             raise failure.TimeoutError()
         except failure.TimeoutError:
             failure = failure.Failure()

         # charge timer
         timer = reactor.callLater(timeout, self._on_timeout, 
request_id, failure)

         # send request
         self.connection.send_request(request_id, data)
         return deferred

     def _on_timeout(self, request_id, failure):
         deferred = self.requests.pop(request_id, None)
         if deferred is not None:
             deferred.errback(failure)

     def on_response_received(self, request_id, response):
         deferred = self.requests.pop(request_id, None)
         if deferred is not None:
             deferred.callback(response)
}}}

Disadvantage 1 of this code:
We construct failure.Failure() always although timeout may not occur at all.
If failure.Failure() was lazy it will be cool.

Disadvantage 2 (bug in twisted?) of this code:
This code doesn't work in some cases and I don't know why.
In some cases deferred.callback(response) does nothing although called.

But this code magically works properly in the same cases:

Example code 2 (one difference is just "lazy" failure construction using 
special FailureFactory class)

{{{
class FailureFactory(object):
     def __init__(self, arg):
         try:
             raise arg
         except:
             exc_info = sys.exc_info()
         self.exc_info = exc_info

     def __call__(self):
         exc_type, exc_value, tb = self.exc_info
         return Failure(exc_value, exc_type, tb)

class Example(object):
     def __init__(self, connection):
         self.connection = connection
         self.counter = 0
         self.requests = {}

     def generate_request_id(self):
         self.counter += 1
         return self.counter

     def request(self, data, timeout=10):
         deferred = defer.Deferred()
         request_id = self.generate_request_id()
         self.requests[request_id] = deferred

         # ATTENTION: I want to see current traceback when timeout occurs
         # therefore raise and catch here
         failure_factory = FailureFactory(failure.TimeoutError())

         # charge timer
         timer = reactor.callLater(timeout, self._on_timeout, 
request_id, failure_factory)

         # send request
         self.connection.send_request(request_id, data)
         return deferred

     def _on_timeout(self, request_id, failure_factory):
         deferred = self.requests.pop(request_id, None)
         if deferred is not None:
             deferred.errback(failure_factory())

     def on_response_received(self, request_id, response):
         deferred = self.requests.pop(request_id, None)
         if deferred is not None:
             deferred.callback(response)
}}}

Example 2 works but Example 1 does not.

What is wrong with example 1?

Bug in twisted?

I have posted this message as ticket but was redirected to mailing-list
http://twistedmatrix.com/trac/ticket/4628





More information about the Twisted-Python mailing list