1# -*- coding: utf-8 -*-
2
3"""
4Test suite for PEP 380 implementation
5
6adapted from original tests written by Greg Ewing
7see <http://www.cosc.canterbury.ac.nz/greg.ewing/python/yield-from/YieldFrom-Python3.1.2-rev5.zip>
8"""
9
10import sys
11
12
13def _lines(trace):
14    for line in trace:
15        print(line)
16
17
18def test_delegation_of_initial_next_to_subgenerator():
19    """
20    >>> _lines(test_delegation_of_initial_next_to_subgenerator())
21    Starting g1
22    Starting g2
23    Yielded 42
24    Finishing g2
25    Finishing g1
26    """
27    trace = []
28    def g1():
29        trace.append("Starting g1")
30        yield from g2()
31        trace.append("Finishing g1")
32    def g2():
33        trace.append("Starting g2")
34        yield 42
35        trace.append("Finishing g2")
36    for x in g1():
37        trace.append("Yielded %s" % (x,))
38    return trace
39
40def test_raising_exception_in_initial_next_call():
41    """
42    >>> _lines(test_raising_exception_in_initial_next_call())
43    Starting g1
44    Starting g2
45    Finishing g2
46    Finishing g1
47    """
48    trace = []
49    def g1():
50        try:
51            trace.append("Starting g1")
52            yield from g2()
53        finally:
54            trace.append("Finishing g1")
55    def g2():
56        try:
57            trace.append("Starting g2")
58            raise ValueError("spanish inquisition occurred")
59        finally:
60            trace.append("Finishing g2")
61    try:
62        for x in g1():
63            trace.append("Yielded %s" % (x,))
64    except ValueError as e:
65        pass
66    else:
67        trace.append("subgenerator failed to raise ValueError")
68    return trace
69
70def test_delegation_of_next_call_to_subgenerator():
71    """
72    >>> _lines(test_delegation_of_next_call_to_subgenerator())
73    Starting g1
74    Yielded g1 ham
75    Starting g2
76    Yielded g2 spam
77    Yielded g2 more spam
78    Finishing g2
79    Yielded g1 eggs
80    Finishing g1
81    """
82    trace = []
83    def g1():
84        trace.append("Starting g1")
85        yield "g1 ham"
86        yield from g2()
87        yield "g1 eggs"
88        trace.append("Finishing g1")
89    def g2():
90        trace.append("Starting g2")
91        yield "g2 spam"
92        yield "g2 more spam"
93        trace.append("Finishing g2")
94    for x in g1():
95        trace.append("Yielded %s" % (x,))
96    return trace
97
98def test_raising_exception_in_delegated_next_call():
99    """
100    >>> _lines(test_raising_exception_in_delegated_next_call())
101    Starting g1
102    Yielded g1 ham
103    Starting g2
104    Yielded g2 spam
105    Finishing g2
106    Finishing g1
107    """
108    trace = []
109    def g1():
110        try:
111            trace.append("Starting g1")
112            yield "g1 ham"
113            yield from g2()
114            yield "g1 eggs"
115        finally:
116            trace.append("Finishing g1")
117    def g2():
118        try:
119            trace.append("Starting g2")
120            yield "g2 spam"
121            raise ValueError("hovercraft is full of eels")
122            yield "g2 more spam"
123        finally:
124            trace.append("Finishing g2")
125    try:
126        for x in g1():
127            trace.append("Yielded %s" % (x,))
128    except ValueError:
129        pass
130    else:
131        trace.append("subgenerator failed to raise ValueError")
132    return trace
133
134def test_delegation_of_send():
135    """
136    >>> _lines(test_delegation_of_send())
137    Starting g1
138    g1 received 1
139    Starting g2
140    Yielded g2 spam
141    g2 received 2
142    Yielded g2 more spam
143    g2 received 3
144    Finishing g2
145    Yielded g1 eggs
146    g1 received 4
147    Finishing g1
148    """
149    trace = []
150    def g1():
151        trace.append("Starting g1")
152        x = yield "g1 ham"
153        trace.append("g1 received %s" % (x,))
154        yield from g2()
155        x = yield "g1 eggs"
156        trace.append("g1 received %s" % (x,))
157        trace.append("Finishing g1")
158    def g2():
159        trace.append("Starting g2")
160        x = yield "g2 spam"
161        trace.append("g2 received %s" % (x,))
162        x = yield "g2 more spam"
163        trace.append("g2 received %s" % (x,))
164        trace.append("Finishing g2")
165    g = g1()
166    y = next(g)
167    x = 1
168    try:
169        while 1:
170            y = g.send(x)
171            trace.append("Yielded %s" % (y,))
172            x += 1
173    except StopIteration:
174        pass
175    return trace
176
177def test_handling_exception_while_delegating_send():
178    """
179    >>> _lines(test_handling_exception_while_delegating_send())
180    Starting g1
181    g1 received 1
182    Starting g2
183    Yielded g2 spam
184    g2 received 2
185    """
186    trace = []
187    def g1():
188        trace.append("Starting g1")
189        x = yield "g1 ham"
190        trace.append("g1 received %s" % (x,))
191        yield from g2()
192        x = yield "g1 eggs"
193        trace.append("g1 received %s" % (x,))
194        trace.append("Finishing g1")
195    def g2():
196        trace.append("Starting g2")
197        x = yield "g2 spam"
198        trace.append("g2 received %s" % (x,))
199        raise ValueError("hovercraft is full of eels")
200        x = yield "g2 more spam"
201        trace.append("g2 received %s" % (x,))
202        trace.append("Finishing g2")
203    def run():
204        g = g1()
205        y = next(g)
206        x = 1
207        try:
208            while 1:
209                y = g.send(x)
210                trace.append("Yielded %s" % (y,))
211                x += 1
212        except StopIteration:
213            trace.append("StopIteration")
214    try:
215        run()
216    except ValueError:
217        pass # ok
218    else:
219        trace.append("no ValueError")
220    return trace
221
222def test_delegating_close():
223    """
224    >>> _lines(test_delegating_close())
225    Starting g1
226    Yielded g1 ham
227    Starting g2
228    Yielded g2 spam
229    Finishing g2
230    Finishing g1
231    """
232    trace = []
233    def g1():
234        try:
235            trace.append("Starting g1")
236            yield "g1 ham"
237            yield from g2()
238            yield "g1 eggs"
239        finally:
240            trace.append("Finishing g1")
241    def g2():
242        try:
243            trace.append("Starting g2")
244            yield "g2 spam"
245            yield "g2 more spam"
246        finally:
247            trace.append("Finishing g2")
248    g = g1()
249    for i in range(2):
250        x = next(g)
251        trace.append("Yielded %s" % (x,))
252    g.close()
253    return trace
254
255def test_handing_exception_while_delegating_close():
256    """
257    >>> _lines(test_handing_exception_while_delegating_close())
258    Starting g1
259    Yielded g1 ham
260    Starting g2
261    Yielded g2 spam
262    Finishing g2
263    Finishing g1
264    nybbles have exploded with delight
265    """
266    trace = []
267    def g1():
268        try:
269            trace.append("Starting g1")
270            yield "g1 ham"
271            yield from g2()
272            yield "g1 eggs"
273        finally:
274            trace.append("Finishing g1")
275    def g2():
276        try:
277            trace.append("Starting g2")
278            yield "g2 spam"
279            yield "g2 more spam"
280        finally:
281            trace.append("Finishing g2")
282            raise ValueError("nybbles have exploded with delight")
283    try:
284        g = g1()
285        for i in range(2):
286            x = next(g)
287            trace.append("Yielded %s" % (x,))
288        g.close()
289    except ValueError as e:
290        trace.append(e.args[0])
291        # FIXME: __context__ is currently not set
292        #if sys.version_info[0] >= 3:
293        #    assert isinstance(e.__context__, GeneratorExit), 'exception context is %r' % e.__context__
294    else:
295        trace.append("subgenerator failed to raise ValueError")
296    return trace
297
298def test_delegating_throw():
299    """
300    >>> _lines(test_delegating_throw())
301    Starting g1
302    Yielded g1 ham
303    Starting g2
304    Yielded g2 spam
305    Finishing g2
306    Finishing g1
307    """
308    trace = []
309    def g1():
310        try:
311            trace.append("Starting g1")
312            yield "g1 ham"
313            yield from g2()
314            yield "g1 eggs"
315        finally:
316            trace.append("Finishing g1")
317    def g2():
318        try:
319            trace.append("Starting g2")
320            yield "g2 spam"
321            yield "g2 more spam"
322        finally:
323            trace.append("Finishing g2")
324    try:
325        g = g1()
326        for i in range(2):
327            x = next(g)
328            trace.append("Yielded %s" % (x,))
329        e = ValueError("tomato ejected")
330        g.throw(e)
331    except ValueError:
332        pass
333    else:
334        trace.append("subgenerator failed to raise ValueError")
335    return trace
336
337def __test_value_attribute_of_StopIteration_exception():
338    """
339    StopIteration:
340    value = None
341    StopIteration: spam
342    value = spam
343    StopIteration: spam
344    value = eggs
345    """
346    trace = []
347    def pex(e):
348        trace.append("%s: %s" % (e.__class__.__name__, e))
349        trace.append("value = %s" % (e.value,))
350    e = StopIteration()
351    pex(e)
352    e = StopIteration("spam")
353    pex(e)
354    e.value = "eggs"
355    pex(e)
356    return trace
357
358
359def test_exception_value_crash():
360    """
361    >>> test_exception_value_crash()
362    ['g2']
363    """
364    # There used to be a refcount error in CPython when the return value
365    # stored in the StopIteration has a refcount of 1.
366    def g1():
367        yield from g2()
368    def g2():
369        yield "g2"
370        return [42]
371    return list(g1())
372
373
374def test_return_none():
375    """
376    >>> test_return_none()
377    ['g2']
378    """
379    # There used to be a refcount error in CPython when the return value
380    # stored in the StopIteration has a refcount of 1.
381    def g1():
382        yield from g2()
383    def g2():
384        yield "g2"
385        return None
386    return list(g1())
387
388
389def test_finally_return_none(raise_exc=None):
390    """
391    >>> gen = test_finally_return_none()
392    >>> next(gen)
393    'g2'
394    >>> next(gen)
395    Traceback (most recent call last):
396    StopIteration
397
398    >>> gen = test_finally_return_none()
399    >>> next(gen)
400    'g2'
401    >>> try: gen.throw(ValueError())
402    ... except StopIteration: pass
403    ... else: print("FAILED")
404    """
405    # There used to be a refcount error in CPython when the return value
406    # stored in the StopIteration has a refcount of 1.
407    def g1():
408        yield from g2()
409    def g2():
410        try:
411            yield "g2"
412        finally:
413            return None
414    return g1()
415
416
417def test_generator_return_value():
418    """
419    >>> _lines(test_generator_return_value())
420    Starting g1
421    Yielded g1 ham
422    Starting g2
423    Yielded g2 spam
424    Yielded g2 more spam
425    Finishing g2
426    g2 returned None
427    Starting g2
428    Yielded g2 spam
429    Yielded g2 more spam
430    Finishing g2
431    g2 returned 42
432    Yielded g1 eggs
433    Finishing g1
434    """
435    trace = []
436    def g1():
437        trace.append("Starting g1")
438        yield "g1 ham"
439        ret = yield from g2()
440        trace.append("g2 returned %s" % (ret,))
441        ret = yield from g2(42)
442        trace.append("g2 returned %s" % (ret,))
443        yield "g1 eggs"
444        trace.append("Finishing g1")
445    def g2(v = None):
446        trace.append("Starting g2")
447        yield "g2 spam"
448        yield "g2 more spam"
449        trace.append("Finishing g2")
450        if v:
451            return v
452    for x in g1():
453        trace.append("Yielded %s" % (x,))
454    return trace
455
456def test_delegation_of_next_to_non_generator():
457    """
458    >>> _lines(test_delegation_of_next_to_non_generator())
459    Yielded 0
460    Yielded 1
461    Yielded 2
462    """
463    trace = []
464    def g():
465        yield from range(3)
466    for x in g():
467        trace.append("Yielded %s" % (x,))
468    return trace
469
470def test_conversion_of_sendNone_to_next():
471    """
472    >>> _lines(test_conversion_of_sendNone_to_next())
473    Yielded: 0
474    Yielded: 1
475    Yielded: 2
476    """
477    trace = []
478    def g():
479        yield from range(3)
480    gi = g()
481    for x in range(3):
482        y = gi.send(None)
483        trace.append("Yielded: %s" % (y,))
484    return trace
485
486def test_delegation_of_close_to_non_generator():
487    """
488    >>> _lines(test_delegation_of_close_to_non_generator())
489    starting g
490    finishing g
491    """
492    trace = []
493    def g():
494        try:
495            trace.append("starting g")
496            yield from range(3)
497            trace.append("g should not be here")
498        finally:
499            trace.append("finishing g")
500    gi = g()
501    next(gi)
502    gi.close()
503    return trace
504
505def test_delegating_throw_to_non_generator():
506    """
507    >>> _lines(test_delegating_throw_to_non_generator())
508    Starting g
509    Yielded 0
510    Yielded 1
511    Yielded 2
512    Yielded 3
513    Yielded 4
514    Finishing g
515    """
516    trace = []
517    def g():
518        try:
519            trace.append("Starting g")
520            yield from range(10)
521        finally:
522            trace.append("Finishing g")
523    try:
524        gi = g()
525        for i in range(5):
526            x = next(gi)
527            trace.append("Yielded %s" % (x,))
528        e = ValueError("tomato ejected")
529        gi.throw(e)
530    except ValueError:
531        pass
532    else:
533        trace.append("subgenerator failed to raise ValueError")
534    return trace
535
536def test_attempting_to_send_to_non_generator():
537    """
538    >>> _lines(test_attempting_to_send_to_non_generator())
539    starting g
540    finishing g
541    """
542    trace = []
543    def g():
544        try:
545            trace.append("starting g")
546            yield from range(3)
547            trace.append("g should not be here")
548        finally:
549            trace.append("finishing g")
550    try:
551        gi = g()
552        next(gi)
553        for x in range(3):
554            y = gi.send(42)
555            trace.append("Should not have yielded: %s" % y)
556    except AttributeError:
557        pass
558    else:
559        trace.append("was able to send into non-generator")
560    return trace
561
562def test_broken_getattr_handling():
563    """
564    >>> test_broken_getattr_handling()
565    []
566    """
567    class Broken:
568        def __iter__(self):
569            return self
570        def __next__(self):
571            return 1
572        next = __next__
573        def __getattr__(self, attr):
574            1/0
575
576    def g():
577        yield from Broken()
578
579    not_raised = []
580    try:
581        gi = g()
582        assert next(gi) == 1
583        gi.send(1)
584    except ZeroDivisionError:
585        pass
586    else:
587        not_raised.append(1)
588
589    try:
590        gi = g()
591        assert next(gi) == 1
592        gi.throw(AttributeError)
593    except ZeroDivisionError:
594        pass
595    else:
596        not_raised.append(2)
597
598    """
599    # this currently only calls PyErr_WriteUnraisable() and doesn't raise ...
600    try:
601        gi = g()
602        assert next(gi) == 1
603        gi.close()
604    except ZeroDivisionError:
605        pass
606    else:
607        not_raised.append(3)
608    """
609    gi = g()
610    assert next(gi) == 1
611    gi.close()
612
613    return not_raised
614
615def test_exception_in_initial_next_call():
616    """
617    >>> _lines(test_exception_in_initial_next_call())
618    g1 about to yield from g2
619    """
620    trace = []
621    def g1():
622        trace.append("g1 about to yield from g2")
623        yield from g2()
624        trace.append("g1 should not be here")
625    def g2():
626        yield 1/0
627    def run():
628        gi = g1()
629        next(gi)
630    try:
631        run()
632    except ZeroDivisionError:
633        pass
634    else:
635        trace.append("ZeroDivisionError not raised")
636    return trace
637
638def test_attempted_yield_from_loop():
639    """
640    >>> _lines(test_attempted_yield_from_loop())
641    g1: starting
642    Yielded: y1
643    g1: about to yield from g2
644    g2: starting
645    Yielded: y2
646    g2: about to yield from g1
647    """
648    trace = []
649    def g1():
650        trace.append("g1: starting")
651        yield "y1"
652        trace.append("g1: about to yield from g2")
653        yield from g2()
654        trace.append("g1 should not be here")
655
656    def g2():
657        trace.append("g2: starting")
658        yield "y2"
659        trace.append("g2: about to yield from g1")
660        yield from gi
661        trace.append("g2 should not be here")
662    try:
663        gi = g1()
664        for y in gi:
665            trace.append("Yielded: %s" % (y,))
666    except ValueError:
667        pass # "generator already executing"
668    else:
669        trace.append("subgenerator didn't raise ValueError")
670    return trace
671
672def test_attempted_reentry():
673    """
674    >>> _lines(test_attempted_reentry())
675    g1: starting
676    Yielded: y1
677    g1: about to yield from g2
678    g2: starting
679    Yielded: y2
680    g2: about to yield from g1
681    g2: caught ValueError
682    Yielded: y3
683    g1: after delegating to g2
684    Yielded: y4
685    """
686    trace = []
687    def g1():
688        trace.append("g1: starting")
689        yield "y1"
690        trace.append("g1: about to yield from g2")
691        yield from g2()
692        trace.append("g1: after delegating to g2")
693        yield "y4"
694
695    def g2():
696        trace.append("g2: starting")
697        yield "y2"
698        trace.append("g2: about to yield from g1")
699        try:
700            yield from gi
701        except ValueError:
702            trace.append("g2: caught ValueError")
703        else:
704            trace.append("g1 did not raise ValueError on reentry")
705        yield "y3"
706    gi = g1()
707    for y in gi:
708        trace.append("Yielded: %s" % (y,))
709    return trace
710
711def test_returning_value_from_delegated_throw():
712    """
713    >>> _lines(test_returning_value_from_delegated_throw())
714    Starting g1
715    Yielded g1 ham
716    Starting g2
717    Yielded g2 spam
718    Caught LunchError in g2
719    Yielded g2 yet more spam
720    Yielded g1 eggs
721    Finishing g1
722    """
723    trace = []
724    def g1():
725        try:
726            trace.append("Starting g1")
727            yield "g1 ham"
728            yield from g2()
729            yield "g1 eggs"
730        finally:
731            trace.append("Finishing g1")
732    def g2():
733        try:
734            trace.append("Starting g2")
735            yield "g2 spam"
736            yield "g2 more spam"
737        except LunchError:
738            trace.append("Caught LunchError in g2")
739            yield "g2 lunch saved"
740            yield "g2 yet more spam"
741    class LunchError(Exception):
742        pass
743    g = g1()
744    for i in range(2):
745        x = next(g)
746        trace.append("Yielded %s" % (x,))
747    e = LunchError("tomato ejected")
748    g.throw(e)
749    for x in g:
750        trace.append("Yielded %s" % (x,))
751    return trace
752
753def test_next_and_return_with_value():
754    """
755    >>> _lines(test_next_and_return_with_value())
756    g starting
757    f resuming g
758    g returning None
759    f caught StopIteration
760    g starting
761    f resuming g
762    g returning 42
763    f caught StopIteration
764    """
765    trace = []
766    def f(r):
767        gi = g(r)
768        next(gi)
769        try:
770            trace.append("f resuming g")
771            next(gi)
772            trace.append("f SHOULD NOT BE HERE")
773        except StopIteration:
774            trace.append("f caught StopIteration")
775    def g(r):
776        trace.append("g starting")
777        yield
778        trace.append("g returning %s" % (r,))
779        return r
780    f(None)
781    f(42)
782    return trace
783
784def test_send_and_return_with_value():
785    """
786    >>> _lines(test_send_and_return_with_value())
787    g starting
788    f sending spam to g
789    g received spam
790    g returning None
791    f caught StopIteration
792    g starting
793    f sending spam to g
794    g received spam
795    g returning 42
796    f caught StopIteration
797    """
798    trace = []
799    def f(r):
800        gi = g(r)
801        next(gi)
802        try:
803            trace.append("f sending spam to g")
804            gi.send("spam")
805            trace.append("f SHOULD NOT BE HERE")
806        except StopIteration:
807            trace.append("f caught StopIteration")
808    def g(r):
809        trace.append("g starting")
810        x = yield
811        trace.append("g received %s" % (x,))
812        trace.append("g returning %s" % (r,))
813        return r
814    f(None)
815    f(42)
816    return trace
817
818def test_catching_exception_from_subgen_and_returning():
819    """
820    Test catching an exception thrown into a
821    subgenerator and returning a value
822
823    >>> _lines(test_catching_exception_from_subgen_and_returning())
824    1
825    inner caught ValueError
826    inner returned 2 to outer
827    2
828    """
829    trace = []
830    def inner():
831        try:
832            yield 1
833        except ValueError:
834            trace.append("inner caught ValueError")
835        return 2
836
837    def outer():
838        v = yield from inner()
839        trace.append("inner returned %r to outer" % v)
840        yield v
841    g = outer()
842    trace.append(next(g))
843    trace.append(g.throw(ValueError))
844    return trace
845
846def test_throwing_GeneratorExit_into_subgen_that_returns():
847    """
848    Test throwing GeneratorExit into a subgenerator that
849    catches it and returns normally.
850
851    >>> _lines(test_throwing_GeneratorExit_into_subgen_that_returns())
852    Enter g
853    Enter f
854    """
855    trace = []
856    def f():
857        try:
858            trace.append("Enter f")
859            yield
860            trace.append("Exit f")
861        except GeneratorExit:
862            return
863    def g():
864        trace.append("Enter g")
865        yield from f()
866        trace.append("Exit g")
867    try:
868        gi = g()
869        next(gi)
870        gi.throw(GeneratorExit)
871    except GeneratorExit:
872        pass
873    else:
874        trace.append("subgenerator failed to raise GeneratorExit")
875    return trace
876
877def test_throwing_GeneratorExit_into_subgenerator_that_yields():
878    """
879    Test throwing GeneratorExit into a subgenerator that
880    catches it and yields.
881
882    >>> _lines(test_throwing_GeneratorExit_into_subgenerator_that_yields())
883    Enter g
884    Enter f
885    """
886    trace = []
887    def f():
888        try:
889            trace.append("Enter f")
890            yield
891            trace.append("Exit f")
892        except GeneratorExit:
893            yield
894    def g():
895        trace.append("Enter g")
896        yield from f()
897        trace.append("Exit g")
898    try:
899        gi = g()
900        next(gi)
901        gi.throw(GeneratorExit)
902    except RuntimeError:
903        pass # "generator ignored GeneratorExit"
904    else:
905        trace.append("subgenerator failed to raise GeneratorExit")
906    return trace
907
908def test_throwing_GeneratorExit_into_subgen_that_raises():
909    """
910    Test throwing GeneratorExit into a subgenerator that
911    catches it and raises a different exception.
912
913    >>> _lines(test_throwing_GeneratorExit_into_subgen_that_raises())
914    Enter g
915    Enter f
916    """
917    trace = []
918    def f():
919        try:
920            trace.append("Enter f")
921            yield
922            trace.append("Exit f")
923        except GeneratorExit:
924            raise ValueError("Vorpal bunny encountered")
925    def g():
926        trace.append("Enter g")
927        yield from f()
928        trace.append("Exit g")
929    try:
930        gi = g()
931        next(gi)
932        gi.throw(GeneratorExit)
933    except ValueError:
934        pass # "Vorpal bunny encountered"
935    else:
936        trace.append("subgenerator failed to raise ValueError")
937    return trace
938
939def test_yield_from_empty():
940    """
941    >>> test_yield_from_empty()
942    """
943    def g():
944        yield from ()
945    try:
946        next(g())
947    except StopIteration:
948        pass
949    else:
950        return "FAILED"
951
952# test re-entry guards
953
954def _reentering_gen():
955    def one():
956        yield 0
957        yield from two()
958        yield 3
959    def two():
960        yield 1
961        try:
962            yield from g1
963        except ValueError:
964            pass
965        yield 2
966    g1 = one()
967    return g1
968
969def test_delegating_generators_claim_to_be_running_next():
970    """
971    >>> test_delegating_generators_claim_to_be_running_next()
972    [0, 1, 2, 3]
973    """
974    return list(_reentering_gen())
975
976def test_delegating_generators_claim_to_be_running_send():
977    """
978    >>> test_delegating_generators_claim_to_be_running_send()
979    [0, 1, 2, 3]
980    """
981    g1 = _reentering_gen()
982    res = [next(g1)]
983    try:
984        while True:
985            res.append(g1.send(42))
986    except StopIteration:
987        pass
988    return res
989
990def test_delegating_generators_claim_to_be_running_throw():
991    """
992    >>> test_delegating_generators_claim_to_be_running_throw()
993    [0, 1, 2, 3]
994    """
995    class MyErr(Exception):
996        pass
997    def one():
998        try:
999            yield 0
1000        except MyErr:
1001            pass
1002        yield from two()
1003        try:
1004            yield 3
1005        except MyErr:
1006            pass
1007    def two():
1008        try:
1009            yield 1
1010        except MyErr:
1011            pass
1012        try:
1013            yield from g1
1014        except ValueError:
1015            pass
1016        try:
1017            yield 2
1018        except MyErr:
1019            pass
1020    g1 = one()
1021    res = [next(g1)]
1022    try:
1023        while True:
1024            res.append(g1.throw(MyErr))
1025    except StopIteration:
1026        pass
1027    return res
1028
1029def test_delegating_generators_claim_to_be_running_close():
1030    """
1031    >>> test_delegating_generators_claim_to_be_running_close()
1032    42
1033    """
1034    class MyIt(object):
1035        def __iter__(self):
1036            return self
1037        def __next__(self):
1038            return 42
1039        next = __next__
1040        def close(self):
1041            assert g1.gi_running
1042            try:
1043                next(g1)
1044            except ValueError:
1045                pass # guard worked
1046            else:
1047                assert False, "re-entry guard failed to bark"
1048    def one():
1049        yield from MyIt()
1050    g1 = one()
1051    ret = next(g1)
1052    g1.close()
1053    return ret
1054
1055
1056def yield_in_return(x):
1057    """
1058    >>> x = yield_in_return(range(3))
1059    >>> for _ in range(10):
1060    ...     try:
1061    ...         print(next(x))
1062    ...     except StopIteration:
1063    ...         if sys.version_info >= (3,3):
1064    ...             print(sys.exc_info()[1].value is None)
1065    ...         else:
1066    ...             print(True)
1067    ...         break
1068    0
1069    1
1070    2
1071    True
1072    """
1073    return (yield from x)
1074
1075
1076def gi_yieldfrom(it):
1077    """
1078    >>> it = iter([1, 2, 3])
1079    >>> g = gi_yieldfrom(it)
1080    >>> g.gi_yieldfrom is None or "ERROR: %r" % g.gi_yieldfrom
1081    True
1082    >>> next(g)
1083    1
1084    >>> g.gi_yieldfrom is it or "ERROR: %r" % g.gi_yieldfrom
1085    True
1086    """
1087    x = yield from it
1088    return x
1089