|
| 1 | +import gc |
| 2 | +import sys |
1 | 3 | import json
|
| 4 | +import typing |
2 | 5 | import asyncio
|
3 | 6 | import inspect
|
4 | 7 | import logging
|
@@ -43,6 +46,46 @@ def pytest_collection_modifyitems(session, config, items):
|
43 | 46 | item.add_marker(pytest.mark.filterwarnings("error::RuntimeWarning"))
|
44 | 47 |
|
45 | 48 |
|
| 49 | +@pytest.hookimpl(trylast=True) |
| 50 | +def pytest_fixture_post_finalizer(fixturedef, request) -> None: |
| 51 | + """Called after fixture teardown""" |
| 52 | + if fixturedef.argname != "event_loop": |
| 53 | + return |
| 54 | + |
| 55 | + policy = asyncio.get_event_loop_policy() |
| 56 | + try: |
| 57 | + loop = policy.get_event_loop() |
| 58 | + except RuntimeError: |
| 59 | + loop = None |
| 60 | + if loop is not None: |
| 61 | + # Cleanup code based on the implementation of asyncio.run() |
| 62 | + try: |
| 63 | + if not loop.is_closed(): |
| 64 | + asyncio.runners._cancel_all_tasks(loop) # type: ignore[attr-defined] |
| 65 | + loop.run_until_complete(loop.shutdown_asyncgens()) |
| 66 | + if sys.version_info >= (3, 9): |
| 67 | + loop.run_until_complete(loop.shutdown_default_executor()) |
| 68 | + finally: |
| 69 | + loop.close() |
| 70 | + new_loop = policy.new_event_loop() # Replace existing event loop |
| 71 | + # Ensure subsequent calls to get_event_loop() succeed |
| 72 | + policy.set_event_loop(new_loop) |
| 73 | + |
| 74 | + |
| 75 | +@pytest.fixture |
| 76 | +def event_loop( |
| 77 | + request: pytest.FixtureRequest, |
| 78 | +) -> typing.Iterator[asyncio.AbstractEventLoop]: |
| 79 | + """Create an instance of the default event loop for each test case.""" |
| 80 | + yield asyncio.get_event_loop_policy().new_event_loop() |
| 81 | + # Call the garbage collector to trigger ResourceWarning's as soon |
| 82 | + # as possible (these are triggered in various __del__ methods). |
| 83 | + # Without this, resources opened in one test can fail other tests |
| 84 | + # when the warning is generated. |
| 85 | + gc.collect() |
| 86 | + # Event loop cleanup handled by pytest_fixture_post_finalizer |
| 87 | + |
| 88 | + |
46 | 89 | class ForwardingSerialTransport:
|
47 | 90 | """
|
48 | 91 | Serial transport that hooks directly into a protocol
|
|
0 commit comments