From e323e808696baeebc8d0c2aac244ccd6ef2df40f Mon Sep 17 00:00:00 2001 From: Austin Raney Date: Tue, 24 Aug 2021 14:58:13 -0400 Subject: [PATCH 1/4] fix #99. RuntimeError: This event loop is already running issue relevant for jupyter/colab users. --- .../hydrotools/_restclient/async_helpers.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/python/_restclient/src/hydrotools/_restclient/async_helpers.py b/python/_restclient/src/hydrotools/_restclient/async_helpers.py index 288c6e45..91f634b9 100644 --- a/python/_restclient/src/hydrotools/_restclient/async_helpers.py +++ b/python/_restclient/src/hydrotools/_restclient/async_helpers.py @@ -19,7 +19,24 @@ def __init__( def _add_to_loop(self, coro: Coroutine): """ Add coro to event loop via run_until_complete """ - return self._loop.run_until_complete(coro) + try: + return self._loop.run_until_complete(coro) + + except RuntimeError as e: + try: + # `RuntimeError: This event loop is already running` thrown by jupyter notebook + # See hydrotools #99 for context and notebook #3397 for detail + import nest_asyncio + + nest_asyncio.apply() + + return self._loop.run_until_complete(coro) + except ModuleNotFoundError: + error_message = ( + "nest_asycnio package not found. Install using `pip install nest_asycnio`.\n" + "See https://github.com/NOAA-OWP/hydrotools/issues/99 for more detail." + ) + raise ModuleNotFoundError(error_message) from e def _wrap_func_in_coro(self, func: Callable, *args, **kwargs): """ Create partial func; wrap and call partial in coro; return coro """ From 01f303acc90ee233c7e7d6fb66f67c2374b0f974 Mon Sep 17 00:00:00 2001 From: Austin Raney Date: Tue, 24 Aug 2021 14:58:39 -0400 Subject: [PATCH 2/4] if session is never to be instantiated, do not try to close it --- python/_restclient/src/hydrotools/_restclient/_restclient.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/_restclient/src/hydrotools/_restclient/_restclient.py b/python/_restclient/src/hydrotools/_restclient/_restclient.py index 02941f83..36cfa724 100644 --- a/python/_restclient/src/hydrotools/_restclient/_restclient.py +++ b/python/_restclient/src/hydrotools/_restclient/_restclient.py @@ -288,6 +288,11 @@ def headers(self) -> dict: def close(self) -> None: """ Release aiohttp.ClientSession """ + # Session never instantiated, thus cannot be closed + session = getattr(self, "_session", None) + if session is None: + return + if not self._session.closed: if not self._loop.is_closed(): self._add_to_loop(self._session.close()) From 858787ee8bcba0c3e895773730acca22970e9786 Mon Sep 17 00:00:00 2001 From: Austin Raney Date: Tue, 24 Aug 2021 14:59:06 -0400 Subject: [PATCH 3/4] unittest to verify RestClient raises a ModuleNotFoundError. Case when loop is running and nest_asyncio not installed --- python/_restclient/tests/test_restclient.py | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/python/_restclient/tests/test_restclient.py b/python/_restclient/tests/test_restclient.py index 64657349..e0a90696 100644 --- a/python/_restclient/tests/test_restclient.py +++ b/python/_restclient/tests/test_restclient.py @@ -150,3 +150,37 @@ def test_build_url(loop): assert client.build_url(base_url) == base_url assert client.build_url(base_url, query_params) == f"{base_url}?key=value" + + +class ModuleFoundError(Exception): + ... + + +def test_restclient_nest_asyncio_ModuleNotFoundError(loop): + """Test for #99. Ensure ModuleNotFoundError raised if `nest_asyncio` not installed""" + import asyncio + import warnings + + # verify `nest_asyncio` is not installed + try: + import nest_asyncio + + error_message = "nest_asyncio installed. Cannot complete test." + raise ModuleFoundError(error_message) + except ModuleNotFoundError: + # this should occur, so continue + pass + + async def test(): + await asyncio.sleep(0.01) + + with warnings.catch_warnings(): + # ignore coroutine not awaited warning for output sake. + # This is not the purpose of this test + warnings.simplefilter("ignore", category=RuntimeWarning) + with pytest.raises(ModuleNotFoundError): + # implicitly verify that `nest_asyncio` is not installed + # this test will need to change if `nest_asyncio` becomes a requirement + RestClient(enable_cache=False) + + loop.run_until_complete(test()) From 8226f2172abaa1671c06be8dd645bf96687b65a1 Mon Sep 17 00:00:00 2001 From: Austin Raney Date: Tue, 24 Aug 2021 14:59:24 -0400 Subject: [PATCH 4/4] bump _restclient patch version to 3.0.4 --- python/_restclient/setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/_restclient/setup.cfg b/python/_restclient/setup.cfg index 311155ea..7583b141 100644 --- a/python/_restclient/setup.cfg +++ b/python/_restclient/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = hydrotools._restclient -version = 3.0.3 +version = 3.0.4 author = Austin Raney author_email = aaraney@protonmail.com description = General REST api client with built in request caching and retries.