blob: 30e773a66ca71ed68534dad829119499ff248eac [file] [log] [blame]
Zsolt Haraszti91350eb2016-11-05 15:33:53 -07001from twisted.internet import reactor
2from twisted.internet.defer import Deferred
3from twisted.internet.error import AlreadyCalled
4
5
6class TimeOutError(Exception): pass
7
8
9class DeferredWithTimeout(Deferred):
10 """
11 Deferred with a timeout. If neither the callback nor the errback method
12 is not called within the given time, the deferred's errback will be called
13 with a TimeOutError() exception.
14
15 All other uses are the same as of Deferred().
16 """
17 def __init__(self, timeout=1.0):
18 Deferred.__init__(self)
19 self._timeout = timeout
20 self.timer = reactor.callLater(timeout, self.timed_out)
21
22 def timed_out(self):
23 self.errback(
24 TimeOutError('timed out after {} seconds'.format(self._timeout)))
25
26 def callback(self, result):
27 self._cancel_timer()
28 return Deferred.callback(self, result)
29
30 def errback(self, fail):
31 self._cancel_timer()
32 return Deferred.errback(self, fail)
33
34 def cancel(self):
35 self._cancel_timer()
36 return Deferred.cancel(self)
37
38 def _cancel_timer(self):
39 try:
40 self.timer.cancel()
41 except AlreadyCalled:
42 pass
43