cython

Форк
0
/
yield_from_pep380.pyx 
1084 строки · 24.8 Кб
1
# -*- coding: utf-8 -*-
2

3
"""
4
Test suite for PEP 380 implementation
5

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>
8
"""
9

10
import sys
11

12

13
def _lines(trace):
14
    for line in trace:
15
        print(line)
16

17

18
def 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

40
def 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

70
def 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

98
def 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

134
def 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

177
def 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

222
def 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

255
def 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
        #assert isinstance(e.__context__, GeneratorExit), 'exception context is %r' % e.__context__
293
    else:
294
        trace.append("subgenerator failed to raise ValueError")
295
    return trace
296

297
def test_delegating_throw():
298
    """
299
    >>> _lines(test_delegating_throw())
300
    Starting g1
301
    Yielded g1 ham
302
    Starting g2
303
    Yielded g2 spam
304
    Finishing g2
305
    Finishing g1
306
    """
307
    trace = []
308
    def g1():
309
        try:
310
            trace.append("Starting g1")
311
            yield "g1 ham"
312
            yield from g2()
313
            yield "g1 eggs"
314
        finally:
315
            trace.append("Finishing g1")
316
    def g2():
317
        try:
318
            trace.append("Starting g2")
319
            yield "g2 spam"
320
            yield "g2 more spam"
321
        finally:
322
            trace.append("Finishing g2")
323
    try:
324
        g = g1()
325
        for i in range(2):
326
            x = next(g)
327
            trace.append("Yielded %s" % (x,))
328
        e = ValueError("tomato ejected")
329
        g.throw(e)
330
    except ValueError:
331
        pass
332
    else:
333
        trace.append("subgenerator failed to raise ValueError")
334
    return trace
335

336
def __test_value_attribute_of_StopIteration_exception():
337
    """
338
    StopIteration:
339
    value = None
340
    StopIteration: spam
341
    value = spam
342
    StopIteration: spam
343
    value = eggs
344
    """
345
    trace = []
346
    def pex(e):
347
        trace.append("%s: %s" % (e.__class__.__name__, e))
348
        trace.append("value = %s" % (e.value,))
349
    e = StopIteration()
350
    pex(e)
351
    e = StopIteration("spam")
352
    pex(e)
353
    e.value = "eggs"
354
    pex(e)
355
    return trace
356

357

358
def test_exception_value_crash():
359
    """
360
    >>> test_exception_value_crash()
361
    ['g2']
362
    """
363
    # There used to be a refcount error in CPython when the return value
364
    # stored in the StopIteration has a refcount of 1.
365
    def g1():
366
        yield from g2()
367
    def g2():
368
        yield "g2"
369
        return [42]
370
    return list(g1())
371

372

373
def test_return_none():
374
    """
375
    >>> test_return_none()
376
    ['g2']
377
    """
378
    # There used to be a refcount error in CPython when the return value
379
    # stored in the StopIteration has a refcount of 1.
380
    def g1():
381
        yield from g2()
382
    def g2():
383
        yield "g2"
384
        return None
385
    return list(g1())
386

387

388
def test_finally_return_none(raise_exc=None):
389
    """
390
    >>> gen = test_finally_return_none()
391
    >>> next(gen)
392
    'g2'
393
    >>> next(gen)
394
    Traceback (most recent call last):
395
    StopIteration
396

397
    >>> gen = test_finally_return_none()
398
    >>> next(gen)
399
    'g2'
400
    >>> try: gen.throw(ValueError())
401
    ... except StopIteration: pass
402
    ... else: print("FAILED")
403
    """
404
    # There used to be a refcount error in CPython when the return value
405
    # stored in the StopIteration has a refcount of 1.
406
    def g1():
407
        yield from g2()
408
    def g2():
409
        try:
410
            yield "g2"
411
        finally:
412
            return None
413
    return g1()
414

415

416
def test_generator_return_value():
417
    """
418
    >>> _lines(test_generator_return_value())
419
    Starting g1
420
    Yielded g1 ham
421
    Starting g2
422
    Yielded g2 spam
423
    Yielded g2 more spam
424
    Finishing g2
425
    g2 returned None
426
    Starting g2
427
    Yielded g2 spam
428
    Yielded g2 more spam
429
    Finishing g2
430
    g2 returned 42
431
    Yielded g1 eggs
432
    Finishing g1
433
    """
434
    trace = []
435
    def g1():
436
        trace.append("Starting g1")
437
        yield "g1 ham"
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,))
442
        yield "g1 eggs"
443
        trace.append("Finishing g1")
444
    def g2(v = None):
445
        trace.append("Starting g2")
446
        yield "g2 spam"
447
        yield "g2 more spam"
448
        trace.append("Finishing g2")
449
        if v:
450
            return v
451
    for x in g1():
452
        trace.append("Yielded %s" % (x,))
453
    return trace
454

455
def test_delegation_of_next_to_non_generator():
456
    """
457
    >>> _lines(test_delegation_of_next_to_non_generator())
458
    Yielded 0
459
    Yielded 1
460
    Yielded 2
461
    """
462
    trace = []
463
    def g():
464
        yield from range(3)
465
    for x in g():
466
        trace.append("Yielded %s" % (x,))
467
    return trace
468

469
def test_conversion_of_sendNone_to_next():
470
    """
471
    >>> _lines(test_conversion_of_sendNone_to_next())
472
    Yielded: 0
473
    Yielded: 1
474
    Yielded: 2
475
    """
476
    trace = []
477
    def g():
478
        yield from range(3)
479
    gi = g()
480
    for x in range(3):
481
        y = gi.send(None)
482
        trace.append("Yielded: %s" % (y,))
483
    return trace
484

485
def test_delegation_of_close_to_non_generator():
486
    """
487
    >>> _lines(test_delegation_of_close_to_non_generator())
488
    starting g
489
    finishing g
490
    """
491
    trace = []
492
    def g():
493
        try:
494
            trace.append("starting g")
495
            yield from range(3)
496
            trace.append("g should not be here")
497
        finally:
498
            trace.append("finishing g")
499
    gi = g()
500
    next(gi)
501
    gi.close()
502
    return trace
503

504
def test_delegating_throw_to_non_generator():
505
    """
506
    >>> _lines(test_delegating_throw_to_non_generator())
507
    Starting g
508
    Yielded 0
509
    Yielded 1
510
    Yielded 2
511
    Yielded 3
512
    Yielded 4
513
    Finishing g
514
    """
515
    trace = []
516
    def g():
517
        try:
518
            trace.append("Starting g")
519
            yield from range(10)
520
        finally:
521
            trace.append("Finishing g")
522
    try:
523
        gi = g()
524
        for i in range(5):
525
            x = next(gi)
526
            trace.append("Yielded %s" % (x,))
527
        e = ValueError("tomato ejected")
528
        gi.throw(e)
529
    except ValueError:
530
        pass
531
    else:
532
        trace.append("subgenerator failed to raise ValueError")
533
    return trace
534

535
def test_attempting_to_send_to_non_generator():
536
    """
537
    >>> _lines(test_attempting_to_send_to_non_generator())
538
    starting g
539
    finishing g
540
    """
541
    trace = []
542
    def g():
543
        try:
544
            trace.append("starting g")
545
            yield from range(3)
546
            trace.append("g should not be here")
547
        finally:
548
            trace.append("finishing g")
549
    try:
550
        gi = g()
551
        next(gi)
552
        for x in range(3):
553
            y = gi.send(42)
554
            trace.append("Should not have yielded: %s" % y)
555
    except AttributeError:
556
        pass
557
    else:
558
        trace.append("was able to send into non-generator")
559
    return trace
560

561
def test_broken_getattr_handling():
562
    """
563
    >>> test_broken_getattr_handling()
564
    []
565
    """
566
    class Broken:
567
        def __iter__(self):
568
            return self
569
        def __next__(self):
570
            return 1
571
        next = __next__
572
        def __getattr__(self, attr):
573
            1/0
574

575
    def g():
576
        yield from Broken()
577

578
    not_raised = []
579
    try:
580
        gi = g()
581
        assert next(gi) == 1
582
        gi.send(1)
583
    except ZeroDivisionError:
584
        pass
585
    else:
586
        not_raised.append(1)
587

588
    try:
589
        gi = g()
590
        assert next(gi) == 1
591
        gi.throw(AttributeError)
592
    except ZeroDivisionError:
593
        pass
594
    else:
595
        not_raised.append(2)
596

597
    """
598
    # this currently only calls PyErr_WriteUnraisable() and doesn't raise ...
599
    try:
600
        gi = g()
601
        assert next(gi) == 1
602
        gi.close()
603
    except ZeroDivisionError:
604
        pass
605
    else:
606
        not_raised.append(3)
607
    """
608
    gi = g()
609
    assert next(gi) == 1
610
    gi.close()
611

612
    return not_raised
613

614
def test_exception_in_initial_next_call():
615
    """
616
    >>> _lines(test_exception_in_initial_next_call())
617
    g1 about to yield from g2
618
    """
619
    trace = []
620
    def g1():
621
        trace.append("g1 about to yield from g2")
622
        yield from g2()
623
        trace.append("g1 should not be here")
624
    def g2():
625
        yield 1/0
626
    def run():
627
        gi = g1()
628
        next(gi)
629
    try:
630
        run()
631
    except ZeroDivisionError:
632
        pass
633
    else:
634
        trace.append("ZeroDivisionError not raised")
635
    return trace
636

637
def test_attempted_yield_from_loop():
638
    """
639
    >>> _lines(test_attempted_yield_from_loop())
640
    g1: starting
641
    Yielded: y1
642
    g1: about to yield from g2
643
    g2: starting
644
    Yielded: y2
645
    g2: about to yield from g1
646
    """
647
    trace = []
648
    def g1():
649
        trace.append("g1: starting")
650
        yield "y1"
651
        trace.append("g1: about to yield from g2")
652
        yield from g2()
653
        trace.append("g1 should not be here")
654

655
    def g2():
656
        trace.append("g2: starting")
657
        yield "y2"
658
        trace.append("g2: about to yield from g1")
659
        yield from gi
660
        trace.append("g2 should not be here")
661
    try:
662
        gi = g1()
663
        for y in gi:
664
            trace.append("Yielded: %s" % (y,))
665
    except ValueError:
666
        pass # "generator already executing"
667
    else:
668
        trace.append("subgenerator didn't raise ValueError")
669
    return trace
670

671
def test_attempted_reentry():
672
    """
673
    >>> _lines(test_attempted_reentry())
674
    g1: starting
675
    Yielded: y1
676
    g1: about to yield from g2
677
    g2: starting
678
    Yielded: y2
679
    g2: about to yield from g1
680
    g2: caught ValueError
681
    Yielded: y3
682
    g1: after delegating to g2
683
    Yielded: y4
684
    """
685
    trace = []
686
    def g1():
687
        trace.append("g1: starting")
688
        yield "y1"
689
        trace.append("g1: about to yield from g2")
690
        yield from g2()
691
        trace.append("g1: after delegating to g2")
692
        yield "y4"
693

694
    def g2():
695
        trace.append("g2: starting")
696
        yield "y2"
697
        trace.append("g2: about to yield from g1")
698
        try:
699
            yield from gi
700
        except ValueError:
701
            trace.append("g2: caught ValueError")
702
        else:
703
            trace.append("g1 did not raise ValueError on reentry")
704
        yield "y3"
705
    gi = g1()
706
    for y in gi:
707
        trace.append("Yielded: %s" % (y,))
708
    return trace
709

710
def test_returning_value_from_delegated_throw():
711
    """
712
    >>> _lines(test_returning_value_from_delegated_throw())
713
    Starting g1
714
    Yielded g1 ham
715
    Starting g2
716
    Yielded g2 spam
717
    Caught LunchError in g2
718
    Yielded g2 yet more spam
719
    Yielded g1 eggs
720
    Finishing g1
721
    """
722
    trace = []
723
    def g1():
724
        try:
725
            trace.append("Starting g1")
726
            yield "g1 ham"
727
            yield from g2()
728
            yield "g1 eggs"
729
        finally:
730
            trace.append("Finishing g1")
731
    def g2():
732
        try:
733
            trace.append("Starting g2")
734
            yield "g2 spam"
735
            yield "g2 more spam"
736
        except LunchError:
737
            trace.append("Caught LunchError in g2")
738
            yield "g2 lunch saved"
739
            yield "g2 yet more spam"
740
    class LunchError(Exception):
741
        pass
742
    g = g1()
743
    for i in range(2):
744
        x = next(g)
745
        trace.append("Yielded %s" % (x,))
746
    e = LunchError("tomato ejected")
747
    g.throw(e)
748
    for x in g:
749
        trace.append("Yielded %s" % (x,))
750
    return trace
751

752
def test_next_and_return_with_value():
753
    """
754
    >>> _lines(test_next_and_return_with_value())
755
    g starting
756
    f resuming g
757
    g returning None
758
    f caught StopIteration
759
    g starting
760
    f resuming g
761
    g returning 42
762
    f caught StopIteration
763
    """
764
    trace = []
765
    def f(r):
766
        gi = g(r)
767
        next(gi)
768
        try:
769
            trace.append("f resuming g")
770
            next(gi)
771
            trace.append("f SHOULD NOT BE HERE")
772
        except StopIteration:
773
            trace.append("f caught StopIteration")
774
    def g(r):
775
        trace.append("g starting")
776
        yield
777
        trace.append("g returning %s" % (r,))
778
        return r
779
    f(None)
780
    f(42)
781
    return trace
782

783
def test_send_and_return_with_value():
784
    """
785
    >>> _lines(test_send_and_return_with_value())
786
    g starting
787
    f sending spam to g
788
    g received spam
789
    g returning None
790
    f caught StopIteration
791
    g starting
792
    f sending spam to g
793
    g received spam
794
    g returning 42
795
    f caught StopIteration
796
    """
797
    trace = []
798
    def f(r):
799
        gi = g(r)
800
        next(gi)
801
        try:
802
            trace.append("f sending spam to g")
803
            gi.send("spam")
804
            trace.append("f SHOULD NOT BE HERE")
805
        except StopIteration:
806
            trace.append("f caught StopIteration")
807
    def g(r):
808
        trace.append("g starting")
809
        x = yield
810
        trace.append("g received %s" % (x,))
811
        trace.append("g returning %s" % (r,))
812
        return r
813
    f(None)
814
    f(42)
815
    return trace
816

817
def test_catching_exception_from_subgen_and_returning():
818
    """
819
    Test catching an exception thrown into a
820
    subgenerator and returning a value
821

822
    >>> _lines(test_catching_exception_from_subgen_and_returning())
823
    1
824
    inner caught ValueError
825
    inner returned 2 to outer
826
    2
827
    """
828
    trace = []
829
    def inner():
830
        try:
831
            yield 1
832
        except ValueError:
833
            trace.append("inner caught ValueError")
834
        return 2
835

836
    def outer():
837
        v = yield from inner()
838
        trace.append("inner returned %r to outer" % v)
839
        yield v
840
    g = outer()
841
    trace.append(next(g))
842
    trace.append(g.throw(ValueError))
843
    return trace
844

845
def test_throwing_GeneratorExit_into_subgen_that_returns():
846
    """
847
    Test throwing GeneratorExit into a subgenerator that
848
    catches it and returns normally.
849

850
    >>> _lines(test_throwing_GeneratorExit_into_subgen_that_returns())
851
    Enter g
852
    Enter f
853
    """
854
    trace = []
855
    def f():
856
        try:
857
            trace.append("Enter f")
858
            yield
859
            trace.append("Exit f")
860
        except GeneratorExit:
861
            return
862
    def g():
863
        trace.append("Enter g")
864
        yield from f()
865
        trace.append("Exit g")
866
    try:
867
        gi = g()
868
        next(gi)
869
        gi.throw(GeneratorExit)
870
    except GeneratorExit:
871
        pass
872
    else:
873
        trace.append("subgenerator failed to raise GeneratorExit")
874
    return trace
875

876
def test_throwing_GeneratorExit_into_subgenerator_that_yields():
877
    """
878
    Test throwing GeneratorExit into a subgenerator that
879
    catches it and yields.
880

881
    >>> _lines(test_throwing_GeneratorExit_into_subgenerator_that_yields())
882
    Enter g
883
    Enter f
884
    """
885
    trace = []
886
    def f():
887
        try:
888
            trace.append("Enter f")
889
            yield
890
            trace.append("Exit f")
891
        except GeneratorExit:
892
            yield
893
    def g():
894
        trace.append("Enter g")
895
        yield from f()
896
        trace.append("Exit g")
897
    try:
898
        gi = g()
899
        next(gi)
900
        gi.throw(GeneratorExit)
901
    except RuntimeError:
902
        pass # "generator ignored GeneratorExit"
903
    else:
904
        trace.append("subgenerator failed to raise GeneratorExit")
905
    return trace
906

907
def test_throwing_GeneratorExit_into_subgen_that_raises():
908
    """
909
    Test throwing GeneratorExit into a subgenerator that
910
    catches it and raises a different exception.
911

912
    >>> _lines(test_throwing_GeneratorExit_into_subgen_that_raises())
913
    Enter g
914
    Enter f
915
    """
916
    trace = []
917
    def f():
918
        try:
919
            trace.append("Enter f")
920
            yield
921
            trace.append("Exit f")
922
        except GeneratorExit:
923
            raise ValueError("Vorpal bunny encountered")
924
    def g():
925
        trace.append("Enter g")
926
        yield from f()
927
        trace.append("Exit g")
928
    try:
929
        gi = g()
930
        next(gi)
931
        gi.throw(GeneratorExit)
932
    except ValueError:
933
        pass # "Vorpal bunny encountered"
934
    else:
935
        trace.append("subgenerator failed to raise ValueError")
936
    return trace
937

938
def test_yield_from_empty():
939
    """
940
    >>> test_yield_from_empty()
941
    """
942
    def g():
943
        yield from ()
944
    try:
945
        next(g())
946
    except StopIteration:
947
        pass
948
    else:
949
        return "FAILED"
950

951
# test re-entry guards
952

953
def _reentering_gen():
954
    def one():
955
        yield 0
956
        yield from two()
957
        yield 3
958
    def two():
959
        yield 1
960
        try:
961
            yield from g1
962
        except ValueError:
963
            pass
964
        yield 2
965
    g1 = one()
966
    return g1
967

968
def test_delegating_generators_claim_to_be_running_next():
969
    """
970
    >>> test_delegating_generators_claim_to_be_running_next()
971
    [0, 1, 2, 3]
972
    """
973
    return list(_reentering_gen())
974

975
def test_delegating_generators_claim_to_be_running_send():
976
    """
977
    >>> test_delegating_generators_claim_to_be_running_send()
978
    [0, 1, 2, 3]
979
    """
980
    g1 = _reentering_gen()
981
    res = [next(g1)]
982
    try:
983
        while True:
984
            res.append(g1.send(42))
985
    except StopIteration:
986
        pass
987
    return res
988

989
def test_delegating_generators_claim_to_be_running_throw():
990
    """
991
    >>> test_delegating_generators_claim_to_be_running_throw()
992
    [0, 1, 2, 3]
993
    """
994
    class MyErr(Exception):
995
        pass
996
    def one():
997
        try:
998
            yield 0
999
        except MyErr:
1000
            pass
1001
        yield from two()
1002
        try:
1003
            yield 3
1004
        except MyErr:
1005
            pass
1006
    def two():
1007
        try:
1008
            yield 1
1009
        except MyErr:
1010
            pass
1011
        try:
1012
            yield from g1
1013
        except ValueError:
1014
            pass
1015
        try:
1016
            yield 2
1017
        except MyErr:
1018
            pass
1019
    g1 = one()
1020
    res = [next(g1)]
1021
    try:
1022
        while True:
1023
            res.append(g1.throw(MyErr))
1024
    except StopIteration:
1025
        pass
1026
    return res
1027

1028
def test_delegating_generators_claim_to_be_running_close():
1029
    """
1030
    >>> test_delegating_generators_claim_to_be_running_close()
1031
    42
1032
    """
1033
    class MyIt(object):
1034
        def __iter__(self):
1035
            return self
1036
        def __next__(self):
1037
            return 42
1038
        next = __next__
1039
        def close(self):
1040
            assert g1.gi_running
1041
            try:
1042
                next(g1)
1043
            except ValueError:
1044
                pass # guard worked
1045
            else:
1046
                assert False, "re-entry guard failed to bark"
1047
    def one():
1048
        yield from MyIt()
1049
    g1 = one()
1050
    ret = next(g1)
1051
    g1.close()
1052
    return ret
1053

1054

1055
def yield_in_return(x):
1056
    """
1057
    >>> x = yield_in_return(range(3))
1058
    >>> for _ in range(10):
1059
    ...     try:
1060
    ...         print(next(x))
1061
    ...     except StopIteration:
1062
    ...         print(sys.exc_info()[1].value is None)
1063
    ...         break
1064
    0
1065
    1
1066
    2
1067
    True
1068
    """
1069
    return (yield from x)
1070

1071

1072
def gi_yieldfrom(it):
1073
    """
1074
    >>> it = iter([1, 2, 3])
1075
    >>> g = gi_yieldfrom(it)
1076
    >>> g.gi_yieldfrom is None or "ERROR: %r" % g.gi_yieldfrom
1077
    True
1078
    >>> next(g)
1079
    1
1080
    >>> g.gi_yieldfrom is it or "ERROR: %r" % g.gi_yieldfrom
1081
    True
1082
    """
1083
    x = yield from it
1084
    return x
1085

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.