4
Test suite for PEP 380 implementation
6
adapted from original tests written by Greg Ewing
7
see <https://www.cosc.canterbury.ac.nz/greg.ewing/python/yield-from/YieldFrom-Python3.1.2-rev5.zip>
18
def test_delegation_of_initial_next_to_subgenerator():
20
>>> _lines(test_delegation_of_initial_next_to_subgenerator())
29
trace.append("Starting g1")
31
trace.append("Finishing g1")
33
trace.append("Starting g2")
35
trace.append("Finishing g2")
37
trace.append("Yielded %s" % (x,))
40
def test_raising_exception_in_initial_next_call():
42
>>> _lines(test_raising_exception_in_initial_next_call())
51
trace.append("Starting g1")
54
trace.append("Finishing g1")
57
trace.append("Starting g2")
58
raise ValueError("spanish inquisition occurred")
60
trace.append("Finishing g2")
63
trace.append("Yielded %s" % (x,))
64
except ValueError as e:
67
trace.append("subgenerator failed to raise ValueError")
70
def test_delegation_of_next_call_to_subgenerator():
72
>>> _lines(test_delegation_of_next_call_to_subgenerator())
84
trace.append("Starting g1")
88
trace.append("Finishing g1")
90
trace.append("Starting g2")
93
trace.append("Finishing g2")
95
trace.append("Yielded %s" % (x,))
98
def test_raising_exception_in_delegated_next_call():
100
>>> _lines(test_raising_exception_in_delegated_next_call())
111
trace.append("Starting g1")
116
trace.append("Finishing g1")
119
trace.append("Starting g2")
121
raise ValueError("hovercraft is full of eels")
124
trace.append("Finishing g2")
127
trace.append("Yielded %s" % (x,))
131
trace.append("subgenerator failed to raise ValueError")
134
def test_delegation_of_send():
136
>>> _lines(test_delegation_of_send())
151
trace.append("Starting g1")
153
trace.append("g1 received %s" % (x,))
156
trace.append("g1 received %s" % (x,))
157
trace.append("Finishing g1")
159
trace.append("Starting g2")
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")
171
trace.append("Yielded %s" % (y,))
173
except StopIteration:
177
def test_handling_exception_while_delegating_send():
179
>>> _lines(test_handling_exception_while_delegating_send())
188
trace.append("Starting g1")
190
trace.append("g1 received %s" % (x,))
193
trace.append("g1 received %s" % (x,))
194
trace.append("Finishing g1")
196
trace.append("Starting g2")
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")
210
trace.append("Yielded %s" % (y,))
212
except StopIteration:
213
trace.append("StopIteration")
219
trace.append("no ValueError")
222
def test_delegating_close():
224
>>> _lines(test_delegating_close())
235
trace.append("Starting g1")
240
trace.append("Finishing g1")
243
trace.append("Starting g2")
247
trace.append("Finishing g2")
251
trace.append("Yielded %s" % (x,))
255
def test_handing_exception_while_delegating_close():
257
>>> _lines(test_handing_exception_while_delegating_close())
264
nybbles have exploded with delight
269
trace.append("Starting g1")
274
trace.append("Finishing g1")
277
trace.append("Starting g2")
281
trace.append("Finishing g2")
282
raise ValueError("nybbles have exploded with delight")
287
trace.append("Yielded %s" % (x,))
289
except ValueError as e:
290
trace.append(e.args[0])
291
# FIXME: __context__ is currently not set
292
#assert isinstance(e.__context__, GeneratorExit), 'exception context is %r' % e.__context__
294
trace.append("subgenerator failed to raise ValueError")
297
def test_delegating_throw():
299
>>> _lines(test_delegating_throw())
310
trace.append("Starting g1")
315
trace.append("Finishing g1")
318
trace.append("Starting g2")
322
trace.append("Finishing g2")
327
trace.append("Yielded %s" % (x,))
328
e = ValueError("tomato ejected")
333
trace.append("subgenerator failed to raise ValueError")
336
def __test_value_attribute_of_StopIteration_exception():
347
trace.append("%s: %s" % (e.__class__.__name__, e))
348
trace.append("value = %s" % (e.value,))
351
e = StopIteration("spam")
358
def test_exception_value_crash():
360
>>> test_exception_value_crash()
363
# There used to be a refcount error in CPython when the return value
364
# stored in the StopIteration has a refcount of 1.
373
def test_return_none():
375
>>> test_return_none()
378
# There used to be a refcount error in CPython when the return value
379
# stored in the StopIteration has a refcount of 1.
388
def test_finally_return_none(raise_exc=None):
390
>>> gen = test_finally_return_none()
394
Traceback (most recent call last):
397
>>> gen = test_finally_return_none()
400
>>> try: gen.throw(ValueError())
401
... except StopIteration: pass
402
... else: print("FAILED")
404
# There used to be a refcount error in CPython when the return value
405
# stored in the StopIteration has a refcount of 1.
416
def test_generator_return_value():
418
>>> _lines(test_generator_return_value())
436
trace.append("Starting g1")
438
ret = yield from g2()
439
trace.append("g2 returned %s" % (ret,))
440
ret = yield from g2(42)
441
trace.append("g2 returned %s" % (ret,))
443
trace.append("Finishing g1")
445
trace.append("Starting g2")
448
trace.append("Finishing g2")
452
trace.append("Yielded %s" % (x,))
455
def test_delegation_of_next_to_non_generator():
457
>>> _lines(test_delegation_of_next_to_non_generator())
466
trace.append("Yielded %s" % (x,))
469
def test_conversion_of_sendNone_to_next():
471
>>> _lines(test_conversion_of_sendNone_to_next())
482
trace.append("Yielded: %s" % (y,))
485
def test_delegation_of_close_to_non_generator():
487
>>> _lines(test_delegation_of_close_to_non_generator())
494
trace.append("starting g")
496
trace.append("g should not be here")
498
trace.append("finishing g")
504
def test_delegating_throw_to_non_generator():
506
>>> _lines(test_delegating_throw_to_non_generator())
518
trace.append("Starting g")
521
trace.append("Finishing g")
526
trace.append("Yielded %s" % (x,))
527
e = ValueError("tomato ejected")
532
trace.append("subgenerator failed to raise ValueError")
535
def test_attempting_to_send_to_non_generator():
537
>>> _lines(test_attempting_to_send_to_non_generator())
544
trace.append("starting g")
546
trace.append("g should not be here")
548
trace.append("finishing g")
554
trace.append("Should not have yielded: %s" % y)
555
except AttributeError:
558
trace.append("was able to send into non-generator")
561
def test_broken_getattr_handling():
563
>>> test_broken_getattr_handling()
572
def __getattr__(self, attr):
583
except ZeroDivisionError:
591
gi.throw(AttributeError)
592
except ZeroDivisionError:
598
# this currently only calls PyErr_WriteUnraisable() and doesn't raise ...
603
except ZeroDivisionError:
614
def test_exception_in_initial_next_call():
616
>>> _lines(test_exception_in_initial_next_call())
617
g1 about to yield from g2
621
trace.append("g1 about to yield from g2")
623
trace.append("g1 should not be here")
631
except ZeroDivisionError:
634
trace.append("ZeroDivisionError not raised")
637
def test_attempted_yield_from_loop():
639
>>> _lines(test_attempted_yield_from_loop())
642
g1: about to yield from g2
645
g2: about to yield from g1
649
trace.append("g1: starting")
651
trace.append("g1: about to yield from g2")
653
trace.append("g1 should not be here")
656
trace.append("g2: starting")
658
trace.append("g2: about to yield from g1")
660
trace.append("g2 should not be here")
664
trace.append("Yielded: %s" % (y,))
666
pass # "generator already executing"
668
trace.append("subgenerator didn't raise ValueError")
671
def test_attempted_reentry():
673
>>> _lines(test_attempted_reentry())
676
g1: about to yield from g2
679
g2: about to yield from g1
680
g2: caught ValueError
682
g1: after delegating to g2
687
trace.append("g1: starting")
689
trace.append("g1: about to yield from g2")
691
trace.append("g1: after delegating to g2")
695
trace.append("g2: starting")
697
trace.append("g2: about to yield from g1")
701
trace.append("g2: caught ValueError")
703
trace.append("g1 did not raise ValueError on reentry")
707
trace.append("Yielded: %s" % (y,))
710
def test_returning_value_from_delegated_throw():
712
>>> _lines(test_returning_value_from_delegated_throw())
717
Caught LunchError in g2
718
Yielded g2 yet more spam
725
trace.append("Starting g1")
730
trace.append("Finishing g1")
733
trace.append("Starting g2")
737
trace.append("Caught LunchError in g2")
738
yield "g2 lunch saved"
739
yield "g2 yet more spam"
740
class LunchError(Exception):
745
trace.append("Yielded %s" % (x,))
746
e = LunchError("tomato ejected")
749
trace.append("Yielded %s" % (x,))
752
def test_next_and_return_with_value():
754
>>> _lines(test_next_and_return_with_value())
758
f caught StopIteration
762
f caught StopIteration
769
trace.append("f resuming g")
771
trace.append("f SHOULD NOT BE HERE")
772
except StopIteration:
773
trace.append("f caught StopIteration")
775
trace.append("g starting")
777
trace.append("g returning %s" % (r,))
783
def test_send_and_return_with_value():
785
>>> _lines(test_send_and_return_with_value())
790
f caught StopIteration
795
f caught StopIteration
802
trace.append("f sending spam to g")
804
trace.append("f SHOULD NOT BE HERE")
805
except StopIteration:
806
trace.append("f caught StopIteration")
808
trace.append("g starting")
810
trace.append("g received %s" % (x,))
811
trace.append("g returning %s" % (r,))
817
def test_catching_exception_from_subgen_and_returning():
819
Test catching an exception thrown into a
820
subgenerator and returning a value
822
>>> _lines(test_catching_exception_from_subgen_and_returning())
824
inner caught ValueError
825
inner returned 2 to outer
833
trace.append("inner caught ValueError")
837
v = yield from inner()
838
trace.append("inner returned %r to outer" % v)
841
trace.append(next(g))
842
trace.append(g.throw(ValueError))
845
def test_throwing_GeneratorExit_into_subgen_that_returns():
847
Test throwing GeneratorExit into a subgenerator that
848
catches it and returns normally.
850
>>> _lines(test_throwing_GeneratorExit_into_subgen_that_returns())
857
trace.append("Enter f")
859
trace.append("Exit f")
860
except GeneratorExit:
863
trace.append("Enter g")
865
trace.append("Exit g")
869
gi.throw(GeneratorExit)
870
except GeneratorExit:
873
trace.append("subgenerator failed to raise GeneratorExit")
876
def test_throwing_GeneratorExit_into_subgenerator_that_yields():
878
Test throwing GeneratorExit into a subgenerator that
879
catches it and yields.
881
>>> _lines(test_throwing_GeneratorExit_into_subgenerator_that_yields())
888
trace.append("Enter f")
890
trace.append("Exit f")
891
except GeneratorExit:
894
trace.append("Enter g")
896
trace.append("Exit g")
900
gi.throw(GeneratorExit)
902
pass # "generator ignored GeneratorExit"
904
trace.append("subgenerator failed to raise GeneratorExit")
907
def test_throwing_GeneratorExit_into_subgen_that_raises():
909
Test throwing GeneratorExit into a subgenerator that
910
catches it and raises a different exception.
912
>>> _lines(test_throwing_GeneratorExit_into_subgen_that_raises())
919
trace.append("Enter f")
921
trace.append("Exit f")
922
except GeneratorExit:
923
raise ValueError("Vorpal bunny encountered")
925
trace.append("Enter g")
927
trace.append("Exit g")
931
gi.throw(GeneratorExit)
933
pass # "Vorpal bunny encountered"
935
trace.append("subgenerator failed to raise ValueError")
938
def test_yield_from_empty():
940
>>> test_yield_from_empty()
946
except StopIteration:
951
# test re-entry guards
953
def _reentering_gen():
968
def test_delegating_generators_claim_to_be_running_next():
970
>>> test_delegating_generators_claim_to_be_running_next()
973
return list(_reentering_gen())
975
def test_delegating_generators_claim_to_be_running_send():
977
>>> test_delegating_generators_claim_to_be_running_send()
980
g1 = _reentering_gen()
984
res.append(g1.send(42))
985
except StopIteration:
989
def test_delegating_generators_claim_to_be_running_throw():
991
>>> test_delegating_generators_claim_to_be_running_throw()
994
class MyErr(Exception):
1023
res.append(g1.throw(MyErr))
1024
except StopIteration:
1028
def test_delegating_generators_claim_to_be_running_close():
1030
>>> test_delegating_generators_claim_to_be_running_close()
1040
assert g1.gi_running
1046
assert False, "re-entry guard failed to bark"
1055
def yield_in_return(x):
1057
>>> x = yield_in_return(range(3))
1058
>>> for _ in range(10):
1061
... except StopIteration:
1062
... print(sys.exc_info()[1].value is None)
1069
return (yield from x)
1072
def gi_yieldfrom(it):
1074
>>> it = iter([1, 2, 3])
1075
>>> g = gi_yieldfrom(it)
1076
>>> g.gi_yieldfrom is None or "ERROR: %r" % g.gi_yieldfrom
1080
>>> g.gi_yieldfrom is it or "ERROR: %r" % g.gi_yieldfrom