1# flake8: noqa
2# test code was mostly copied from stdlib, can't be fixing this mad stuff...
3import copy
4import inspect
5import pickle
6import re
7import sys
8import types
9import warnings
10
11import pytest
12
13from lazy_object_proxy.utils import await_
14
15
16class AsyncYieldFrom:
17    def __init__(self, obj):
18        self.obj = obj
19
20    def __await__(self):
21        yield from self.obj
22
23
24class AsyncYield:
25    def __init__(self, value):
26        self.value = value
27
28    def __await__(self):
29        yield self.value
30
31
32def run_async(coro):
33    assert coro.__class__ in {types.GeneratorType, types.CoroutineType}
34
35    buffer = []
36    result = None
37    while True:
38        try:
39            buffer.append(coro.send(None))
40        except StopIteration as ex:
41            result = ex.args[0] if ex.args else None
42            break
43    return buffer, result
44
45
46def run_async__await__(coro):
47    assert coro.__class__ is types.CoroutineType
48    aw = coro.__await__()
49    buffer = []
50    result = None
51    i = 0
52    while True:
53        try:
54            if i % 2:
55                buffer.append(next(aw))
56            else:
57                buffer.append(aw.send(None))
58            i += 1
59        except StopIteration as ex:
60            result = ex.args[0] if ex.args else None
61            break
62    return buffer, result
63
64
65async def proxy(ob):  # workaround
66    return await ob
67
68
69def test_gen_1(lop):
70    def gen(): yield
71
72    assert not hasattr(gen, '__await__')
73
74
75def test_func_1(lop):
76    async def foo():
77        return 10
78
79    f = lop.Proxy(foo)
80    assert isinstance(f, types.CoroutineType)
81    assert bool(foo.__code__.co_flags & inspect.CO_COROUTINE)
82    assert not bool(foo.__code__.co_flags & inspect.CO_GENERATOR)
83    assert bool(f.cr_code.co_flags & inspect.CO_COROUTINE)
84    assert not bool(f.cr_code.co_flags & inspect.CO_GENERATOR)
85    assert run_async(f) == ([], 10)
86
87    assert run_async__await__(foo()) == ([], 10)
88
89    def bar(): pass
90
91    assert not bool(bar.__code__.co_flags & inspect.CO_COROUTINE)
92
93
94def test_func_2(lop):
95    async def foo():
96        raise StopIteration
97
98    with pytest.raises(RuntimeError, match="coroutine raised StopIteration"):
99        run_async(lop.Proxy(foo))
100
101
102def test_func_3(lop):
103    async def foo():
104        raise StopIteration
105
106    coro = lop.Proxy(foo)
107    assert re.search('^<coroutine object.* at 0x.*>$', str(coro))
108    coro.close()
109
110
111def test_func_4(lop):
112    async def foo():
113        raise StopIteration
114
115    coro = lop.Proxy(foo)
116
117    check = lambda: pytest.raises(TypeError, match="'coroutine' object is not iterable")
118
119    with check():
120        list(coro)
121
122    with check():
123        tuple(coro)
124
125    with check():
126        sum(coro)
127
128    with check():
129        iter(coro)
130
131    with check():
132        for i in coro:
133            pass
134
135    with check():
136        [i for i in coro]
137
138    coro.close()
139
140
141def test_func_5(lop):
142    @types.coroutine
143    def bar():
144        yield 1
145
146    async def foo():
147        await lop.Proxy(bar)
148
149    check = lambda: pytest.raises(TypeError, match="'coroutine' object is not iterable")
150
151    coro = lop.Proxy(foo)
152    with check():
153        for el in coro:
154            pass
155    coro.close()
156
157    # the following should pass without an error
158    for el in lop.Proxy(bar):
159        assert el == 1
160    assert [el for el in lop.Proxy(bar)] == [1]
161    assert tuple(lop.Proxy(bar)) == (1,)
162    assert next(iter(lop.Proxy(bar))) == 1
163
164
165def test_func_6(lop):
166    @types.coroutine
167    def bar():
168        yield 1
169        yield 2
170
171    async def foo():
172        await lop.Proxy(bar)
173
174    f = lop.Proxy(foo)
175    assert f.send(None) == 1
176    assert f.send(None) == 2
177    with pytest.raises(StopIteration):
178        f.send(None)
179
180
181def test_func_7(lop):
182    async def bar():
183        return 10
184
185    coro = lop.Proxy(bar)
186
187    def foo():
188        yield from coro
189
190    with pytest.raises(
191        TypeError,
192        match="'coroutine' object is not iterable",
193        # looks like python has some special error rewrapping?!
194        # match="cannot 'yield from' a coroutine object in "
195        #       "a non-coroutine generator"
196    ):
197        list(lop.Proxy(foo))
198
199    coro.close()
200
201
202def test_func_8(lop):
203    @types.coroutine
204    def bar():
205        return (yield from coro)
206
207    async def foo():
208        return 'spam'
209
210    coro = await_(lop.Proxy(foo))
211    # coro = lop.Proxy(foo)
212    assert run_async(lop.Proxy(bar)) == ([], 'spam')
213    coro.close()
214
215
216def test_func_10(lop):
217    N = 0
218
219    @types.coroutine
220    def gen():
221        nonlocal N
222        try:
223            a = yield
224            yield (a ** 2)
225        except ZeroDivisionError:
226            N += 100
227            raise
228        finally:
229            N += 1
230
231    async def foo():
232        await lop.Proxy(gen)
233
234    coro = lop.Proxy(foo)
235    aw = coro.__await__()
236    assert aw is iter(aw)
237    next(aw)
238    assert aw.send(10) == 100
239
240    assert N == 0
241    aw.close()
242    assert N == 1
243
244    coro = foo()
245    aw = coro.__await__()
246    next(aw)
247    with pytest.raises(ZeroDivisionError):
248        aw.throw(ZeroDivisionError, None, None)
249    assert N == 102
250
251
252def test_func_11(lop):
253    async def func(): pass
254
255    coro = lop.Proxy(func)
256    # Test that PyCoro_Type and _PyCoroWrapper_Type types were properly
257    # initialized
258    assert '__await__' in dir(coro)
259    assert '__iter__' in dir(coro.__await__())
260    assert 'coroutine_wrapper' in str(coro.__await__())
261    coro.close()  # avoid RuntimeWarning
262
263
264def test_func_12(lop):
265    async def g():
266        i = me.send(None)
267        await foo
268
269    me = lop.Proxy(g)
270    with pytest.raises(ValueError, match="coroutine already executing"):
271        me.send(None)
272
273
274def test_func_13(lop):
275    async def g():
276        pass
277
278    coro = lop.Proxy(g)
279    with pytest.raises(TypeError, match="can't send non-None value to a just-started coroutine"):
280        coro.send('spam')
281
282    coro.close()
283
284
285def test_func_14(lop):
286    @types.coroutine
287    def gen():
288        yield
289
290    async def coro():
291        try:
292            await lop.Proxy(gen)
293        except GeneratorExit:
294            await lop.Proxy(gen)
295
296    c = lop.Proxy(coro)
297    c.send(None)
298    with pytest.raises(RuntimeError, match="coroutine ignored GeneratorExit"):
299        c.close()
300
301
302def test_func_15(lop):
303    # See http://bugs.python.org/issue25887 for details
304
305    async def spammer():
306        return 'spam'
307
308    async def reader(coro):
309        return await coro
310
311    spammer_coro = lop.Proxy(spammer)
312
313    with pytest.raises(StopIteration, match='spam'):
314        reader(spammer_coro).send(None)
315
316    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
317        reader(spammer_coro).send(None)
318
319
320def test_func_16(lop):
321    # See http://bugs.python.org/issue25887 for details
322
323    @types.coroutine
324    def nop():
325        yield
326
327    async def send():
328        await nop()
329        return 'spam'
330
331    async def read(coro):
332        await nop()
333        return await coro
334
335    spammer = lop.Proxy(send)
336
337    reader = lop.Proxy(lambda: read(spammer))
338    reader.send(None)
339    reader.send(None)
340    with pytest.raises(Exception, match='ham'):
341        reader.throw(Exception('ham'))
342
343    reader = read(spammer)
344    reader.send(None)
345    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
346        reader.send(None)
347
348    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
349        reader.throw(Exception('wat'))
350
351
352def test_func_17(lop):
353    # See http://bugs.python.org/issue25887 for details
354
355    async def coroutine():
356        return 'spam'
357
358    coro = lop.Proxy(coroutine)
359    with pytest.raises(StopIteration, match='spam'):
360        coro.send(None)
361
362    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
363        coro.send(None)
364
365    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
366        coro.throw(Exception('wat'))
367
368    # Closing a coroutine shouldn't raise any exception even if it's
369    # already closed/exhausted (similar to generators)
370    coro.close()
371    coro.close()
372
373
374def test_func_18(lop):
375    # See http://bugs.python.org/issue25887 for details
376
377    async def coroutine():
378        return 'spam'
379
380    coro = lop.Proxy(coroutine)
381    await_iter = coro.__await__()
382    it = iter(await_iter)
383
384    with pytest.raises(StopIteration, match='spam'):
385        it.send(None)
386
387    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
388        it.send(None)
389
390    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
391        # Although the iterator protocol requires iterators to
392        # raise another StopIteration here, we don't want to do
393        # that.  In this particular case, the iterator will raise
394        # a RuntimeError, so that 'yield from' and 'await'
395        # expressions will trigger the error, instead of silently
396        # ignoring the call.
397        next(it)
398
399    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
400        it.throw(Exception('wat'))
401
402    with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'):
403        it.throw(Exception('wat'))
404
405    # Closing a coroutine shouldn't raise any exception even if it's
406    # already closed/exhausted (similar to generators)
407    it.close()
408    it.close()
409
410
411def test_func_19(lop):
412    CHK = 0
413
414    @types.coroutine
415    def foo():
416        nonlocal CHK
417        yield
418        try:
419            yield
420        except GeneratorExit:
421            CHK += 1
422
423    async def coroutine():
424        await foo()
425
426    coro = lop.Proxy(coroutine)
427
428    coro.send(None)
429    coro.send(None)
430
431    assert CHK == 0
432    coro.close()
433    assert CHK == 1
434
435    for _ in range(3):
436        # Closing a coroutine shouldn't raise any exception even if it's
437        # already closed/exhausted (similar to generators)
438        coro.close()
439        assert CHK == 1
440
441
442def test_coro_wrapper_send_tuple(lop):
443    async def foo():
444        return (10,)
445
446    result = run_async__await__(lop.Proxy(foo))
447    assert result == ([], (10,))
448
449
450def test_coro_wrapper_send_stop_iterator(lop):
451    async def foo():
452        return StopIteration(10)
453
454    result = run_async__await__(lop.Proxy(foo))
455    assert isinstance(result[1], StopIteration)
456    assert result[1].value == 10
457
458
459def test_cr_await(lop):
460    @types.coroutine
461    def a():
462        assert inspect.getcoroutinestate(coro_b) == inspect.CORO_RUNNING
463        assert coro_b.cr_await is None
464        yield
465        assert inspect.getcoroutinestate(coro_b) == inspect.CORO_RUNNING
466        assert coro_b.cr_await is None
467
468    async def c():
469        await lop.Proxy(a)
470
471    async def b():
472        assert coro_b.cr_await is None
473        await lop.Proxy(c)
474        assert coro_b.cr_await is None
475
476    coro_b = lop.Proxy(b)
477    assert inspect.getcoroutinestate(coro_b) == inspect.CORO_CREATED
478    assert coro_b.cr_await is None
479
480    coro_b.send(None)
481    assert inspect.getcoroutinestate(coro_b) == inspect.CORO_SUSPENDED
482
483    with pytest.raises(StopIteration):
484        coro_b.send(None)  # complete coroutine
485    assert inspect.getcoroutinestate(coro_b) == inspect.CORO_CLOSED
486    assert coro_b.cr_await is None
487
488
489def test_await_1(lop):
490    async def foo():
491        await 1
492
493    with pytest.raises(TypeError, match="object int can.t.*await"):
494        run_async(lop.Proxy(foo))
495
496
497def test_await_2(lop):
498    async def foo():
499        await []
500
501    with pytest.raises(TypeError, match="object list can.t.*await"):
502        run_async(lop.Proxy(foo))
503
504
505def test_await_3(lop):
506    async def foo():
507        await AsyncYieldFrom([1, 2, 3])
508
509    assert run_async(lop.Proxy(foo)) == ([1, 2, 3], None)
510    assert run_async__await__(lop.Proxy(foo)) == ([1, 2, 3], None)
511
512
513def test_await_4(lop):
514    async def bar():
515        return 42
516
517    async def foo():
518        return await lop.Proxy(bar)
519
520    assert run_async(lop.Proxy(foo)) == ([], 42)
521
522
523def test_await_5(lop):
524    class Awaitable:
525        def __await__(self):
526            return
527
528    async def foo():
529        return (await lop.Proxy(Awaitable))
530
531    with pytest.raises(TypeError, match="__await__.*returned non-iterator of type"):
532        run_async(lop.Proxy(foo))
533
534
535def test_await_6(lop):
536    class Awaitable:
537        def __await__(self):
538            return iter([52])
539
540    async def foo():
541        return (await lop.Proxy(Awaitable))
542
543    assert run_async(lop.Proxy(foo)) == ([52], None)
544
545
546def test_await_7(lop):
547    class Awaitable:
548        def __await__(self):
549            yield 42
550            return 100
551
552    async def foo():
553        return (await lop.Proxy(Awaitable))
554
555    assert run_async(lop.Proxy(foo)) == ([42], 100)
556
557
558def test_await_8(lop):
559    class Awaitable:
560        pass
561
562    async def foo():
563        return await lop.Proxy(Awaitable)
564
565    with pytest.raises(TypeError):
566        run_async(lop.Proxy(foo))
567
568
569def test_await_9(lop):
570    def wrap():
571        return bar
572
573    async def bar():
574        return 42
575
576    async def foo():
577        db = {'b': lambda: wrap}
578
579        class DB:
580            b = wrap
581
582        return (await lop.Proxy(bar) + await lop.Proxy(wrap)() + await lop.Proxy(lambda: db['b']()()()) +
583                await lop.Proxy(bar) * 1000 + await DB.b()())
584
585    async def foo2():
586        return -await lop.Proxy(bar)
587
588    assert run_async(lop.Proxy(foo)) == ([], 42168)
589    assert run_async(lop.Proxy(foo2)) == ([], -42)
590
591
592def test_await_10(lop):
593    async def baz():
594        return 42
595
596    async def bar():
597        return lop.Proxy(baz)
598
599    async def foo():
600        return await (await lop.Proxy(bar))
601
602    assert run_async(lop.Proxy(foo)) == ([], 42)
603
604
605def test_await_11(lop):
606    def ident(val):
607        return val
608
609    async def bar():
610        return 'spam'
611
612    async def foo():
613        return ident(val=await lop.Proxy(bar))
614
615    async def foo2():
616        return await lop.Proxy(bar), 'ham'
617
618    assert run_async(lop.Proxy(foo2)) == ([], ('spam', 'ham'))
619
620
621def test_await_12(lop):
622    async def coro():
623        return 'spam'
624
625    c = coro()
626
627    class Awaitable:
628        def __await__(self):
629            return c
630
631    async def foo():
632        return await lop.Proxy(Awaitable)
633
634    with pytest.raises(TypeError, match=r"__await__\(\) returned a coroutine"):
635        run_async(lop.Proxy(foo))
636
637    c.close()
638
639
640def test_await_13(lop):
641    class Awaitable:
642        def __await__(self):
643            return self
644
645    async def foo():
646        return await lop.Proxy(Awaitable)
647
648    with pytest.raises(TypeError, match="__await__.*returned non-iterator of type"):
649        run_async(lop.Proxy(foo))
650
651
652def test_await_14(lop):
653    class Wrapper:
654        # Forces the interpreter to use CoroutineType.__await__
655        def __init__(self, coro):
656            assert coro.__class__ is types.CoroutineType
657            self.coro = coro
658
659        def __await__(self):
660            return self.coro.__await__()
661
662    class FutureLike:
663        def __await__(self):
664            return (yield)
665
666    class Marker(Exception):
667        pass
668
669    async def coro1():
670        try:
671            return await lop.Proxy(FutureLike)
672        except ZeroDivisionError:
673            raise Marker
674
675    async def coro2():
676        return await lop.Proxy(lambda: Wrapper(lop.Proxy(coro1)))
677
678    c = lop.Proxy(coro2)
679    c.send(None)
680    with pytest.raises(StopIteration, match='spam'):
681        c.send('spam')
682
683    c = lop.Proxy(coro2)
684    c.send(None)
685    with pytest.raises(Marker):
686        c.throw(ZeroDivisionError)
687
688
689def test_await_15(lop):
690    @types.coroutine
691    def nop():
692        yield
693
694    async def coroutine():
695        await nop()
696
697    async def waiter(coro):
698        await coro
699
700    coro = lop.Proxy(coroutine)
701    coro.send(None)
702
703    with pytest.raises(RuntimeError, match="coroutine is being awaited already"):
704        waiter(coro).send(None)
705
706
707def test_await_16(lop):
708    # See https://bugs.python.org/issue29600 for details.
709
710    async def f():
711        return ValueError()
712
713    async def g():
714        try:
715            raise KeyError
716        except:
717            return await lop.Proxy(f)
718
719    _, result = run_async(lop.Proxy(g))
720    assert result.__context__ is None
721
722
723def test_with_1(lop):
724    class Manager:
725        def __init__(self, name):
726            self.name = name
727
728        async def __aenter__(self):
729            await AsyncYieldFrom(['enter-1-' + self.name,
730                                  'enter-2-' + self.name])
731            return self
732
733        async def __aexit__(self, *args):
734            await AsyncYieldFrom(['exit-1-' + self.name,
735                                  'exit-2-' + self.name])
736
737            if self.name == 'B':
738                return True
739
740    async def foo():
741        async with lop.Proxy(lambda: Manager("A")) as a, lop.Proxy(lambda: Manager("B")) as b:
742            await lop.Proxy(lambda: AsyncYieldFrom([('managers', a.name, b.name)]))
743            1 / 0
744
745    f = lop.Proxy(foo)
746    result, _ = run_async(f)
747
748    assert result == ['enter-1-A', 'enter-2-A', 'enter-1-B', 'enter-2-B',
749                      ('managers', 'A', 'B'),
750                      'exit-1-B', 'exit-2-B', 'exit-1-A', 'exit-2-A']
751
752    async def foo():
753        async with lop.Proxy(lambda: Manager("A")) as a, lop.Proxy(lambda: Manager("C")) as c:
754            await lop.Proxy(lambda: AsyncYieldFrom([('managers', a.name, c.name)]))
755            1 / 0
756
757    with pytest.raises(ZeroDivisionError):
758        run_async(lop.Proxy(foo))
759
760
761def test_with_2(lop):
762    class CM:
763        def __aenter__(self):
764            pass
765
766    body_executed = False
767
768    async def foo():
769        async with lop.Proxy(CM):
770            body_executed = True
771
772    with pytest.raises(TypeError):
773        run_async(lop.Proxy(foo))
774    assert not body_executed
775
776
777def test_with_3(lop):
778    class CM:
779        def __aexit__(self):
780            pass
781
782    body_executed = False
783
784    async def foo():
785        async with lop.Proxy(CM):
786            body_executed = True
787
788    with pytest.raises(AttributeError, match='__aenter__'):
789        run_async(lop.Proxy(foo))
790    assert not body_executed
791
792
793def test_with_4(lop):
794    class CM:
795        pass
796
797    body_executed = False
798
799    async def foo():
800        async with lop.Proxy(CM):
801            body_executed = True
802
803    with pytest.raises(AttributeError, match='__aenter__'):
804        run_async(lop.Proxy(foo))
805    assert not body_executed
806
807
808def test_with_5(lop):
809    # While this test doesn't make a lot of sense,
810    # it's a regression test for an early bug with opcodes
811    # generation
812
813    class CM:
814        async def __aenter__(self):
815            return self
816
817        async def __aexit__(self, *exc):
818            pass
819
820    async def func():
821        async with lop.Proxy(CM):
822            assert (1,) == 1
823
824    with pytest.raises(AssertionError):
825        run_async(lop.Proxy(func))
826
827
828def test_with_6(lop):
829    class CM:
830        def __aenter__(self):
831            return 123
832
833        def __aexit__(self, *e):
834            return 456
835
836    async def foo():
837        async with lop.Proxy(CM):
838            pass
839
840    with pytest.raises(TypeError, match="'async with' received an object from __aenter__ "
841                                        "that does not implement __await__: int"):
842        # it's important that __aexit__ wasn't called
843        run_async(lop.Proxy(foo))
844
845
846def test_with_7(lop):
847    class CM:
848        async def __aenter__(self):
849            return self
850
851        def __aexit__(self, *e):
852            return 444
853
854    # Exit with exception
855    async def foo():
856        async with lop.Proxy(CM):
857            1 / 0
858
859    try:
860        run_async(lop.Proxy(foo))
861    except TypeError as exc:
862        assert re.search("'async with' received an object from __aexit__ " \
863                         "that does not implement __await__: int", exc.args[0])
864        assert exc.__context__ is not None
865        assert isinstance(exc.__context__, ZeroDivisionError)
866    else:
867        pytest.fail('invalid asynchronous context manager did not fail')
868
869
870def test_with_8(lop):
871    CNT = 0
872
873    class CM:
874        async def __aenter__(self):
875            return self
876
877        def __aexit__(self, *e):
878            return 456
879
880    # Normal exit
881    async def foo():
882        nonlocal CNT
883        async with lop.Proxy(CM):
884            CNT += 1
885
886    with pytest.raises(TypeError, match="'async with' received an object from __aexit__ "
887                                        "that does not implement __await__: int"):
888        run_async(lop.Proxy(foo))
889    assert CNT == 1
890
891    # Exit with 'break'
892    async def foo():
893        nonlocal CNT
894        for i in range(2):
895            async with lop.Proxy(CM):
896                CNT += 1
897                break
898
899    with pytest.raises(TypeError, match="'async with' received an object from __aexit__ "
900                                        "that does not implement __await__: int"):
901        run_async(lop.Proxy(foo))
902    assert CNT == 2
903
904    # Exit with 'continue'
905    async def foo():
906        nonlocal CNT
907        for i in range(2):
908            async with lop.Proxy(CM):
909                CNT += 1
910                continue
911
912    with pytest.raises(TypeError, match="'async with' received an object from __aexit__ "
913                                        "that does not implement __await__: int"):
914        run_async(lop.Proxy(foo))
915    assert CNT == 3
916
917    # Exit with 'return'
918    async def foo():
919        nonlocal CNT
920        async with lop.Proxy(CM):
921            CNT += 1
922            return
923
924    with pytest.raises(TypeError, match="'async with' received an object from __aexit__ "
925                                        "that does not implement __await__: int"):
926        run_async(lop.Proxy(foo))
927    assert CNT == 4
928
929
930def test_with_9(lop):
931    CNT = 0
932
933    class CM:
934        async def __aenter__(self):
935            return self
936
937        async def __aexit__(self, *e):
938            1 / 0
939
940    async def foo():
941        nonlocal CNT
942        async with lop.Proxy(CM):
943            CNT += 1
944
945    with pytest.raises(ZeroDivisionError):
946        run_async(lop.Proxy(foo))
947
948    assert CNT == 1
949
950
951def test_with_10(lop):
952    CNT = 0
953
954    class CM:
955        async def __aenter__(self):
956            return self
957
958        async def __aexit__(self, *e):
959            1 / 0
960
961    async def foo():
962        nonlocal CNT
963        async with lop.Proxy(CM):
964            async with lop.Proxy(CM):
965                raise RuntimeError
966
967    try:
968        run_async(lop.Proxy(foo))
969    except ZeroDivisionError as exc:
970        assert exc.__context__ is not None
971        assert isinstance(exc.__context__, ZeroDivisionError)
972        assert isinstance(exc.__context__.__context__,
973                          RuntimeError)
974    else:
975        pytest.fail('exception from __aexit__ did not propagate')
976
977
978def test_with_11(lop):
979    CNT = 0
980
981    class CM:
982        async def __aenter__(self):
983            raise NotImplementedError
984
985        async def __aexit__(self, *e):
986            1 / 0
987
988    async def foo():
989        nonlocal CNT
990        async with lop.Proxy(CM):
991            raise RuntimeError
992
993    try:
994        run_async(lop.Proxy(foo))
995    except NotImplementedError as exc:
996        assert exc.__context__ is None
997    else:
998        pytest.fail('exception from __aenter__ did not propagate')
999
1000
1001def test_with_12(lop):
1002    CNT = 0
1003
1004    class CM:
1005        async def __aenter__(self):
1006            return self
1007
1008        async def __aexit__(self, *e):
1009            return True
1010
1011    async def foo():
1012        nonlocal CNT
1013        async with lop.Proxy(CM) as cm:
1014            assert cm.__class__ is CM
1015            raise RuntimeError
1016
1017    run_async(lop.Proxy(foo))
1018
1019
1020def test_with_13(lop):
1021    CNT = 0
1022
1023    class CM:
1024        async def __aenter__(self):
1025            1 / 0
1026
1027        async def __aexit__(self, *e):
1028            return True
1029
1030    async def foo():
1031        nonlocal CNT
1032        CNT += 1
1033        async with lop.Proxy(CM):
1034            CNT += 1000
1035        CNT += 10000
1036
1037    with pytest.raises(ZeroDivisionError):
1038        run_async(lop.Proxy(foo))
1039    assert CNT == 1
1040
1041
1042def test_for_1(lop):
1043    aiter_calls = 0
1044
1045    class AsyncIter:
1046        def __init__(self):
1047            self.i = 0
1048
1049        def __aiter__(self):
1050            nonlocal aiter_calls
1051            aiter_calls += 1
1052            return self
1053
1054        async def __anext__(self):
1055            self.i += 1
1056
1057            if not (self.i % 10):
1058                await lop.Proxy(lambda: AsyncYield(self.i * 10))
1059
1060            if self.i > 100:
1061                raise StopAsyncIteration
1062
1063            return self.i, self.i
1064
1065    buffer = []
1066
1067    async def test1():
1068        async for i1, i2 in lop.Proxy(AsyncIter):
1069            buffer.append(i1 + i2)
1070
1071    yielded, _ = run_async(lop.Proxy(test1))
1072    # Make sure that __aiter__ was called only once
1073    assert aiter_calls == 1
1074    assert yielded == [i * 100 for i in range(1, 11)]
1075    assert buffer == [i * 2 for i in range(1, 101)]
1076
1077    buffer = []
1078
1079    async def test2():
1080        nonlocal buffer
1081        async for i in lop.Proxy(AsyncIter):
1082            buffer.append(i[0])
1083            if i[0] == 20:
1084                break
1085        else:
1086            buffer.append('what?')
1087        buffer.append('end')
1088
1089    yielded, _ = run_async(lop.Proxy(test2))
1090    # Make sure that __aiter__ was called only once
1091    assert aiter_calls == 2
1092    assert yielded == [100, 200]
1093    assert buffer == [i for i in range(1, 21)] + ['end']
1094
1095    buffer = []
1096
1097    async def test3():
1098        nonlocal buffer
1099        async for i in lop.Proxy(AsyncIter):
1100            if i[0] > 20:
1101                continue
1102            buffer.append(i[0])
1103        else:
1104            buffer.append('what?')
1105        buffer.append('end')
1106
1107    yielded, _ = run_async(lop.Proxy(test3))
1108    # Make sure that __aiter__ was called only once
1109    assert aiter_calls == 3
1110    assert yielded == [i * 100 for i in range(1, 11)]
1111    assert buffer == [i for i in range(1, 21)] + \
1112           ['what?', 'end']
1113
1114
1115def test_for_2(lop):
1116    tup = (1, 2, 3)
1117    refs_before = sys.getrefcount(tup)
1118
1119    async def foo():
1120        async for i in lop.Proxy(lambda: tup):
1121            print('never going to happen')
1122
1123    with pytest.raises(AttributeError, match="'tuple' object has no attribute '__aiter__'"):
1124        run_async(lop.Proxy(foo))
1125
1126    assert sys.getrefcount(tup) == refs_before
1127
1128
1129def test_for_3(lop):
1130    class I:
1131        def __aiter__(self):
1132            return self
1133
1134    aiter = lop.Proxy(I)
1135    refs_before = sys.getrefcount(aiter)
1136
1137    async def foo():
1138        async for i in aiter:
1139            print('never going to happen')
1140
1141    with pytest.raises(TypeError):
1142        run_async(lop.Proxy(foo))
1143
1144    assert sys.getrefcount(aiter) == refs_before
1145
1146
1147def test_for_4(lop):
1148    class I:
1149        def __aiter__(self):
1150            return self
1151
1152        def __anext__(self):
1153            return ()
1154
1155    aiter = lop.Proxy(I)
1156    refs_before = sys.getrefcount(aiter)
1157
1158    async def foo():
1159        async for i in aiter:
1160            print('never going to happen')
1161
1162    with pytest.raises(TypeError, match="async for' received an invalid object.*__anext__.*tuple"):
1163        run_async(lop.Proxy(foo))
1164
1165    assert sys.getrefcount(aiter) == refs_before
1166
1167
1168def test_for_6(lop):
1169    I = 0
1170
1171    class Manager:
1172        async def __aenter__(self):
1173            nonlocal I
1174            I += 10000
1175
1176        async def __aexit__(self, *args):
1177            nonlocal I
1178            I += 100000
1179
1180    class Iterable:
1181        def __init__(self):
1182            self.i = 0
1183
1184        def __aiter__(self):
1185            return self
1186
1187        async def __anext__(self):
1188            if self.i > 10:
1189                raise StopAsyncIteration
1190            self.i += 1
1191            return self.i
1192
1193    ##############
1194
1195    manager = lop.Proxy(Manager)
1196    iterable = lop.Proxy(Iterable)
1197    mrefs_before = sys.getrefcount(manager)
1198    irefs_before = sys.getrefcount(iterable)
1199
1200    async def main():
1201        nonlocal I
1202
1203        async with manager:
1204            async for i in iterable:
1205                I += 1
1206        I += 1000
1207
1208    with warnings.catch_warnings():
1209        warnings.simplefilter("error")
1210        # Test that __aiter__ that returns an asynchronous iterator
1211        # directly does not throw any warnings.
1212        run_async(main())
1213    assert I == 111011
1214
1215    assert sys.getrefcount(manager) == mrefs_before
1216    assert sys.getrefcount(iterable) == irefs_before
1217
1218    ##############
1219
1220    async def main():
1221        nonlocal I
1222
1223        async with lop.Proxy(Manager):
1224            async for i in lop.Proxy(Iterable):
1225                I += 1
1226        I += 1000
1227
1228        async with lop.Proxy(Manager):
1229            async for i in lop.Proxy(Iterable):
1230                I += 1
1231        I += 1000
1232
1233    run_async(main())
1234    assert I == 333033
1235
1236    ##############
1237
1238    async def main():
1239        nonlocal I
1240
1241        async with lop.Proxy(Manager):
1242            I += 100
1243            async for i in lop.Proxy(Iterable):
1244                I += 1
1245            else:
1246                I += 10000000
1247        I += 1000
1248
1249        async with lop.Proxy(Manager):
1250            I += 100
1251            async for i in lop.Proxy(Iterable):
1252                I += 1
1253            else:
1254                I += 10000000
1255        I += 1000
1256
1257    run_async(lop.Proxy(main))
1258    assert I == 20555255
1259
1260
1261def test_for_7(lop):
1262    CNT = 0
1263
1264    class AI:
1265        def __aiter__(self):
1266            1 / 0
1267
1268    async def foo():
1269        nonlocal CNT
1270        async for i in lop.Proxy(AI):
1271            CNT += 1
1272        CNT += 10
1273
1274    with pytest.raises(ZeroDivisionError):
1275        run_async(lop.Proxy(foo))
1276    assert CNT == 0
1277
1278
1279def test_for_8(lop):
1280    CNT = 0
1281
1282    class AI:
1283        def __aiter__(self):
1284            1 / 0
1285
1286    async def foo():
1287        nonlocal CNT
1288        async for i in lop.Proxy(AI):
1289            CNT += 1
1290        CNT += 10
1291
1292    with pytest.raises(ZeroDivisionError):
1293        with warnings.catch_warnings():
1294            warnings.simplefilter("error")
1295            # Test that if __aiter__ raises an exception it propagates
1296            # without any kind of warning.
1297            run_async(lop.Proxy(foo))
1298    assert CNT == 0
1299
1300
1301def test_for_11(lop):
1302    class F:
1303        def __aiter__(self):
1304            return self
1305
1306        def __anext__(self):
1307            return self
1308
1309        def __await__(self):
1310            1 / 0
1311
1312    async def main():
1313        async for _ in lop.Proxy(F):
1314            pass
1315
1316    with pytest.raises(TypeError, match='an invalid object from __anext__') as c:
1317        lop.Proxy(main).send(None)
1318
1319    err = c.value
1320    assert isinstance(err.__cause__, ZeroDivisionError)
1321
1322
1323def test_for_tuple(lop):
1324    class Done(Exception):
1325        pass
1326
1327    class AIter(tuple):
1328        i = 0
1329
1330        def __aiter__(self):
1331            return self
1332
1333        async def __anext__(self):
1334            if self.i >= len(self):
1335                raise StopAsyncIteration
1336            self.i += 1
1337            return self[self.i - 1]
1338
1339    result = []
1340
1341    async def foo():
1342        async for i in lop.Proxy(lambda: AIter([42])):
1343            result.append(i)
1344        raise Done
1345
1346    with pytest.raises(Done):
1347        lop.Proxy(foo).send(None)
1348    assert result == [42]
1349
1350
1351def test_for_stop_iteration(lop):
1352    class Done(Exception):
1353        pass
1354
1355    class AIter(StopIteration):
1356        i = 0
1357
1358        def __aiter__(self):
1359            return self
1360
1361        async def __anext__(self):
1362            if self.i:
1363                raise StopAsyncIteration
1364            self.i += 1
1365            return self.value
1366
1367    result = []
1368
1369    async def foo():
1370        async for i in lop.Proxy(lambda: AIter(42)):
1371            result.append(i)
1372        raise Done
1373
1374    with pytest.raises(Done):
1375        lop.Proxy(foo).send(None)
1376    assert result == [42]
1377
1378
1379def test_comp_1(lop):
1380    async def f(i):
1381        return i
1382
1383    async def run_list():
1384        return [await c for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]]
1385
1386    async def run_set():
1387        return {await c for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]}
1388
1389    async def run_dict1():
1390        return {await c: 'a' for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]}
1391
1392    async def run_dict2():
1393        return {i: await c for i, c in enumerate([lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))])}
1394
1395    assert run_async(run_list()) == ([], [1, 41])
1396    assert run_async(run_set()) == ([], {1, 41})
1397    assert run_async(run_dict1()) == ([], {1: 'a', 41: 'a'})
1398    assert run_async(run_dict2()) == ([], {0: 1, 1: 41})
1399
1400
1401def test_comp_2(lop):
1402    async def f(i):
1403        return i
1404
1405    async def run_list():
1406        return [s for c in [lop.Proxy(lambda: f('')), lop.Proxy(lambda: f('abc')), lop.Proxy(lambda: f('')),
1407                            lop.Proxy(lambda: f(['de', 'fg']))]
1408                for s in await c]
1409
1410    assert run_async(lop.Proxy(run_list)) == \
1411           ([], ['a', 'b', 'c', 'de', 'fg'])
1412
1413    async def run_set():
1414        return {
1415            d for c in [
1416                lop.Proxy(lambda: f([
1417                    lop.Proxy(lambda: f([10, 30])),
1418                    lop.Proxy(lambda: f([20]))]))
1419            ]
1420            for s in await c
1421            for d in await s}
1422
1423    assert run_async(lop.Proxy(run_set)) == \
1424           ([], {10, 20, 30})
1425
1426    async def run_set2():
1427        return {
1428            await s
1429            for c in [lop.Proxy(lambda: f([
1430                lop.Proxy(lambda: f(10)),
1431                lop.Proxy(lambda: f(20))
1432            ]))]
1433            for s in await c}
1434
1435    assert run_async(lop.Proxy(run_set2)) == \
1436           ([], {10, 20})
1437
1438
1439def test_comp_3(lop):
1440    async def f(it):
1441        for i in it:
1442            yield i
1443
1444    async def run_list():
1445        return [i + 1 async for i in f([10, 20])]
1446
1447    assert run_async(run_list()) == \
1448           ([], [11, 21])
1449
1450    async def run_set():
1451        return {i + 1 async for i in f([10, 20])}
1452
1453    assert run_async(run_set()) == \
1454           ([], {11, 21})
1455
1456    async def run_dict():
1457        return {i + 1: i + 2 async for i in f([10, 20])}
1458
1459    assert run_async(run_dict()) == \
1460           ([], {11: 12, 21: 22})
1461
1462    async def run_gen():
1463        gen = (i + 1 async for i in f([10, 20]))
1464        return [g + 100 async for g in gen]
1465
1466    assert run_async(run_gen()) == \
1467           ([], [111, 121])
1468
1469
1470def test_comp_4(lop):
1471    async def f(it):
1472        for i in it:
1473            yield i
1474
1475    async def run_list():
1476        return [i + 1 async for i in f([10, 20]) if i > 10]
1477
1478    assert run_async(run_list()) == \
1479           ([], [21])
1480
1481    async def run_set():
1482        return {i + 1 async for i in f([10, 20]) if i > 10}
1483
1484    assert run_async(run_set()) == \
1485           ([], {21})
1486
1487    async def run_dict():
1488        return {i + 1: i + 2 async for i in f([10, 20]) if i > 10}
1489
1490    assert run_async(run_dict()) == \
1491           ([], {21: 22})
1492
1493    async def run_gen():
1494        gen = (i + 1 async for i in f([10, 20]) if i > 10)
1495        return [g + 100 async for g in gen]
1496
1497    assert run_async(run_gen()) == \
1498           ([], [121])
1499
1500
1501def test_comp_4_2(lop):
1502    async def f(it):
1503        for i in it:
1504            yield i
1505
1506    async def run_list():
1507        return [i + 10 async for i in f(range(5)) if 0 < i < 4]
1508
1509    assert run_async(run_list()) == \
1510           ([], [11, 12, 13])
1511
1512    async def run_set():
1513        return {i + 10 async for i in f(range(5)) if 0 < i < 4}
1514
1515    assert run_async(run_set()) == \
1516           ([], {11, 12, 13})
1517
1518    async def run_dict():
1519        return {i + 10: i + 100 async for i in f(range(5)) if 0 < i < 4}
1520
1521    assert run_async(run_dict()) == \
1522           ([], {11: 101, 12: 102, 13: 103})
1523
1524    async def run_gen():
1525        gen = (i + 10 async for i in f(range(5)) if 0 < i < 4)
1526        return [g + 100 async for g in gen]
1527
1528    assert run_async(run_gen()) == \
1529           ([], [111, 112, 113])
1530
1531
1532def test_comp_5(lop):
1533    async def f(it):
1534        for i in it:
1535            yield i
1536
1537    async def run_list():
1538        return [i + 1 for pair in ([10, 20], [30, 40]) if pair[0] > 10
1539                async for i in f(pair) if i > 30]
1540
1541    assert run_async(run_list()) == \
1542           ([], [41])
1543
1544
1545def test_comp_6(lop):
1546    async def f(it):
1547        for i in it:
1548            yield i
1549
1550    async def run_list():
1551        return [i + 1 async for seq in f([(10, 20), (30,)])
1552                for i in seq]
1553
1554    assert run_async(run_list()) == \
1555           ([], [11, 21, 31])
1556
1557
1558def test_comp_7(lop):
1559    async def f():
1560        yield 1
1561        yield 2
1562        raise Exception('aaa')
1563
1564    async def run_list():
1565        return [i async for i in f()]
1566
1567    with pytest.raises(Exception, match='aaa'):
1568        run_async(run_list())
1569
1570
1571def test_comp_8(lop):
1572    async def f():
1573        return [i for i in [1, 2, 3]]
1574
1575    assert run_async(f()) == \
1576           ([], [1, 2, 3])
1577
1578
1579def test_comp_9(lop):
1580    async def gen():
1581        yield 1
1582        yield 2
1583
1584    async def f():
1585        l = [i async for i in gen()]
1586        return [i for i in l]
1587
1588    assert run_async(f()) == \
1589           ([], [1, 2])
1590
1591
1592def test_comp_10(lop):
1593    async def f():
1594        xx = {i for i in [1, 2, 3]}
1595        return {x: x for x in xx}
1596
1597    assert run_async(f()) == \
1598           ([], {1: 1, 2: 2, 3: 3})
1599
1600
1601def test_copy(lop):
1602    async def func():
1603        pass
1604
1605    coro = func()
1606    with pytest.raises(TypeError):
1607        copy.copy(coro)
1608
1609    aw = coro.__await__()
1610    try:
1611        with pytest.raises(TypeError):
1612            copy.copy(aw)
1613    finally:
1614        aw.close()
1615
1616
1617def test_pickle(lop):
1618    async def func():
1619        pass
1620
1621    coro = func()
1622    for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1623        with pytest.raises((TypeError, pickle.PicklingError)):
1624            pickle.dumps(coro, proto)
1625
1626    aw = coro.__await__()
1627    try:
1628        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1629            with pytest.raises((TypeError, pickle.PicklingError)):
1630                pickle.dumps(aw, proto)
1631    finally:
1632        aw.close()
1633
1634
1635@pytest.mark.skipif("sys.version_info[1] < 8")
1636def test_for_assign_raising_stop_async_iteration(lop):
1637    class BadTarget:
1638        def __setitem__(self, key, value):
1639            raise StopAsyncIteration(42)
1640
1641    tgt = BadTarget()
1642
1643    async def source():
1644        yield 10
1645
1646    async def run_for():
1647        with pytest.raises(StopAsyncIteration) as cm:
1648            async for tgt[0] in source():
1649                pass
1650        assert cm.value.args == (42,)
1651        return 'end'
1652
1653    assert run_async(run_for()) == ([], 'end')
1654
1655    async def run_list():
1656        with pytest.raises(StopAsyncIteration) as cm:
1657            return [0 async for tgt[0] in lop.Proxy(source)]
1658        assert cm.value.args == (42,)
1659        return 'end'
1660
1661    assert run_async(run_list()) == ([], 'end')
1662
1663    async def run_gen():
1664        gen = (0 async for tgt[0] in lop.Proxy(source))
1665        a = gen.asend(None)
1666        with pytest.raises(RuntimeError) as cm:
1667            await a
1668        assert isinstance(cm.value.__cause__, StopAsyncIteration)
1669        assert cm.value.__cause__.args == (42,)
1670        return 'end'
1671
1672    assert run_async(run_gen()) == ([], 'end')
1673
1674
1675@pytest.mark.skipif("sys.version_info[1] < 8")
1676def test_for_assign_raising_stop_async_iteration_2(lop):
1677    class BadIterable:
1678        def __iter__(self):
1679            raise StopAsyncIteration(42)
1680
1681    async def badpairs():
1682        yield BadIterable()
1683
1684    async def run_for():
1685        with pytest.raises(StopAsyncIteration) as cm:
1686            async for i, j in lop.Proxy(badpairs):
1687                pass
1688        assert cm.value.args == (42,)
1689        return 'end'
1690
1691    assert run_async(run_for()) == ([], 'end')
1692
1693    async def run_list():
1694        with pytest.raises(StopAsyncIteration) as cm:
1695            return [0 async for i, j in badpairs()]
1696        assert cm.value.args == (42,)
1697        return 'end'
1698
1699    assert run_async(run_list()) == ([], 'end')
1700
1701    async def run_gen():
1702        gen = (0 async for i, j in badpairs())
1703        a = gen.asend(None)
1704        with pytest.raises(RuntimeError) as cm:
1705            await a
1706        assert isinstance(cm.value.__cause__, StopAsyncIteration)
1707        assert cm.value.__cause__.args == (42,)
1708        return 'end'
1709
1710    assert run_async(run_gen()) == ([], 'end')
1711
1712
1713def test_asyncio_1(lop):
1714    import asyncio
1715
1716    class MyException(Exception):
1717        pass
1718
1719    buffer = []
1720
1721    class CM:
1722        async def __aenter__(self):
1723            buffer.append(1)
1724            await lop.Proxy(lambda: asyncio.sleep(0.01))
1725            buffer.append(2)
1726            return self
1727
1728        async def __aexit__(self, exc_type, exc_val, exc_tb):
1729            await lop.Proxy(lambda: asyncio.sleep(0.01))
1730            buffer.append(exc_type.__name__)
1731
1732    async def f():
1733        async with lop.Proxy(CM) as c:
1734            await lop.Proxy(lambda: asyncio.sleep(0.01))
1735            raise MyException
1736        buffer.append('unreachable')
1737
1738    loop = asyncio.new_event_loop()
1739    asyncio.set_event_loop(loop)
1740    try:
1741        loop.run_until_complete(f())
1742    except MyException:
1743        pass
1744    finally:
1745        loop.close()
1746        asyncio.set_event_loop_policy(None)
1747
1748    assert buffer == [1, 2, 'MyException']
1749