~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/internet/defer.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
177
177
        cbs = ((callback, callbackArgs, callbackKeywords),
178
178
               (errback or (passthru), errbackArgs, errbackKeywords))
179
179
        self.callbacks.append(cbs)
180
 
            
 
180
 
181
181
        if self.called:
182
182
            self._runCallbacks()
183
183
        return self
213
213
        """Chain another Deferred to this Deferred.
214
214
 
215
215
        This method adds callbacks to this Deferred to call d's callback or
216
 
        errback, as appropriate."""
 
216
        errback, as appropriate. It is merely a shorthand way of performing
 
217
        the following::
 
218
 
 
219
            self.addCallbacks(d.callback, d.errback)
 
220
 
 
221
        When you chain a deferred d2 to another deferred d1 with
 
222
        d1.chainDeferred(d2), you are making d2 participate in the callback
 
223
        chain of d1. Thus any event that fires d1 will also fire d2.
 
224
        However, the converse is B{not} true; if d2 is fired d1 will not be
 
225
        affected.
 
226
        """
217
227
        return self.addCallbacks(d.callback, d.errback)
218
228
 
219
229
    def callback(self, result):
393
403
 
394
404
class FirstError(Exception):
395
405
    """First error to occur in a DeferredList if fireOnOneErrback is set.
396
 
    
 
406
 
397
407
    @ivar subFailure: the L{Failure} that occurred.
398
408
    @ivar index: the index of the Deferred in the DeferredList where it
399
409
    happened.
424
434
        if isinstance(other, tuple):
425
435
            return tuple(self) == other
426
436
        elif isinstance(other, FirstError):
427
 
            return (self.subFailure == other.subFailure and 
 
437
            return (self.subFailure == other.subFailure and
428
438
                    self.index == other.index)
429
439
        return False
430
440
 
527
537
 
528
538
 
529
539
 
 
540
## deferredGenerator
530
541
 
531
542
class waitForDeferred:
532
543
    """
533
 
    API Stability: semi-stable
 
544
    See L{deferredGenerator}.
 
545
    """
 
546
 
 
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,))
 
550
        self.d = d
 
551
 
 
552
 
 
553
    def getResult(self):
 
554
        if isinstance(self.result, failure.Failure):
 
555
            self.result.raiseException()
 
556
        return self.result
 
557
 
 
558
 
 
559
 
 
560
def _deferGenerator(g, deferred):
 
561
    """
 
562
    See L{deferredGenerator}.
 
563
    """
 
564
    result = None
 
565
 
 
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
 
569
    # recursion.
 
570
 
 
571
    waiting = [True, # defgen is waiting for result?
 
572
               None] # result
 
573
 
 
574
    while 1:
 
575
        try:
 
576
            result = g.next()
 
577
        except StopIteration:
 
578
            deferred.callback(result)
 
579
            return deferred
 
580
        except:
 
581
            deferred.errback()
 
582
            return deferred
 
583
 
 
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!"))
 
589
 
 
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):
 
596
                result.result = r
 
597
                if waiting[0]:
 
598
                    waiting[0] = False
 
599
                    waiting[1] = r
 
600
                else:
 
601
                    _deferGenerator(g, deferred)
 
602
            result.d.addBoth(gotResult)
 
603
            if waiting[0]:
 
604
                # Haven't called back yet, set flag so that we get reinvoked
 
605
                # and return from the loop
 
606
                waiting[0] = False
 
607
                return deferred
 
608
            # Reset waiting to initial values for next loop
 
609
            waiting[0] = True
 
610
            waiting[1] = None
 
611
 
 
612
            result = None
 
613
 
 
614
 
 
615
 
 
616
def deferredGenerator(f):
 
617
    """
 
618
    API Stability: stable
534
619
 
535
620
    Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
536
621
 
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
539
 
    generators.
 
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.
540
626
 
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.
589
675
    """
590
 
 
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,))
594
 
        self.d = d
595
 
 
596
 
 
597
 
    def getResult(self):
598
 
        if isinstance(self.result, failure.Failure):
599
 
            self.result.raiseException()
600
 
        return self.result
601
 
 
602
 
 
603
 
 
604
 
def _deferGenerator(g, deferred=None):
605
 
    """
606
 
    See L{waitForDeferred}.
607
 
    """
608
 
    result = None
 
676
    def unwindGenerator(*args, **kwargs):
 
677
        return _deferGenerator(f(*args, **kwargs), Deferred())
 
678
    return mergeFunctionMetadata(f, unwindGenerator)
 
679
 
 
680
 
 
681
## inlineCallbacks
 
682
 
 
683
# BaseException is only in Py 2.5.
 
684
try:
 
685
    BaseException
 
686
except NameError:
 
687
    BaseException=Exception
 
688
 
 
689
class _DefGen_Return(BaseException):
 
690
    def __init__(self, value):
 
691
        self.value = value
 
692
 
 
693
def returnValue(val):
 
694
    """
 
695
    Return val from a L{inlineCallbacks} generator.
 
696
 
 
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.
 
701
 
 
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.
 
705
    """
 
706
    raise _DefGen_Return(val)
 
707
 
 
708
def _inlineCallbacks(result, g, deferred):
 
709
    """
 
710
    See L{inlineCallbacks}.
 
711
    """
 
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
 
715
    # recursion.
 
716
 
 
717
    waiting = [True, # waiting for result?
 
718
               None] # result
 
719
 
609
720
    while 1:
610
 
        if deferred is None:
611
 
            deferred = Deferred()
612
721
        try:
613
 
            result = g.next()
 
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)
 
725
            else:
 
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)
 
730
            return deferred
 
731
        except _DefGen_Return, e:
 
732
            # returnValue call
 
733
            deferred.callback(e.value)
616
734
            return deferred
617
735
        except:
618
736
            deferred.errback()
619
737
            return deferred
620
738
 
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
624
 
        # change.
625
739
        if isinstance(result, Deferred):
626
 
            return fail(TypeError("Yield waitForDeferred(d), not d!"))
627
 
 
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):
632
 
                result.result = r
 
740
            # a deferred was yielded, get the result.
 
741
            def gotResult(r):
633
742
                if waiting[0]:
634
743
                    waiting[0] = False
635
744
                    waiting[1] = r
636
745
                else:
637
 
                    _deferGenerator(g, deferred)
638
 
            result.d.addBoth(gotResult)
 
746
                    _inlineCallbacks(r, g, deferred)
 
747
 
 
748
            result.addBoth(gotResult)
639
749
            if waiting[0]:
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
643
753
                return deferred
644
 
            result = None # waiting[1]
645
 
 
646
 
 
647
 
 
648
 
def deferredGenerator(f):
 
754
 
 
755
            result = waiting[1]
 
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.
 
760
 
 
761
 
 
762
            waiting[0] = True
 
763
            waiting[1] = None
 
764
 
 
765
 
 
766
    return deferred
 
767
 
 
768
def inlineCallbacks(f):
649
769
    """
650
 
    See L{waitForDeferred}.
 
770
    API Stability: semi-stable
 
771
 
 
772
    Maintainer: U{Christopher Armstrong<mailto:radix@twistedmatrix.com>}
 
773
 
 
774
    WARNING: this function will not work in Python 2.4 and earlier!
 
775
 
 
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.
 
781
 
 
782
        def thingummy():
 
783
            thing = yield makeSomeRequestResultingInDeferred()
 
784
            print thing #the result! hoorj!
 
785
        thingummy = inlineCallbacks(thingummy)
 
786
 
 
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'.
 
791
 
 
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.
 
798
 
 
799
    The Deferred returned from your deferred generator may errback if your
 
800
    generator raised an exception.
 
801
 
 
802
        def thingummy():
 
803
            thing = yield makeSomeRequestResultingInDeferred()
 
804
            if thing == 'I love Twisted':
 
805
                # will become the result of the Deferred
 
806
                returnValue('TWISTED IS GREAT!')
 
807
            else:
 
808
                # will trigger an errback
 
809
                raise Exception('DESTROY ALL LIFE')
 
810
        thingummy = inlineCallbacks(thingummy)
651
811
    """
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)
655
815
 
656
816
 
 
817
## DeferredLock/DeferredQueue
 
818
 
657
819
class _ConcurrencyPrimitive(object):
658
820
    def __init__(self):
659
821
        self.waiting = []
835
997
 
836
998
__all__ = ["Deferred", "DeferredList", "succeed", "fail", "FAILURE", "SUCCESS",
837
999
           "AlreadyCalledError", "TimeoutError", "gatherResults",
838
 
           "maybeDeferred", "waitForDeferred", "deferredGenerator",
 
1000
           "maybeDeferred",
 
1001
           "waitForDeferred", "deferredGenerator", "inlineCallbacks",
839
1002
           "DeferredLock", "DeferredSemaphore", "DeferredQueue",
840
1003
          ]