def maybeDeferred(f, *args, **kw): """Invoke a function that may or may not return a deferred. Call the given function with the given arguments. If the returned object is a C{Deferred}, return it. If the returned object is a C{Failure}, wrap it with C{fail} and return it. Otherwise, wrap it in C{succeed} and return it. If an exception is raised, convert it to a C{Failure}, wrap it in C{fail}, and then return it. @type f: Any callable @param f: The callable to invoke @param args: The arguments to pass to C{f} @param kw: The keyword arguments to pass to C{f} @rtype: C{Deferred} @return: The result of the function call, wrapped in a C{Deferred} if necessary. """ try: result = f(*args, **kw) except: return fail(Failure()) if isinstance(result, Deferred): return result elif isinstance(result, Failure): return fail(result) else: return succeed(result)
def _cbDeferred(self, result, index, succeeded): """(internal) Callback for when one of my deferreds fires. """ self.resultList[index] = (succeeded, result) self.finishedCount += 1 if not self.called: if succeeded == SUCCESS and self.fireOnOneCallback: self.callback((result, index)) elif succeeded == FAILURE and self.fireOnOneErrback: self.errback(Failure(FirstError(result, index))) elif self.finishedCount == len(self.resultList): self.callback(self.resultList) if succeeded == FAILURE and self.consumeErrors: result = None return result
def _runCallbacks(self): if self._runningCallbacks: # Don't recursively run callbacks return if not self.paused: while self.callbacks: item = self.callbacks.pop(0) callback, args, kw = item[ isinstance(self.result, Failure)] args = args or () kw = kw or {} try: self._runningCallbacks = True try: self.result = callback(self.result, *args, **kw) finally: self._runningCallbacks = False if isinstance(self.result, Deferred): # note: this will cause _runCallbacks to be called # recursively if self.result already has a result. # This shouldn't cause any problems, since there is no # relevant state in this stack frame at this point. # The recursive call will continue to process # self.callbacks until it is empty, then return here, # where there is no more work to be done, so this call # will return as well. self.pause() self.result.addBoth(self._continue) break except: self.result = Failure() if isinstance(self.result, Failure): self.result.cleanFailure() if self._debugInfo is None: self._debugInfo = DebugInfo() self._debugInfo.failResult = self.result else: if self._debugInfo is not None: self._debugInfo.failResult = None
def errback(self, fail=None): """ Run all error callbacks that have been added to this Deferred. Each callback will have its result passed as the first argument to the next; this way, the callbacks act as a 'processing chain'. Also, if the error-callback returns a non-Failure or doesn't raise an Exception, processing will continue on the *success*-callback chain. If the argument that's passed to me is not a Failure instance, it will be embedded in one. If no argument is passed, a Failure instance will be created based on the current traceback stack. Passing a string as `fail' is deprecated, and will be punished with a warning message. @raise NoCurrentExceptionError: If C{fail} is C{None} but there is no current exception state. """ if not isinstance(fail, Failure): fail = Failure(fail) self._startRunCallbacks(fail)
def timeout(deferred): deferred.errback(Failure(TimeoutError("Callback timed out")))