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.