531
542
class waitForDeferred:
533
API Stability: semi-stable
544
See L{deferredGenerator}.
547
def __init__(self, d):
548
if not isinstance(d, Deferred):
549
raise TypeError("You must give waitForDeferred a Deferred. You gave it %r." % (d,))
554
if isinstance(self.result, failure.Failure):
555
self.result.raiseException()
560
def _deferGenerator(g, deferred):
562
See L{deferredGenerator}.
566
# This function is complicated by the need to prevent unbounded recursion
567
# arising from repeatedly yielding immediately ready deferreds. This while
568
# loop and the waiting variable solve that by manually unfolding the
571
waiting = [True, # defgen is waiting for result?
577
except StopIteration:
578
deferred.callback(result)
584
# Deferred.callback(Deferred) raises an error; we catch this case
585
# early here and give a nicer error message to the user in case
586
# they yield a Deferred.
587
if isinstance(result, Deferred):
588
return fail(TypeError("Yield waitForDeferred(d), not d!"))
590
if isinstance(result, waitForDeferred):
591
# a waitForDeferred was yielded, get the result.
592
# Pass result in so it don't get changed going around the loop
593
# This isn't a problem for waiting, as it's only reused if
594
# gotResult has already been executed.
595
def gotResult(r, result=result):
601
_deferGenerator(g, deferred)
602
result.d.addBoth(gotResult)
604
# Haven't called back yet, set flag so that we get reinvoked
605
# and return from the loop
608
# Reset waiting to initial values for next loop
616
def deferredGenerator(f):
618
API Stability: stable
535
620
Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
537
waitForDeferred and deferredGenerator help you write Deferred-using code
538
that looks like it's blocking (but isn't really), with the help of
622
deferredGenerator and waitForDeferred help you write Deferred-using code
623
that looks like a regular sequential function. If your code has a minimum
624
requirement of Python 2.5, consider the use of L{inlineCallbacks} instead,
625
which can accomplish the same thing in a more concise manner.
541
627
There are two important functions involved: waitForDeferred, and
542
628
deferredGenerator. They are used together, like this::
587
673
Deferred to the 'blocking' style, and deferredGenerator converts from the
588
674
'blocking' style to a Deferred.
591
def __init__(self, d):
592
if not isinstance(d, Deferred):
593
raise TypeError("You must give waitForDeferred a Deferred. You gave it %r." % (d,))
598
if isinstance(self.result, failure.Failure):
599
self.result.raiseException()
604
def _deferGenerator(g, deferred=None):
606
See L{waitForDeferred}.
676
def unwindGenerator(*args, **kwargs):
677
return _deferGenerator(f(*args, **kwargs), Deferred())
678
return mergeFunctionMetadata(f, unwindGenerator)
683
# BaseException is only in Py 2.5.
687
BaseException=Exception
689
class _DefGen_Return(BaseException):
690
def __init__(self, value):
693
def returnValue(val):
695
Return val from a L{inlineCallbacks} generator.
697
Note: this is currently implemented by raising an exception
698
derived from BaseException. You might want to change any
699
'except:' clauses to an 'except Exception:' clause so as not to
700
catch this exception.
702
Also: while this function currently will work when called from
703
within arbitrary functions called from within the generator, do
704
not rely upon this behavior.
706
raise _DefGen_Return(val)
708
def _inlineCallbacks(result, g, deferred):
710
See L{inlineCallbacks}.
712
# This function is complicated by the need to prevent unbounded recursion
713
# arising from repeatedly yielding immediately ready deferreds. This while
714
# loop and the waiting variable solve that by manually unfolding the
717
waiting = [True, # waiting for result?
611
deferred = Deferred()
722
# Send the last result back as the result of the yield expression.
723
if isinstance(result, failure.Failure):
724
result = g.throw(result.type, result.value, result.tb)
726
result = g.send(result)
614
727
except StopIteration:
615
deferred.callback(result)
728
# fell off the end, or "return" statement
729
deferred.callback(None)
731
except _DefGen_Return, e:
733
deferred.callback(e.value)
618
736
deferred.errback()
621
# Deferred.callback(Deferred) raises an error; we catch this case
622
# early here and give a nicer error message to the user in case
623
# they yield a Deferred. Perhaps eventually these semantics may
625
739
if isinstance(result, Deferred):
626
return fail(TypeError("Yield waitForDeferred(d), not d!"))
628
if isinstance(result, waitForDeferred):
629
waiting = [True, None]
630
# Pass vars in so they don't get changed going around the loop
631
def gotResult(r, waiting=waiting, result=result):
740
# a deferred was yielded, get the result.
634
743
waiting[0] = False
637
_deferGenerator(g, deferred)
638
result.d.addBoth(gotResult)
746
_inlineCallbacks(r, g, deferred)
748
result.addBoth(gotResult)
640
750
# Haven't called back yet, set flag so that we get reinvoked
641
751
# and return from the loop
642
752
waiting[0] = False
644
result = None # waiting[1]
648
def deferredGenerator(f):
756
# Reset waiting to initial values for next loop. gotResult uses
757
# waiting, but this isn't a problem because gotResult is only
758
# executed once, and if it hasn't been executed yet, the return
759
# branch above would have been taken.
768
def inlineCallbacks(f):
650
See L{waitForDeferred}.
770
API Stability: semi-stable
772
Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
774
WARNING: this function will not work in Python 2.4 and earlier!
776
inlineCallbacks helps you write Deferred-using code that looks like a
777
regular sequential function. This function uses features of Python 2.5
778
generators. If you need to be compatible with Python 2.4 or before, use
779
the L{deferredGenerator} function instead, which accomplishes the same
780
thing, but with somewhat more boilerplate.
783
thing = yield makeSomeRequestResultingInDeferred()
784
print thing #the result! hoorj!
785
thingummy = inlineCallbacks(thingummy)
787
When you call anything that results in a Deferred, you can simply yield it;
788
your generator will automatically be resumed when the Deferred's result is
789
available. The generator will be sent the result of the Deferred with the
790
'send' method on generators, or if the result was a failure, 'throw'.
792
Your inlineCallbacks-enabled generator will return a Deferred object, which
793
will result in the return value of the generator (or will fail with a
794
failure object if your generator raises an unhandled exception). Note that
795
you can't use 'return result' to return a value; use 'returnValue(result)'
796
instead. Falling off the end of the generator, or simply using 'return'
797
will cause the Deferred to have a result of None.
799
The Deferred returned from your deferred generator may errback if your
800
generator raised an exception.
803
thing = yield makeSomeRequestResultingInDeferred()
804
if thing == 'I love Twisted':
805
# will become the result of the Deferred
806
returnValue('TWISTED IS GREAT!')
808
# will trigger an errback
809
raise Exception('DESTROY ALL LIFE')
810
thingummy = inlineCallbacks(thingummy)
652
812
def unwindGenerator(*args, **kwargs):
653
return _deferGenerator(f(*args, **kwargs))
813
return _inlineCallbacks(None, f(*args, **kwargs), Deferred())
654
814
return mergeFunctionMetadata(f, unwindGenerator)
817
## DeferredLock/DeferredQueue
657
819
class _ConcurrencyPrimitive(object):
658
820
def __init__(self):
659
821
self.waiting = []