Skip to content

Commit 751c7eb

Browse files
committed
Fix asyncio error when opening notebooks
This is a fix for #6164 `nest_asyncio` must be applied before any async tasks have been created otherwise there could be tasks queued that are unpatched, and thus do not respect nested loops. An example of an unpatched task can be seen in the original issue: ``` <Task pending coro=<HTTP1ServerConnection._server_request_loop() running at /apps/python3/lib/python3.7/site-packages/tornado/http1connection.py:823> ``` which originates from Tornado. A similar issue was reported in `nest-asyncio`: erdewit/nest_asyncio#22 where the solution is to call `apply` on import so that unpatched tasks do not get created.
1 parent eb3a1c2 commit 751c7eb

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

notebook/notebookapp.py

+27
Original file line numberDiff line numberDiff line change
@@ -2092,7 +2092,34 @@ def _init_asyncio_patch(self):
20922092
20932093
FIXME: if/when tornado supports the defaults in asyncio,
20942094
remove and bump tornado requirement for py38
2095+
2096+
With the introduction of the async kernel, the existing sync kernel
2097+
requires the use of nested loops in order to run code synchronously.
2098+
This is done in `jupyter_client` using the helper util `run_sync`:
2099+
2100+
ref: https://github.com/jupyter/jupyter_client/blob/f453b51eeeff9e905c583b7da3905c0e35cfbdf0/jupyter_client/utils.py#L11
2101+
2102+
which creates a new event loop and relies on `nest_asyncio` patching
2103+
to allow nested loops. This requires that *all* potential tasks are
2104+
patched before executing. When only some tasks are patched it leads to
2105+
the following issue:
2106+
2107+
ref: https://github.com/jupyter/notebook/issues/6164
2108+
2109+
So we must call `nest_asyncio.apply()` method as early as possible. It
2110+
is preferable to do this in the consuming application rather than the
2111+
`jupyter_client` as it is a global patch and would impact all consumers
2112+
rather than just the ones that rely on synchronous kernel behavior.
20952113
"""
2114+
import nest_asyncio
2115+
2116+
try:
2117+
nest_asyncio.apply()
2118+
except RuntimeError:
2119+
# nest_asyncio requires a running loop in order to patch.
2120+
# In tests the loop may not have been created yet.
2121+
pass
2122+
20962123
if sys.platform.startswith("win") and sys.version_info >= (3, 8):
20972124
import asyncio
20982125
try:

notebook/tests/launchnotebook.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,16 @@ def start_thread():
167167
token=cls.token,
168168
**bind_args
169169
)
170-
if 'asyncio' in sys.modules:
171-
app._init_asyncio_patch()
172-
import asyncio
173-
asyncio.set_event_loop(asyncio.new_event_loop())
170+
if "asyncio" in sys.modules:
171+
app._init_asyncio_patch()
172+
import asyncio
173+
174+
asyncio.set_event_loop(asyncio.new_event_loop())
175+
# Patch the current loop in order to match production
176+
# behavior
177+
import nest_asyncio
178+
179+
nest_asyncio.apply()
174180
# don't register signal handler during tests
175181
app.init_signal = lambda : None
176182
# clear log handlers and propagate to root for nose to capture it

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
'jupyter_client>=5.3.4',
122122
'nbformat',
123123
'nbconvert',
124+
'nest-asyncio>=1.5',
124125
'ipykernel', # bless IPython kernel for now
125126
'Send2Trash>=1.8.0',
126127
'terminado>=0.8.3',

0 commit comments

Comments
 (0)