aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/nest_asyncio.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/nest_asyncio.py')
-rw-r--r--.venv/lib/python3.12/site-packages/nest_asyncio.py219
1 files changed, 219 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/nest_asyncio.py b/.venv/lib/python3.12/site-packages/nest_asyncio.py
new file mode 100644
index 00000000..1cb5c253
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/nest_asyncio.py
@@ -0,0 +1,219 @@
+"""Patch asyncio to allow nested event loops."""
+
+import asyncio
+import asyncio.events as events
+import os
+import sys
+import threading
+from contextlib import contextmanager, suppress
+from heapq import heappop
+
+
+def apply(loop=None):
+ """Patch asyncio to make its event loop reentrant."""
+ _patch_asyncio()
+ _patch_policy()
+ _patch_tornado()
+
+ loop = loop or asyncio.get_event_loop()
+ _patch_loop(loop)
+
+
+def _patch_asyncio():
+ """Patch asyncio module to use pure Python tasks and futures."""
+
+ def run(main, *, debug=False):
+ loop = asyncio.get_event_loop()
+ loop.set_debug(debug)
+ task = asyncio.ensure_future(main)
+ try:
+ return loop.run_until_complete(task)
+ finally:
+ if not task.done():
+ task.cancel()
+ with suppress(asyncio.CancelledError):
+ loop.run_until_complete(task)
+
+ def _get_event_loop(stacklevel=3):
+ loop = events._get_running_loop()
+ if loop is None:
+ loop = events.get_event_loop_policy().get_event_loop()
+ return loop
+
+ # Use module level _current_tasks, all_tasks and patch run method.
+ if hasattr(asyncio, '_nest_patched'):
+ return
+ if sys.version_info >= (3, 6, 0):
+ asyncio.Task = asyncio.tasks._CTask = asyncio.tasks.Task = \
+ asyncio.tasks._PyTask
+ asyncio.Future = asyncio.futures._CFuture = asyncio.futures.Future = \
+ asyncio.futures._PyFuture
+ if sys.version_info < (3, 7, 0):
+ asyncio.tasks._current_tasks = asyncio.tasks.Task._current_tasks
+ asyncio.all_tasks = asyncio.tasks.Task.all_tasks
+ if sys.version_info >= (3, 9, 0):
+ events._get_event_loop = events.get_event_loop = \
+ asyncio.get_event_loop = _get_event_loop
+ asyncio.run = run
+ asyncio._nest_patched = True
+
+
+def _patch_policy():
+ """Patch the policy to always return a patched loop."""
+
+ def get_event_loop(self):
+ if self._local._loop is None:
+ loop = self.new_event_loop()
+ _patch_loop(loop)
+ self.set_event_loop(loop)
+ return self._local._loop
+
+ policy = events.get_event_loop_policy()
+ policy.__class__.get_event_loop = get_event_loop
+
+
+def _patch_loop(loop):
+ """Patch loop to make it reentrant."""
+
+ def run_forever(self):
+ with manage_run(self), manage_asyncgens(self):
+ while True:
+ self._run_once()
+ if self._stopping:
+ break
+ self._stopping = False
+
+ 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.')
+ return f.result()
+
+ def _run_once(self):
+ """
+ Simplified re-implementation of asyncio's _run_once that
+ runs handles as they become ready.
+ """
+ ready = self._ready
+ scheduled = self._scheduled
+ while scheduled and scheduled[0]._cancelled:
+ heappop(scheduled)
+
+ timeout = (
+ 0 if ready or self._stopping
+ else min(max(
+ scheduled[0]._when - self.time(), 0), 86400) if scheduled
+ else None)
+ event_list = self._selector.select(timeout)
+ self._process_events(event_list)
+
+ end_time = self.time() + self._clock_resolution
+ while scheduled and scheduled[0]._when < end_time:
+ handle = heappop(scheduled)
+ ready.append(handle)
+
+ for _ in range(len(ready)):
+ if not ready:
+ break
+ handle = ready.popleft()
+ if not handle._cancelled:
+ # preempt the current task so that that checks in
+ # Task.__step do not raise
+ curr_task = curr_tasks.pop(self, None)
+
+ try:
+ handle._run()
+ finally:
+ # restore the current task
+ if curr_task is not None:
+ curr_tasks[self] = curr_task
+
+ handle = None
+
+ @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
+
+ @contextmanager
+ def manage_asyncgens(self):
+ if not hasattr(sys, 'get_asyncgen_hooks'):
+ # Python version is too old.
+ return
+ old_agen_hooks = sys.get_asyncgen_hooks()
+ try:
+ self._set_coroutine_origin_tracking(self._debug)
+ if self._asyncgens is not None:
+ sys.set_asyncgen_hooks(
+ firstiter=self._asyncgen_firstiter_hook,
+ finalizer=self._asyncgen_finalizer_hook)
+ yield
+ finally:
+ self._set_coroutine_origin_tracking(False)
+ if self._asyncgens is not None:
+ sys.set_asyncgen_hooks(*old_agen_hooks)
+
+ 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))
+ cls = loop.__class__
+ cls.run_forever = run_forever
+ cls.run_until_complete = run_until_complete
+ cls._run_once = _run_once
+ cls._check_running = _check_running
+ cls._check_runnung = _check_running # typo in Python 3.7 source
+ cls._num_runs_pending = 1 if loop.is_running() else 0
+ cls._is_proactorloop = (
+ os.name == 'nt' and issubclass(cls, asyncio.ProactorEventLoop))
+ if sys.version_info < (3, 7, 0):
+ cls._set_coroutine_origin_tracking = cls._set_coroutine_wrapper
+ curr_tasks = asyncio.tasks._current_tasks \
+ if sys.version_info >= (3, 7, 0) else asyncio.Task._current_tasks
+ cls._nest_patched = True
+
+
+def _patch_tornado():
+ """
+ If tornado is imported before nest_asyncio, make tornado aware of
+ the pure-Python asyncio Future.
+ """
+ if 'tornado' in sys.modules:
+ import tornado.concurrent as tc # type: ignore
+ tc.Future = asyncio.Future
+ if asyncio.Future not in tc.FUTURES:
+ tc.FUTURES += (asyncio.Future,)