##// END OF EJS Templates
Swallow potential exceptions from showtraceback()...
Swallow potential exceptions from showtraceback() The nbgrader project is aware of a form of cheating where students disrupt `InteractiveShell.showtraceback` in hopes of hiding exceptions to avoid losing points. They have implemented a solution to prevent this cheating from working on the client side, and have some tests to demonstrate this technique: https://github.com/jupyter/nbgrader/blob/main/nbgrader/tests/apps/files/submitted-cheat-attempt.ipynb https://github.com/jupyter/nbgrader/blob/main/nbgrader/tests/apps/files/submitted-cheat-attempt-alternative.ipynb In essence, these attacks import the interactive shell and erase the traceback handler so that their failing tests won't report failures. import IPython.core.interactiveshell IPython.core.interactiveshell.InteractiveShell.showtraceback = None The problem is that this causes an exception inside the kernel, leading to a stalled execution. The kernel has stopped working, but the client continues to wait for messages. So far, nbgrader's solution to this is to require a timeout value so the client can eventually decide it is done. This prevents allowing a value of `None` for `Execute.timeout` because this would cause a test case to infinitely hang. This commit addresses the problem by making `InteractiveShell._run_cell` a little more protective around it's call to `showtraceback()`. There is already a try/except block around running the cell. This commit adds a finally clause so that the method will _always_ return an `ExecutionResult`, even if a new exception is thrown within the except clause. For the record, the exception thrown is: TypeError: 'NoneType' object is not callable Accepting this change will allow nbgrader to update `nbgrader.preprocessors.Execute` to support a type of `Integer(allow_none=True)` as the parent `NotebookClient` intended. Discussion about this is ongoing in jupyter/nbgrader#1690.

File last commit:

r27843:667f3cbe
r28094:fd34cf5f
Show More
asyncio.py
62 lines | 1.8 KiB | text/x-python | PythonLexer
"""
Inputhook for running the original asyncio event loop while we're waiting for
input.
By default, in IPython, we run the prompt with a different asyncio event loop,
because otherwise we risk that people are freezing the prompt by scheduling bad
coroutines. E.g., a coroutine that does a while/true and never yield back
control to the loop. We can't cancel that.
However, sometimes we want the asyncio loop to keep running while waiting for
a prompt.
The following example will print the numbers from 1 to 10 above the prompt,
while we are waiting for input. (This works also because we use
prompt_toolkit`s `patch_stdout`)::
In [1]: import asyncio
In [2]: %gui asyncio
In [3]: async def f():
...: for i in range(10):
...: await asyncio.sleep(1)
...: print(i)
In [4]: asyncio.ensure_future(f())
"""
from prompt_toolkit import __version__ as ptk_version
from IPython.core.async_helpers import get_asyncio_loop
PTK3 = ptk_version.startswith("3.")
def inputhook(context):
"""
Inputhook for asyncio event loop integration.
"""
# For prompt_toolkit 3.0, this input hook literally doesn't do anything.
# The event loop integration here is implemented in `interactiveshell.py`
# by running the prompt itself in the current asyncio loop. The main reason
# for this is that nesting asyncio event loops is unreliable.
if PTK3:
return
# For prompt_toolkit 2.0, we can run the current asyncio event loop,
# because prompt_toolkit 2.0 uses a different event loop internally.
# get the persistent asyncio event loop
loop = get_asyncio_loop()
def stop():
loop.stop()
fileno = context.fileno()
loop.add_reader(fileno, stop)
try:
loop.run_forever()
finally:
loop.remove_reader(fileno)