diff --git a/mypyc/test-data/driver/driver.py b/mypyc/test-data/driver/driver.py index 1ec1c48dfb75..395be6e1630e 100644 --- a/mypyc/test-data/driver/driver.py +++ b/mypyc/test-data/driver/driver.py @@ -9,6 +9,10 @@ import sys import native +import asyncio +import inspect + +evloop = asyncio.new_event_loop() failures = [] tests_run = 0 @@ -18,7 +22,10 @@ test_func = getattr(native, name) tests_run += 1 try: - test_func() + if inspect.iscoroutinefunction(test_func): + evloop.run_until_complete(test_func) + else: + test_func() except Exception as e: failures.append((name, sys.exc_info())) diff --git a/mypyc/test-data/run-async.test b/mypyc/test-data/run-async.test index f1ec7e8f85e0..a1112e964671 100644 --- a/mypyc/test-data/run-async.test +++ b/mypyc/test-data/run-async.test @@ -22,12 +22,12 @@ async def f2() -> int: x += i + await f() + await g() return x -def test_simple_call() -> None: - result = asyncio.run(f()) +async def test_simple_call() -> None: + result = await f() assert result == 3 -def test_multiple_awaits_in_expression() -> None: - result = asyncio.run(f2()) +async def test_multiple_awaits_in_expression() -> None: + result = await f2() assert result == 9 class MyError(Exception): @@ -61,17 +61,17 @@ async def exc6() -> int: return 3 return 4 -def test_exception() -> None: +async def test_exception() -> None: with assertRaises(MyError): - asyncio.run(exc1()) + await exc1() with assertRaises(MyError): - asyncio.run(exc2()) + await exc2() with assertRaises(MyError): - asyncio.run(exc3()) + await exc3() with assertRaises(MyError): - asyncio.run(exc4()) - assert asyncio.run(exc5()) == 3 - assert asyncio.run(exc6()) == 3 + await exc4() + assert await exc5() == 3 + assert await exc6() == 3 async def indirect_call(x: int, c: Callable[[int], Awaitable[int]]) -> int: return await c(x) @@ -92,20 +92,20 @@ async def ident(x: float, err: bool = False) -> float: raise MyError() return x + float("0.0") -def test_indirect_call() -> None: - assert asyncio.run(indirect_call(3, inc)) == 4 +async def test_indirect_call() -> None: + assert await indirect_call(3, inc) == 4 with assertRaises(MyError): - asyncio.run(indirect_call_2(exc1())) + await indirect_call_2(exc1()) - assert asyncio.run(indirect_call_3(ident(2.0))) == 3.0 - assert asyncio.run(indirect_call_3(ident(-113.0))) == -112.0 - assert asyncio.run(indirect_call_3(ident(-114.0))) == -113.0 + assert await indirect_call_3(ident(2.0)) == 3.0 + assert await indirect_call_3(ident(-113.0)) == -112.0 + assert await indirect_call_3(ident(-114.0)) == -113.0 with assertRaises(MyError): - asyncio.run(indirect_call_3(ident(1.0, True))) + await indirect_call_3(ident(1.0, True)) with assertRaises(MyError): - asyncio.run(indirect_call_3(ident(-113.0, True))) + await indirect_call_3(ident(-113.0, True)) class C: def __init__(self, n: int) -> None: @@ -125,15 +125,13 @@ async def method_call_exception() -> int: c = C(5) return await c.add(3, err=True) -def test_async_method_call() -> None: - assert asyncio.run(method_call(3)) == 8 +async def test_async_method_call() -> None: + assert await method_call(3) == 8 with assertRaises(MyError): - asyncio.run(method_call_exception()) + await method_call_exception() [file asyncio/__init__.pyi] async def sleep(t: float) -> None: ... -# eh, we could use the real type but it doesn't seem important -def run(x: object) -> object: ... [typing fixtures/typing-full.pyi] @@ -159,16 +157,16 @@ async def branch_await_not() -> int: return 3 return 2 -def test_branch() -> None: - assert asyncio.run(branch_await()) == 3 - assert asyncio.run(branch_await_not()) == 2 +async def test_branch() -> None: + assert await branch_await() == 3 + assert await branch_await_not() == 2 async def assign_multi() -> int: _, x = int(), await one() return x + 1 -def test_assign_multi() -> None: - assert asyncio.run(assign_multi()) == 2 +async def test_assign_multi() -> None: + assert await assign_multi() == 2 class C: def __init__(self, s: str) -> None: @@ -188,8 +186,8 @@ async def concat(s: str, t: str) -> str: async def set_attr(s: str) -> None: (await make_c("xyz")).s = await concat(s, "!") -def test_set_attr() -> None: - asyncio.run(set_attr("foo")) # Just check that it compiles and runs +async def test_set_attr() -> None: + await set_attr("foo") # Just check that it compiles and runs def concat2(x: str, y: str) -> str: return x + y @@ -200,15 +198,15 @@ async def call1(s: str) -> str: async def call2(s: str) -> str: return await concat(str(int()), await concat(s, "b")) -def test_call() -> None: - assert asyncio.run(call1("foo")) == "0fooa" - assert asyncio.run(call2("foo")) == "0foob" +async def test_call() -> None: + assert await call1("foo") == "0fooa" + assert await call2("foo") == "0foob" async def method_call(s: str) -> str: return C("<").concat(await concat(s, ">")) -def test_method_call() -> None: - assert asyncio.run(method_call("foo")) == "" +async def test_method_call() -> None: + assert await method_call("foo") == "" class D: def __init__(self, a: str, b: str) -> None: @@ -219,13 +217,11 @@ async def construct(s: str) -> str: c = D(await concat(s, "!"), await concat(s, "?")) return c.a + c.b -def test_construct() -> None: - assert asyncio.run(construct("foo")) == "foo!foo?" +async def test_construct() -> None: + assert await construct("foo") == "foo!foo?" [file asyncio/__init__.pyi] async def sleep(t: float) -> None: ... -# eh, we could use the real type but it doesn't seem important -def run(x: object) -> object: ... [typing fixtures/typing-full.pyi] @@ -361,7 +357,7 @@ class ConManB: async def __aexit__(self, *exc: object): pass -async def x() -> None: +async def test_x() -> None: value = 2 async with ConMan() as f: value += f @@ -370,12 +366,6 @@ async def x() -> None: value += f assert value == 5, value -[typing fixtures/typing-full.pyi] -[file driver.py] -import asyncio -import native -asyncio.run(native.x()) - [case testRunAsyncSpecialCases] import asyncio @@ -385,8 +375,8 @@ async def t() -> tuple[int, str, str]: async def f() -> tuple[int, str, str]: return await t() -def test_tuple_return() -> None: - result = asyncio.run(f()) +async def test_tuple_return() -> None: + result = await f() assert result == (1, "x", "y") async def e() -> ValueError: @@ -395,14 +385,12 @@ async def e() -> ValueError: async def g() -> ValueError: return await e() -def test_exception_return() -> None: - result = asyncio.run(g()) +async def test_exception_return() -> None: + result = await g() assert isinstance(result, ValueError) [file asyncio/__init__.pyi] async def sleep(t: float) -> None: ... -# eh, we could use the real type but it doesn't seem important -def run(x: object) -> object: ... [typing fixtures/typing-full.pyi] @@ -410,15 +398,15 @@ def run(x: object) -> object: ... import asyncio import gc -def assert_no_leaks(fn, max_new): +async def assert_no_leaks(fn, max_new): # Warm-up, in case asyncio allocates something on first use - asyncio.run(fn()) + await fn() gc.collect() old_objs = gc.get_objects() for i in range(10): - asyncio.run(fn()) + await fn() gc.collect() new_objs = gc.get_objects() @@ -438,8 +426,8 @@ async def foo(n: int) -> str: s = await concat_one(s) return s -def test_trivial() -> None: - assert_no_leaks(lambda: foo(1000), 5) +async def test_trivial() -> None: + await assert_no_leaks(lambda: foo(1000), 5) async def make_list(a: list[int]) -> list[int]: await concat_one("foobar") @@ -456,8 +444,8 @@ async def bar(n: int) -> None: for i in range(n): await spill() -def test_spilled() -> None: - assert_no_leaks(lambda: bar(40), 2) +async def test_spilled() -> None: + await assert_no_leaks(lambda: bar(80), 2) async def raise_deep(n: int) -> str: if n == 0: @@ -484,8 +472,8 @@ async def exc(n: int) -> list[str]: a.append(str(int() + 5)) return a -def test_exception() -> None: - assert_no_leaks(lambda: exc(50), 2) +async def test_exception() -> None: + await assert_no_leaks(lambda: exc(50), 2) class C: def __init__(self, s: str) -> None: @@ -507,11 +495,10 @@ async def stolen(n: int) -> int: assert s == str(i + 2) + "1" return n -def test_stolen() -> None: - assert_no_leaks(lambda: stolen(100), 2) +async def test_stolen() -> None: + await assert_no_leaks(lambda: stolen(200), 2) [file asyncio/__init__.pyi] -def run(x: object) -> object: ... async def sleep(t: float) -> None: ... [case testRunAsyncMiscTypesInEnvironment] @@ -559,8 +546,8 @@ async def float_ops(x: float) -> float: n = float("0.5") + await inc_float(n) return n -def test_float() -> None: - assert asyncio.run(float_ops(2.5)) == 5.0 +async def test_float() -> None: + assert await float_ops(2.5) == 5.0 async def i64_ops(x: i64) -> i64: n = x @@ -568,8 +555,8 @@ async def i64_ops(x: i64) -> i64: n = i64("1") + await inc_i64(n) return n -def test_i64() -> None: - assert asyncio.run(i64_ops(2)) == 5 +async def test_i64() -> None: + assert await i64_ops(2) == 5 async def i32_ops(x: i32) -> i32: n = x @@ -577,8 +564,8 @@ async def i32_ops(x: i32) -> i32: n = i32("1") + await inc_i32(n) return n -def test_i32() -> None: - assert asyncio.run(i32_ops(3)) == 6 +async def test_i32() -> None: + assert await i32_ops(3) == 6 async def i16_ops(x: i16) -> i16: n = x @@ -586,8 +573,8 @@ async def i16_ops(x: i16) -> i16: n = i16("1") + await inc_i16(n) return n -def test_i16() -> None: - assert asyncio.run(i16_ops(4)) == 7 +async def test_i16() -> None: + assert await i16_ops(4) == 7 async def u8_ops(x: u8) -> u8: n = x @@ -595,8 +582,8 @@ async def u8_ops(x: u8) -> u8: n = u8("1") + await inc_u8(n) return n -def test_u8() -> None: - assert asyncio.run(u8_ops(5)) == 8 +async def test_u8() -> None: + assert await u8_ops(5) == 8 async def tuple_ops(x: tuple[i64, float]) -> tuple[i64, float]: n = x @@ -604,8 +591,8 @@ async def tuple_ops(x: tuple[i64, float]) -> tuple[i64, float]: m = ((i64("1"), float("0.5")), await inc_tuple(n)) return m[1] -def test_tuple() -> None: - assert asyncio.run(tuple_ops((1, 2.5))) == (3, 5.5) +async def test_tuple() -> None: + assert await tuple_ops((1, 2.5)) == (3, 5.5) async def bool_ops(x: bool) -> bool: n = x @@ -613,9 +600,9 @@ async def bool_ops(x: bool) -> bool: m = (bool("1"), await neg_bool(n)) return m[0] and m[1] -def test_bool() -> None: - assert asyncio.run(bool_ops(True)) is True - assert asyncio.run(bool_ops(False)) is False +async def test_bool() -> None: + assert await bool_ops(True) is True + assert await bool_ops(False) is False [file asyncio/__init__.pyi] def run(x: object) -> object: ... @@ -648,8 +635,8 @@ async def async_def_contains_normal(x: int) -> int: a += nested((await inc(3)), (await inc(4))) return a -def test_async_def_contains_normal() -> None: - assert normal_contains_async_def(2) == (2 + 2 + 4 + 5) +async def test_async_def_contains_normal() -> None: + assert await async_def_contains_normal(2) == (2 + 2 + 4 + 5) async def async_def_contains_async_def(x: int) -> int: async def f(y: int) -> int: @@ -657,8 +644,8 @@ async def async_def_contains_async_def(x: int) -> int: return (await f(1)) + (await f(2)) -def test_async_def_contains_async_def() -> None: - assert asyncio.run(async_def_contains_async_def(3)) == (3 + 1 + 1 + 1) + (3 + 1 + 2 + 1) +async def test_async_def_contains_async_def() -> None: + assert await async_def_contains_async_def(3) == (3 + 1 + 1 + 1) + (3 + 1 + 2 + 1) async def async_def_contains_generator(x: int) -> tuple[int, int, int]: def gen(y: int) -> Iterator[int]: @@ -673,8 +660,8 @@ async def async_def_contains_generator(x: int) -> tuple[int, int, int]: return res -def test_async_def_contains_generator() -> None: - assert asyncio.run(async_def_contains_generator(3)) == (13, 4, 7) +async def test_async_def_contains_generator() -> None: + assert await async_def_contains_generator(3) == (13, 4, 7) def generator_contains_async_def(x: int) -> Iterator[int]: async def f(y: int) -> int: @@ -696,8 +683,8 @@ async def async_def_contains_two_nested_functions(x: int, y: int) -> tuple[int, return (await inc(f(3))), (await inc(g(4, 10))) -def test_async_def_contains_two_nested_functions() -> None: - assert asyncio.run(async_def_contains_two_nested_functions(5, 7)) == ( +async def test_async_def_contains_two_nested_functions() -> None: + assert await async_def_contains_two_nested_functions(5, 7) == ( (5 + 3 + 1), (7 + 4 + 10 + 1) ) @@ -714,8 +701,8 @@ async def async_def_contains_overloaded_async_def(n: int) -> int: return (await f(n)) + 1 -def test_async_def_contains_overloaded_async_def() -> None: - assert asyncio.run(async_def_contains_overloaded_async_def(5)) == 6 +async def test_async_def_contains_overloaded_async_def() -> None: + assert await async_def_contains_overloaded_async_def(5) == 6 T = TypeVar("T") @@ -730,8 +717,9 @@ async def async_def_contains_decorated_async_def(n: int) -> int: return (await f(n)) + 1 -def test_async_def_contains_decorated_async_def() -> None: - assert asyncio.run(async_def_contains_decorated_async_def(7)) == 10 +async def test_async_def_contains_decorated_async_def() -> None: + assert await async_def_contains_decorated_async_def(7) == 10 + [file asyncio/__init__.pyi] def run(x: object) -> object: ... @@ -742,10 +730,7 @@ def run(x: object) -> object: ... # - at least one of those does not explicitly return # - the non-returning path is taken at runtime -import asyncio - - -async def test_mixed_return(b: bool) -> bool: +async def mixed_return(b: bool) -> bool: try: if b: return b @@ -754,33 +739,21 @@ async def test_mixed_return(b: bool) -> bool: return b -async def test_run() -> None: +async def test_async_try_finally_mixed_return() -> None: # Test return path - result1 = await test_mixed_return(True) + result1 = await mixed_return(True) assert result1 == True # Test non-return path - result2 = await test_mixed_return(False) + result2 = await mixed_return(False) assert result2 == False - -def test_async_try_finally_mixed_return() -> None: - asyncio.run(test_run()) - -[file driver.py] -from native import test_async_try_finally_mixed_return -test_async_try_finally_mixed_return() - -[file asyncio/__init__.pyi] -def run(x: object) -> object: ... - [case testAsyncWithMixedReturn] # This used to raise an AttributeError, related to # testAsyncTryFinallyMixedReturn, this is essentially # a far more extensive version of that test surfacing # more edge cases -import asyncio from typing import Optional, Type, Literal @@ -798,14 +771,14 @@ class AsyncContextManager: # Simple async functions (generator class) -async def test_gen_1(b: bool) -> bool: +async def gen_1(b: bool) -> bool: async with AsyncContextManager(): if b: return b return b -async def test_gen_2(b: bool) -> bool: +async def gen_2(b: bool) -> bool: async with AsyncContextManager(): if b: return b @@ -813,7 +786,7 @@ async def test_gen_2(b: bool) -> bool: return b -async def test_gen_3(b: bool) -> bool: +async def gen_3(b: bool) -> bool: async with AsyncContextManager(): if b: return b @@ -822,7 +795,7 @@ async def test_gen_3(b: bool) -> bool: return b -async def test_gen_4(b: bool) -> bool: +async def gen_4(b: bool) -> bool: ret: bool async with AsyncContextManager(): if b: @@ -832,7 +805,7 @@ async def test_gen_4(b: bool) -> bool: return ret -async def test_gen_5(i: int) -> int: +async def gen_5(i: int) -> int: async with AsyncContextManager(): if i == 1: return i @@ -843,7 +816,7 @@ async def test_gen_5(i: int) -> int: return i -async def test_gen_6(i: int) -> int: +async def gen_6(i: int) -> int: async with AsyncContextManager(): if i == 1: return i @@ -854,7 +827,7 @@ async def test_gen_6(i: int) -> int: return i -async def test_gen_7(i: int) -> int: +async def gen_7(i: int) -> int: async with AsyncContextManager(): if i == 1: return i @@ -867,7 +840,7 @@ async def test_gen_7(i: int) -> int: # Async functions with nested functions (environment class) -async def test_env_1(b: bool) -> bool: +async def env_1(b: bool) -> bool: def helper() -> bool: return True @@ -877,7 +850,7 @@ async def test_env_1(b: bool) -> bool: return b -async def test_env_2(b: bool) -> bool: +async def env_2(b: bool) -> bool: def helper() -> bool: return True @@ -888,7 +861,7 @@ async def test_env_2(b: bool) -> bool: return b -async def test_env_3(b: bool) -> bool: +async def env_3(b: bool) -> bool: def helper() -> bool: return True @@ -900,7 +873,7 @@ async def test_env_3(b: bool) -> bool: return b -async def test_env_4(b: bool) -> bool: +async def env_4(b: bool) -> bool: def helper() -> bool: return True @@ -913,7 +886,7 @@ async def test_env_4(b: bool) -> bool: return ret -async def test_env_5(i: int) -> int: +async def env_5(i: int) -> int: def helper() -> int: return 1 @@ -927,7 +900,7 @@ async def test_env_5(i: int) -> int: return i -async def test_env_6(i: int) -> int: +async def env_6(i: int) -> int: def helper() -> int: return 1 @@ -941,7 +914,7 @@ async def test_env_6(i: int) -> int: return i -async def test_env_7(i: int) -> int: +async def env_7(i: int) -> int: def helper() -> int: return 1 @@ -956,87 +929,76 @@ async def test_env_7(i: int) -> int: return i -async def run_all_tests() -> None: +async def test_async_with_mixed_return() -> None: # Test simple async functions (generator class) - # test_env_1: mixed return/no-return - assert await test_gen_1(True) is True - assert await test_gen_1(False) is False - - # test_gen_2: all branches return - assert await test_gen_2(True) is True - assert await test_gen_2(False) is False - - # test_gen_3: mixed return/pass - assert await test_gen_3(True) is True - assert await test_gen_3(False) is False - - # test_gen_4: no returns in async with - assert await test_gen_4(True) is True - assert await test_gen_4(False) is False - - # test_gen_5: multiple branches, some return - assert await test_gen_5(0) == 0 - assert await test_gen_5(1) == 1 - assert await test_gen_5(2) == 2 - assert await test_gen_5(3) == 3 - - # test_gen_6: all explicit branches return, implicit fallthrough - assert await test_gen_6(0) == 0 - assert await test_gen_6(1) == 1 - assert await test_gen_6(2) == 2 - assert await test_gen_6(3) == 3 - - # test_gen_7: all branches return including else - assert await test_gen_7(0) == 0 - assert await test_gen_7(1) == 1 - assert await test_gen_7(2) == 2 - assert await test_gen_7(3) == 3 + # env_1: mixed return/no-return + assert await gen_1(True) is True + assert await gen_1(False) is False + + # gen_2: all branches return + assert await gen_2(True) is True + assert await gen_2(False) is False + + # gen_3: mixed return/pass + assert await gen_3(True) is True + assert await gen_3(False) is False + + # gen_4: no returns in async with + assert await gen_4(True) is True + assert await gen_4(False) is False + + # gen_5: multiple branches, some return + assert await gen_5(0) == 0 + assert await gen_5(1) == 1 + assert await gen_5(2) == 2 + assert await gen_5(3) == 3 + + # gen_6: all explicit branches return, implicit fallthrough + assert await gen_6(0) == 0 + assert await gen_6(1) == 1 + assert await gen_6(2) == 2 + assert await gen_6(3) == 3 + + # gen_7: all branches return including else + assert await gen_7(0) == 0 + assert await gen_7(1) == 1 + assert await gen_7(2) == 2 + assert await gen_7(3) == 3 # Test async functions with nested functions (environment class) - # test_env_1: mixed return/no-return - assert await test_env_1(True) is True - assert await test_env_1(False) is False - - # test_env_2: all branches return - assert await test_env_2(True) is True - assert await test_env_2(False) is False - - # test_env_3: mixed return/pass - assert await test_env_3(True) is True - assert await test_env_3(False) is False - - # test_env_4: no returns in async with - assert await test_env_4(True) is True - assert await test_env_4(False) is False - - # test_env_5: multiple branches, some return - assert await test_env_5(0) == 0 - assert await test_env_5(1) == 1 - assert await test_env_5(2) == 2 - assert await test_env_5(3) == 3 - - # test_env_6: all explicit branches return, implicit fallthrough - assert await test_env_6(0) == 0 - assert await test_env_6(1) == 1 - assert await test_env_6(2) == 2 - assert await test_env_6(3) == 3 - - # test_env_7: all branches return including else - assert await test_env_7(0) == 0 - assert await test_env_7(1) == 1 - assert await test_env_7(2) == 2 - assert await test_env_7(3) == 3 - - -def test_async_with_mixed_return() -> None: - asyncio.run(run_all_tests()) - -[file driver.py] -from native import test_async_with_mixed_return -test_async_with_mixed_return() - -[file asyncio/__init__.pyi] -def run(x: object) -> object: ... + # env_1: mixed return/no-return + assert await env_1(True) is True + assert await env_1(False) is False + + # env_2: all branches return + assert await env_2(True) is True + assert await env_2(False) is False + + # env_3: mixed return/pass + assert await env_3(True) is True + assert await env_3(False) is False + + # env_4: no returns in async with + assert await env_4(True) is True + assert await env_4(False) is False + + # env_5: multiple branches, some return + assert await env_5(0) == 0 + assert await env_5(1) == 1 + assert await env_5(2) == 2 + assert await env_5(3) == 3 + + # env_6: all explicit branches return, implicit fallthrough + assert await env_6(0) == 0 + assert await env_6(1) == 1 + assert await env_6(2) == 2 + assert await env_6(3) == 3 + + # env_7: all branches return including else + assert await env_7(0) == 0 + assert await env_7(1) == 1 + assert await env_7(2) == 2 + assert await env_7(3) == 3 [case testAsyncTryExceptFinallyAwait] import asyncio @@ -1127,49 +1089,48 @@ async def async_no_exception_with_await_in_finally() -> int: await asyncio.sleep(0) return 2 # Should not reach this -def test_async_try_except_finally_await() -> None: +async def test_async_try_except_finally_await() -> None: # Test 0: Simplest case - just try/finally with exception # Expected: ValueError propagates with assertRaises(ValueError): - asyncio.run(simple_try_finally_await()) + await simple_try_finally_await() # Test 1: Exception caught, not re-raised # Expected: return 2 (from except block) - result = asyncio.run(async_try_except_no_reraise()) + result = await async_try_except_no_reraise() assert result == 2, f"Expected 2, got {result}" # Test 2: Exception caught and re-raised # Expected: ValueError propagates with assertRaises(ValueError): - asyncio.run(async_try_except_reraise()) + await async_try_except_reraise() # Test 3: Exception caught, different exception raised # Expected: RuntimeError propagates with assertRaises(RuntimeError): - asyncio.run(async_try_except_raise_different()) + await async_try_except_raise_different() # Test 4: Try/except inside finally # Expected: ValueError propagates (outer exception) with assertRaises(ValueError): - asyncio.run(async_try_except_inside_finally()) + await async_try_except_inside_finally() # Test 5: Try/finally inside finally # Expected: RuntimeError propagates (inner error) with assertRaises(RuntimeError): - asyncio.run(async_try_finally_inside_finally()) + await async_try_finally_inside_finally() # Control case: No await in finally (should work correctly) with assertRaises(TestError): - asyncio.run(async_exception_no_await_in_finally()) + await async_exception_no_await_in_finally() # Test normal flow (no exception) # Expected: return 1 - result = asyncio.run(async_no_exception_with_await_in_finally()) + result = await async_no_exception_with_await_in_finally() assert result == 1, f"Expected 1, got {result}" [file asyncio/__init__.pyi] async def sleep(t: float) -> None: ... -def run(x: object) -> object: ... [case testAsyncContextManagerExceptionHandling] import asyncio @@ -1233,18 +1194,17 @@ async def test_exception_in_aexit() -> str: except Exception as e: return f"caught different exception: {type(e).__name__}" -def test_async_context_manager_exception_handling() -> None: +async def test_async_context_manager_exception_handling() -> None: # Test 1: Basic exception propagation - result = asyncio.run(test_basic_exception()) + result = await test_basic_exception() # Expected: "caught ValueError - correct!" assert result == "caught ValueError - correct!", f"Expected exception to propagate, got: {result}" # Test 2: Exception raised in __aexit__ replaces original exception - result = asyncio.run(test_exception_in_aexit()) + result = await test_exception_in_aexit() # Expected: "caught RuntimeError - correct!" # (The RuntimeError from __aexit__ should replace the ValueError) assert result == "caught RuntimeError - correct!", f"Expected RuntimeError from __aexit__, got: {result}" [file asyncio/__init__.pyi] async def sleep(t: float) -> None: ... -def run(x: object) -> object: ...