././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1973257 nest_asyncio-1.6.0/0000755000175000017500000000000014553224514013233 5ustar00ewaldewald././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1963258 nest_asyncio-1.6.0/.github/0000755000175000017500000000000014553224514014573 5ustar00ewaldewald././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1664520394.0 nest_asyncio-1.6.0/.github/FUNDING.yml0000644000175000017500000000005514315510312016376 0ustar00ewaldewaldgithub: erdewit custom: www.paypal.me/erdewit././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1973257 nest_asyncio-1.6.0/.github/workflows/0000755000175000017500000000000014553224514016630 5ustar00ewaldewald././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694944988.0 nest_asyncio-1.6.0/.github/workflows/test.yml0000644000175000017500000000233114501547334020332 0ustar00ewaldewaldname: nest_asyncio on: [ push, pull_request, workflow_dispatch ] env: FORCE_COLOR: 1 jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [ 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12", pypy-3.9 ] exclude: - os: ubuntu-latest python-version: 3.5 - os: ubuntu-latest python-version: 3.6 include: - os: ubuntu-20.04 python-version: 3.5 - os: ubuntu-20.04 python-version: 3.6 steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 mypy . - name: Flake8 static code analysis run: flake8 nest_asyncio.py - name: MyPy static code analysis run: | mypy nest_asyncio.py - name: Testsuite run: | python tests/nest_test.py ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1538170537.0 nest_asyncio-1.6.0/.gitignore0000664000175000017500000000226613353517251015233 0ustar00ewaldewald# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # dotenv .env # virtualenv .venv venv/ ENV/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .vscode .project .pydevproject .settings/ .idea ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585492464.0 nest_asyncio-1.6.0/LICENSE0000664000175000017500000000245213640130760014240 0ustar00ewaldewaldBSD 2-Clause License Copyright (c) 2018-2020, Ewald de Wit All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1580213584.0 nest_asyncio-1.6.0/MANIFEST.in0000664000175000017500000000005513614022520014761 0ustar00ewaldewaldinclude LICENSE recursive-include tests *.py ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1973257 nest_asyncio-1.6.0/PKG-INFO0000644000175000017500000000537414553224514014341 0ustar00ewaldewaldMetadata-Version: 2.1 Name: nest_asyncio Version: 1.6.0 Summary: Patch asyncio to allow nested event loops Home-page: https://github.com/erdewit/nest_asyncio Author: Ewald R. de Wit Author-email: ewald.de.wit@gmail.com License: BSD Keywords: asyncio,nested,eventloop Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Framework :: AsyncIO Requires-Python: >=3.5 Description-Content-Type: text/x-rst License-File: LICENSE |Build| |Status| |PyPiVersion| |License| |Downloads| Introduction ------------ By design asyncio `does not allow `_ its event loop to be nested. This presents a practical problem: When in an environment where the event loop is already running it's impossible to run tasks and wait for the result. Trying to do so will give the error "``RuntimeError: This event loop is already running``". The issue pops up in various environments, such as web servers, GUI applications and in Jupyter notebooks. This module patches asyncio to allow nested use of ``asyncio.run`` and ``loop.run_until_complete``. Installation ------------ .. code-block:: pip3 install nest_asyncio Python 3.5 or higher is required. Usage ----- .. code-block:: python import nest_asyncio nest_asyncio.apply() Optionally the specific loop that needs patching can be given as argument to ``apply``, otherwise the current event loop is used. An event loop can be patched whether it is already running or not. Only event loops from asyncio can be patched; Loops from other projects, such as uvloop or quamash, generally can't be patched. .. |Build| image:: https://github.com/erdewit/nest_asyncio/actions/workflows/test.yml/badge.svg?branche=master :alt: Build :target: https://github.com/erdewit/nest_asyncio/actions .. |PyPiVersion| image:: https://img.shields.io/pypi/v/nest_asyncio.svg :alt: PyPi :target: https://pypi.python.org/pypi/nest_asyncio .. |Status| image:: https://img.shields.io/badge/status-stable-green.svg :alt: .. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg :alt: .. |Downloads| image:: https://static.pepy.tech/badge/nest-asyncio/month :alt: Number of downloads :target: https://pepy.tech/project/nest-asyncio ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1701097652.0 nest_asyncio-1.6.0/README.rst0000644000175000017500000000343314531130264014717 0ustar00ewaldewald|Build| |Status| |PyPiVersion| |License| |Downloads| Introduction ------------ By design asyncio `does not allow `_ its event loop to be nested. This presents a practical problem: When in an environment where the event loop is already running it's impossible to run tasks and wait for the result. Trying to do so will give the error "``RuntimeError: This event loop is already running``". The issue pops up in various environments, such as web servers, GUI applications and in Jupyter notebooks. This module patches asyncio to allow nested use of ``asyncio.run`` and ``loop.run_until_complete``. Installation ------------ .. code-block:: pip3 install nest_asyncio Python 3.5 or higher is required. Usage ----- .. code-block:: python import nest_asyncio nest_asyncio.apply() Optionally the specific loop that needs patching can be given as argument to ``apply``, otherwise the current event loop is used. An event loop can be patched whether it is already running or not. Only event loops from asyncio can be patched; Loops from other projects, such as uvloop or quamash, generally can't be patched. .. |Build| image:: https://github.com/erdewit/nest_asyncio/actions/workflows/test.yml/badge.svg?branche=master :alt: Build :target: https://github.com/erdewit/nest_asyncio/actions .. |PyPiVersion| image:: https://img.shields.io/pypi/v/nest_asyncio.svg :alt: PyPi :target: https://pypi.python.org/pypi/nest_asyncio .. |Status| image:: https://img.shields.io/badge/status-stable-green.svg :alt: .. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg :alt: .. |Downloads| image:: https://static.pepy.tech/badge/nest-asyncio/month :alt: Number of downloads :target: https://pepy.tech/project/nest-asyncio ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1536333200.0 nest_asyncio-1.6.0/dist.sh0000775000175000017500000000016113344512620014530 0ustar00ewaldewaldrm -rf dist build python3 setup.py sdist bdist_wheel python3 -m twine upload dist/* rm -rf dist build *.egg-info ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1973257 nest_asyncio-1.6.0/nest_asyncio.egg-info/0000755000175000017500000000000014553224514017423 5ustar00ewaldewald././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705847116.0 nest_asyncio-1.6.0/nest_asyncio.egg-info/PKG-INFO0000644000175000017500000000537414553224514020531 0ustar00ewaldewaldMetadata-Version: 2.1 Name: nest-asyncio Version: 1.6.0 Summary: Patch asyncio to allow nested event loops Home-page: https://github.com/erdewit/nest_asyncio Author: Ewald R. de Wit Author-email: ewald.de.wit@gmail.com License: BSD Keywords: asyncio,nested,eventloop Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Framework :: AsyncIO Requires-Python: >=3.5 Description-Content-Type: text/x-rst License-File: LICENSE |Build| |Status| |PyPiVersion| |License| |Downloads| Introduction ------------ By design asyncio `does not allow `_ its event loop to be nested. This presents a practical problem: When in an environment where the event loop is already running it's impossible to run tasks and wait for the result. Trying to do so will give the error "``RuntimeError: This event loop is already running``". The issue pops up in various environments, such as web servers, GUI applications and in Jupyter notebooks. This module patches asyncio to allow nested use of ``asyncio.run`` and ``loop.run_until_complete``. Installation ------------ .. code-block:: pip3 install nest_asyncio Python 3.5 or higher is required. Usage ----- .. code-block:: python import nest_asyncio nest_asyncio.apply() Optionally the specific loop that needs patching can be given as argument to ``apply``, otherwise the current event loop is used. An event loop can be patched whether it is already running or not. Only event loops from asyncio can be patched; Loops from other projects, such as uvloop or quamash, generally can't be patched. .. |Build| image:: https://github.com/erdewit/nest_asyncio/actions/workflows/test.yml/badge.svg?branche=master :alt: Build :target: https://github.com/erdewit/nest_asyncio/actions .. |PyPiVersion| image:: https://img.shields.io/pypi/v/nest_asyncio.svg :alt: PyPi :target: https://pypi.python.org/pypi/nest_asyncio .. |Status| image:: https://img.shields.io/badge/status-stable-green.svg :alt: .. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg :alt: .. |Downloads| image:: https://static.pepy.tech/badge/nest-asyncio/month :alt: Number of downloads :target: https://pepy.tech/project/nest-asyncio ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705847116.0 nest_asyncio-1.6.0/nest_asyncio.egg-info/SOURCES.txt0000644000175000017500000000050714553224514021311 0ustar00ewaldewald.gitignore LICENSE MANIFEST.in README.rst dist.sh nest_asyncio.py pyproject.toml setup.cfg setup.py .github/FUNDING.yml .github/workflows/test.yml nest_asyncio.egg-info/PKG-INFO nest_asyncio.egg-info/SOURCES.txt nest_asyncio.egg-info/dependency_links.txt nest_asyncio.egg-info/top_level.txt tests/__init__.py tests/nest_test.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705847116.0 nest_asyncio-1.6.0/nest_asyncio.egg-info/dependency_links.txt0000644000175000017500000000000114553224514023471 0ustar00ewaldewald ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705847116.0 nest_asyncio-1.6.0/nest_asyncio.egg-info/top_level.txt0000644000175000017500000000001514553224514022151 0ustar00ewaldewaldnest_asyncio ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705846229.0 nest_asyncio-1.6.0/nest_asyncio.py0000644000175000017500000001650214553222725016311 0ustar00ewaldewald"""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,) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1594895983.0 nest_asyncio-1.6.0/pyproject.toml0000664000175000017500000000022413704027157016150 0ustar00ewaldewald[build-system] requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4.3"] build-backend = "setuptools.build_meta" [tool.setuptools_scm] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1983256 nest_asyncio-1.6.0/setup.cfg0000644000175000017500000000177014553224514015061 0ustar00ewaldewald[metadata] name = nest_asyncio version = 1.6.0 author = Ewald R. de Wit author_email = ewald.de.wit@gmail.com license = BSD license_files = LICENSE description = Patch asyncio to allow nested event loops keywords = asyncio, nested, eventloop url = https://github.com/erdewit/nest_asyncio long_description = file: README.rst long_description_content_type = text/x-rst classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: BSD License Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3 :: Only Framework :: AsyncIO [options] py_modules = nest_asyncio python_requires = >=3.5 [flake8] ignore = D205,D400,W503 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1594895996.0 nest_asyncio-1.6.0/setup.py0000664000175000017500000000010613704027174014744 0ustar00ewaldewaldfrom setuptools import setup if __name__ == "__main__": setup() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705847116.1973257 nest_asyncio-1.6.0/tests/0000755000175000017500000000000014553224514014375 5ustar00ewaldewald././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1551821325.0 nest_asyncio-1.6.0/tests/__init__.py0000664000175000017500000000000013437565015016502 0ustar00ewaldewald././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648905891.0 nest_asyncio-1.6.0/tests/nest_test.py0000644000175000017500000000563614222047243016764 0ustar00ewaldewaldimport asyncio import sys import unittest import nest_asyncio def exception_handler(loop, context): print('Exception:', context) class NestTest(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() nest_asyncio.apply(self.loop) asyncio.set_event_loop(self.loop) self.loop.set_debug(True) self.loop.set_exception_handler(exception_handler) def tearDown(self): self.assertIsNone(asyncio._get_running_loop()) self.loop.close() del self.loop async def coro(self): await asyncio.sleep(0.01) return 42 def test_nesting(self): async def f1(): result = self.loop.run_until_complete(self.coro()) self.assertEqual(result, await self.coro()) return result async def f2(): result = self.loop.run_until_complete(f1()) self.assertEqual(result, await f1()) return result result = self.loop.run_until_complete(f2()) self.assertEqual(result, 42) def test_ensure_future_with_run_until_complete(self): async def f(): task = asyncio.ensure_future(self.coro()) return self.loop.run_until_complete(task) result = self.loop.run_until_complete(f()) self.assertEqual(result, 42) def test_ensure_future_with_run_until_complete_with_wait(self): async def f(): task = asyncio.ensure_future(self.coro()) done, pending = self.loop.run_until_complete( asyncio.wait([task], return_when=asyncio.ALL_COMPLETED)) task = done.pop() return task.result() result = self.loop.run_until_complete(f()) self.assertEqual(result, 42) def test_timeout(self): async def f1(): await asyncio.sleep(0.1) async def f2(): asyncio.run(asyncio.wait_for(f1(), 0.01)) with self.assertRaises(asyncio.TimeoutError): self.loop.run_until_complete(f2()) def test_two_run_until_completes_in_one_outer_loop(self): async def f1(): self.loop.run_until_complete(asyncio.sleep(0.02)) return 4 async def f2(): self.loop.run_until_complete(asyncio.sleep(0.01)) return 2 result = self.loop.run_until_complete( asyncio.gather(f1(), f2())) self.assertEqual(result, [4, 2]) @unittest.skipIf(sys.version_info < (3, 7, 0), 'No contextvars module') def test_contextvars(self): from contextvars import ContextVar var = ContextVar('var') var.set(0) async def set_val(): var.set(42) async def coro(): await set_val() await asyncio.sleep(0.01) return var.get() result = self.loop.run_until_complete(coro()) self.assertEqual(result, 42) if __name__ == '__main__': unittest.main()