Skip to content

Commit 0461429

Browse files
committed
remove asyncio from contextlib async tests
1 parent d9ed42b commit 0461429

File tree

1 file changed

+62
-33
lines changed

1 file changed

+62
-33
lines changed

Lib/test/test_contextlib_async.py

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import asyncio
1+
import functools
22
from contextlib import (
33
asynccontextmanager, AbstractAsyncContextManager,
44
AsyncExitStack, nullcontext, aclosing, contextmanager)
@@ -8,14 +8,32 @@
88

99
from test.test_contextlib import TestBaseExitStack
1010

11-
support.requires_working_socket(module=True)
1211

13-
def tearDownModule():
14-
asyncio._set_event_loop_policy(None)
12+
def _run_async_fn(async_fn, /, *args, **kwargs):
13+
coro = async_fn(*args, **kwargs)
14+
gen = type(coro).__await__(coro)
15+
try:
16+
gen.send(None)
17+
except StopIteration as e:
18+
return e.value
19+
else:
20+
raise AssertionError("coroutine did not stop")
21+
finally:
22+
gen.close()
1523

1624

17-
class TestAbstractAsyncContextManager(unittest.IsolatedAsyncioTestCase):
25+
def _async_test(async_fn):
26+
"""Decorator to turn an async function into a test case."""
27+
@functools.wraps(async_fn)
28+
def wrapper(*args, **kwargs):
29+
return _run_async_fn(async_fn, *args, **kwargs)
1830

31+
return wrapper
32+
33+
34+
class TestAbstractAsyncContextManager(unittest.TestCase):
35+
36+
@_async_test
1937
async def test_enter(self):
2038
class DefaultEnter(AbstractAsyncContextManager):
2139
async def __aexit__(self, *args):
@@ -27,6 +45,7 @@ async def __aexit__(self, *args):
2745
async with manager as context:
2846
self.assertIs(manager, context)
2947

48+
@_async_test
3049
async def test_slots(self):
3150
class DefaultAsyncContextManager(AbstractAsyncContextManager):
3251
__slots__ = ()
@@ -38,6 +57,7 @@ async def __aexit__(self, *args):
3857
manager = DefaultAsyncContextManager()
3958
manager.var = 42
4059

60+
@_async_test
4161
async def test_async_gen_propagates_generator_exit(self):
4262
# A regression test for https://bugs.python.org/issue33786.
4363

@@ -88,8 +108,9 @@ class NoneAexit(ManagerFromScratch):
88108
self.assertFalse(issubclass(NoneAexit, AbstractAsyncContextManager))
89109

90110

91-
class AsyncContextManagerTestCase(unittest.IsolatedAsyncioTestCase):
111+
class AsyncContextManagerTestCase(unittest.TestCase):
92112

113+
@_async_test
93114
async def test_contextmanager_plain(self):
94115
state = []
95116
@asynccontextmanager
@@ -103,6 +124,7 @@ async def woohoo():
103124
state.append(x)
104125
self.assertEqual(state, [1, 42, 999])
105126

127+
@_async_test
106128
async def test_contextmanager_finally(self):
107129
state = []
108130
@asynccontextmanager
@@ -120,6 +142,7 @@ async def woohoo():
120142
raise ZeroDivisionError()
121143
self.assertEqual(state, [1, 42, 999])
122144

145+
@_async_test
123146
async def test_contextmanager_traceback(self):
124147
@asynccontextmanager
125148
async def f():
@@ -175,6 +198,7 @@ class StopAsyncIterationSubclass(StopAsyncIteration):
175198
self.assertEqual(frames[0].name, 'test_contextmanager_traceback')
176199
self.assertEqual(frames[0].line, 'raise stop_exc')
177200

201+
@_async_test
178202
async def test_contextmanager_no_reraise(self):
179203
@asynccontextmanager
180204
async def whee():
@@ -184,6 +208,7 @@ async def whee():
184208
# Calling __aexit__ should not result in an exception
185209
self.assertFalse(await ctx.__aexit__(TypeError, TypeError("foo"), None))
186210

211+
@_async_test
187212
async def test_contextmanager_trap_yield_after_throw(self):
188213
@asynccontextmanager
189214
async def whoo():
@@ -199,6 +224,7 @@ async def whoo():
199224
# The "gen" attribute is an implementation detail.
200225
self.assertFalse(ctx.gen.ag_suspended)
201226

227+
@_async_test
202228
async def test_contextmanager_trap_no_yield(self):
203229
@asynccontextmanager
204230
async def whoo():
@@ -208,6 +234,7 @@ async def whoo():
208234
with self.assertRaises(RuntimeError):
209235
await ctx.__aenter__()
210236

237+
@_async_test
211238
async def test_contextmanager_trap_second_yield(self):
212239
@asynccontextmanager
213240
async def whoo():
@@ -221,6 +248,7 @@ async def whoo():
221248
# The "gen" attribute is an implementation detail.
222249
self.assertFalse(ctx.gen.ag_suspended)
223250

251+
@_async_test
224252
async def test_contextmanager_non_normalised(self):
225253
@asynccontextmanager
226254
async def whoo():
@@ -234,6 +262,7 @@ async def whoo():
234262
with self.assertRaises(SyntaxError):
235263
await ctx.__aexit__(RuntimeError, None, None)
236264

265+
@_async_test
237266
async def test_contextmanager_except(self):
238267
state = []
239268
@asynccontextmanager
@@ -251,6 +280,7 @@ async def woohoo():
251280
raise ZeroDivisionError(999)
252281
self.assertEqual(state, [1, 42, 999])
253282

283+
@_async_test
254284
async def test_contextmanager_except_stopiter(self):
255285
@asynccontextmanager
256286
async def woohoo():
@@ -277,6 +307,7 @@ class StopAsyncIterationSubclass(StopAsyncIteration):
277307
else:
278308
self.fail(f'{stop_exc} was suppressed')
279309

310+
@_async_test
280311
async def test_contextmanager_wrap_runtimeerror(self):
281312
@asynccontextmanager
282313
async def woohoo():
@@ -321,12 +352,14 @@ def test_contextmanager_doc_attrib(self):
321352
self.assertEqual(baz.__doc__, "Whee!")
322353

323354
@support.requires_docstrings
355+
@_async_test
324356
async def test_instance_docstring_given_cm_docstring(self):
325357
baz = self._create_contextmanager_attribs()(None)
326358
self.assertEqual(baz.__doc__, "Whee!")
327359
async with baz:
328360
pass # suppress warning
329361

362+
@_async_test
330363
async def test_keywords(self):
331364
# Ensure no keyword arguments are inhibited
332365
@asynccontextmanager
@@ -335,6 +368,7 @@ async def woohoo(self, func, args, kwds):
335368
async with woohoo(self=11, func=22, args=33, kwds=44) as target:
336369
self.assertEqual(target, (11, 22, 33, 44))
337370

371+
@_async_test
338372
async def test_recursive(self):
339373
depth = 0
340374
ncols = 0
@@ -361,6 +395,7 @@ async def recursive():
361395
self.assertEqual(ncols, 10)
362396
self.assertEqual(depth, 0)
363397

398+
@_async_test
364399
async def test_decorator(self):
365400
entered = False
366401

@@ -379,6 +414,7 @@ async def test():
379414
await test()
380415
self.assertFalse(entered)
381416

417+
@_async_test
382418
async def test_decorator_with_exception(self):
383419
entered = False
384420

@@ -401,6 +437,7 @@ async def test():
401437
await test()
402438
self.assertFalse(entered)
403439

440+
@_async_test
404441
async def test_decorating_method(self):
405442

406443
@asynccontextmanager
@@ -435,14 +472,15 @@ async def method(self, a, b, c=None):
435472
self.assertEqual(test.b, 2)
436473

437474

438-
class AclosingTestCase(unittest.IsolatedAsyncioTestCase):
475+
class AclosingTestCase(unittest.TestCase):
439476

440477
@support.requires_docstrings
441478
def test_instance_docs(self):
442479
cm_docstring = aclosing.__doc__
443480
obj = aclosing(None)
444481
self.assertEqual(obj.__doc__, cm_docstring)
445482

483+
@_async_test
446484
async def test_aclosing(self):
447485
state = []
448486
class C:
@@ -454,6 +492,7 @@ async def aclose(self):
454492
self.assertEqual(x, y)
455493
self.assertEqual(state, [1])
456494

495+
@_async_test
457496
async def test_aclosing_error(self):
458497
state = []
459498
class C:
@@ -467,6 +506,7 @@ async def aclose(self):
467506
1 / 0
468507
self.assertEqual(state, [1])
469508

509+
@_async_test
470510
async def test_aclosing_bpo41229(self):
471511
state = []
472512

@@ -492,45 +532,27 @@ async def agenfunc():
492532
self.assertEqual(state, [1])
493533

494534

495-
class TestAsyncExitStack(TestBaseExitStack, unittest.IsolatedAsyncioTestCase):
535+
class TestAsyncExitStack(TestBaseExitStack, unittest.TestCase):
496536
class SyncAsyncExitStack(AsyncExitStack):
497-
@staticmethod
498-
def run_coroutine(coro):
499-
loop = asyncio.new_event_loop()
500-
t = loop.create_task(coro)
501-
t.add_done_callback(lambda f: loop.stop())
502-
loop.run_forever()
503-
504-
exc = t.exception()
505-
if not exc:
506-
return t.result()
507-
else:
508-
context = exc.__context__
509-
510-
try:
511-
raise exc
512-
except:
513-
exc.__context__ = context
514-
raise exc
515537

516538
def close(self):
517-
return self.run_coroutine(self.aclose())
539+
return _run_async_fn(self.aclose)
518540

519541
def __enter__(self):
520-
return self.run_coroutine(self.__aenter__())
542+
return _run_async_fn(self.__aenter__)
521543

522544
def __exit__(self, *exc_details):
523-
return self.run_coroutine(self.__aexit__(*exc_details))
545+
return _run_async_fn(self.__aexit__, *exc_details)
524546

525547
exit_stack = SyncAsyncExitStack
526548
callback_error_internal_frames = [
527-
('__exit__', 'return self.run_coroutine(self.__aexit__(*exc_details))'),
528-
('run_coroutine', 'raise exc'),
529-
('run_coroutine', 'raise exc'),
549+
('__exit__', 'return _run_async_fn(self.__aexit__, *exc_details)'),
550+
('_run_async_fn', 'gen.send(None)'),
530551
('__aexit__', 'raise exc'),
531552
('__aexit__', 'cb_suppress = cb(*exc_details)'),
532553
]
533554

555+
@_async_test
534556
async def test_async_callback(self):
535557
expected = [
536558
((), {}),
@@ -573,6 +595,7 @@ async def _exit(*args, **kwds):
573595
stack.push_async_callback(callback=_exit, arg=3)
574596
self.assertEqual(result, [])
575597

598+
@_async_test
576599
async def test_async_push(self):
577600
exc_raised = ZeroDivisionError
578601
async def _expect_exc(exc_type, exc, exc_tb):
@@ -608,6 +631,7 @@ async def __aexit__(self, *exc_details):
608631
self.assertIs(stack._exit_callbacks[-1][1], _expect_exc)
609632
1/0
610633

634+
@_async_test
611635
async def test_enter_async_context(self):
612636
class TestCM(object):
613637
async def __aenter__(self):
@@ -629,6 +653,7 @@ async def _exit():
629653

630654
self.assertEqual(result, [1, 2, 3, 4])
631655

656+
@_async_test
632657
async def test_enter_async_context_errors(self):
633658
class LacksEnterAndExit:
634659
pass
@@ -648,6 +673,7 @@ async def __aenter__(self):
648673
await stack.enter_async_context(LacksExit())
649674
self.assertFalse(stack._exit_callbacks)
650675

676+
@_async_test
651677
async def test_async_exit_exception_chaining(self):
652678
# Ensure exception chaining matches the reference behaviour
653679
async def raise_exc(exc):
@@ -679,6 +705,7 @@ async def suppress_exc(*exc_details):
679705
self.assertIsInstance(inner_exc, ValueError)
680706
self.assertIsInstance(inner_exc.__context__, ZeroDivisionError)
681707

708+
@_async_test
682709
async def test_async_exit_exception_explicit_none_context(self):
683710
# Ensure AsyncExitStack chaining matches actual nested `with` statements
684711
# regarding explicit __context__ = None.
@@ -713,6 +740,7 @@ async def my_cm_with_exit_stack():
713740
else:
714741
self.fail("Expected IndexError, but no exception was raised")
715742

743+
@_async_test
716744
async def test_instance_bypass_async(self):
717745
class Example(object): pass
718746
cm = Example()
@@ -725,7 +753,8 @@ class Example(object): pass
725753
self.assertIs(stack._exit_callbacks[-1][1], cm)
726754

727755

728-
class TestAsyncNullcontext(unittest.IsolatedAsyncioTestCase):
756+
class TestAsyncNullcontext(unittest.TestCase):
757+
@_async_test
729758
async def test_async_nullcontext(self):
730759
class C:
731760
pass

0 commit comments

Comments
 (0)