Skip to content

Commit

Permalink
nest_asyncio
Browse files Browse the repository at this point in the history
  • Loading branch information
m9810223 committed May 29, 2024
1 parent 56fc13a commit 7a7cf6a
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 16 deletions.
12 changes: 1 addition & 11 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ distribution = true
dev = [
"pytest>=7.4.0",
"ipython>=8.12.2",
"nest-asyncio>=1.6.0",
]

[tool.pdm.scripts]
Expand Down
68 changes: 64 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,73 @@
import asyncio
import asyncio.events as events
from contextlib import contextmanager
import os
import threading

import nest_asyncio
import pytest_asyncio


def _patch_loop(loop): # nest_asyncio
"""Patch loop to make it reentrant."""

def run_until_complete(self, future):
with manage_run(self):
f = asyncio.ensure_future(future, loop=self)
if f is not future:
f._log_destroy_pending = False
while not f.done():
self._run_once()
if self._stopping:
break
if not f.done():
raise RuntimeError('Event loop stopped before Future completed.') # noqa: TRY003
return f.result()

@contextmanager
def manage_run(self):
"""Set up the loop for running."""
self._check_closed()
old_thread_id = self._thread_id
old_running_loop = events._get_running_loop()
try:
self._thread_id = threading.get_ident()
events._set_running_loop(self)
self._num_runs_pending += 1
if self._is_proactorloop:
if self._self_reading_future is None:
self.call_soon(self._loop_self_reading)
yield
finally:
self._thread_id = old_thread_id
events._set_running_loop(old_running_loop)
self._num_runs_pending -= 1
if self._is_proactorloop:
if self._num_runs_pending == 0 and self._self_reading_future is not None:
ov = self._self_reading_future._ov
self._self_reading_future.cancel()
if ov is not None:
self._proactor._unregister(ov)
self._self_reading_future = None

def _check_running(self):
"""Do not throw exception if loop is already running."""
pass

if hasattr(loop, '_nest_patched'):
return
if not isinstance(loop, asyncio.BaseEventLoop):
raise ValueError("Can't patch loop of type %s" % type(loop)) # noqa: TRY004
cls = loop.__class__
cls.run_until_complete = run_until_complete
cls._check_running = _check_running
cls._num_runs_pending = 1 if loop.is_running() else 0
cls._is_proactorloop = os.name == 'nt' and issubclass(cls, asyncio.ProactorEventLoop)
cls._nest_patched = True


@pytest_asyncio.fixture(scope='session')
def event_loop(): # https://pytest-asyncio.readthedocs.io/en/latest/reference/fixtures.html#fixtures
policy = asyncio.get_event_loop_policy()
loop = policy.new_event_loop()
nest_asyncio.apply(loop)
loop = asyncio.get_event_loop_policy().new_event_loop()
_patch_loop(loop)
yield loop
loop.close()

0 comments on commit 7a7cf6a

Please sign in to comment.