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