处理笔记本异常的 Jupyter 魔法
Jupyter magic to handle notebook exceptions
我在我的 Jupyter Notebook 中进行了一些长期的 运行 实验。因为我不知道他们什么时候完成,所以我在笔记本的最后一个单元格添加了一个电子邮件功能,所以当笔记本完成时我会自动收到一封电子邮件。
但是当其中一个单元格出现随机异常时,整个笔记本停止执行,我再也没有收到任何电子邮件。 所以我想知道是否有一些神奇的函数可以在异常/内核停止的情况下执行函数。
喜欢
def handle_exception(stacktrace):
send_mail_to_myself(stacktrace)
%%in_case_of_notebook_exception handle_exception # <--- this is what I'm looking for
另一种选择是将每个单元封装在 try-catch 中,对吗?但这太乏味了。
提前感谢您的任何建议。
我不认为有一种开箱即用的方法可以做到这一点,而不是在您的单元格中使用 try..except
语句。 AFAIK a 4 years old issue 提到了这一点,但仍处于开放状态。
但是,runtools extension 可能会起作用。
这样的魔法命令是不存在的,但是你可以自己写。
from IPython.core.magic import register_cell_magic
@register_cell_magic('handle')
def handle(line, cell):
try:
exec(cell)
except Exception as e:
send_mail_to_myself(e)
raise # if you want the full trace-back in the notebook
无法为整个笔记本自动加载魔术命令,您必须在需要此功能的每个单元格中添加它。
%%handle
some_code()
raise ValueError('this exception will be caught by the magic command')
@show0k 对我的问题给出了正确的答案(关于魔术方法)。非常感谢! :)
这个答案激发了我深入挖掘的灵感,我发现了一个 IPython 方法,可以让您为整个笔记本定义一个 自定义异常处理程序。
我是这样工作的:
from IPython.core.ultratb import AutoFormattedTB
# initialize the formatter for making the tracebacks into strings
itb = AutoFormattedTB(mode = 'Plain', tb_offset = 1)
# this function will be called on exceptions in any cell
def custom_exc(shell, etype, evalue, tb, tb_offset=None):
# still show the error within the notebook, don't just swallow it
shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)
# grab the traceback and make it into a list of strings
stb = itb.structured_traceback(etype, evalue, tb)
sstb = itb.stb2text(stb)
print (sstb) # <--- this is the variable with the traceback string
print ("sending mail")
send_mail_to_myself(sstb)
# this registers a custom exception handler for the whole current notebook
get_ipython().set_custom_exc((Exception,), custom_exc)
所以这可以放在任何笔记本顶部的单个单元格中,因此它会在出现问题时进行邮寄。
自我注意事项/TODO:将此片段制作成一个小 python 模块,可以将其导入笔记本并通过 line magic 激活。
不过要小心。该文档包含针对此 set_custom_exc
方法的警告:"WARNING: by putting in your own exception handler into IPython’s main execution loop, you run a very good chance of nasty crashes. This facility should only be used if you really know what you are doing."
为什么 exec
并不总是解决方案
几年后,我在尝试使用 Jupyter magics 处理错误时遇到了类似的问题。但是,我需要变量来保留在实际的 Jupyter notebook 中。
%%try_except print
a = 12
raise ValueError('test')
在此示例中,我希望打印错误(但可以是任何内容,例如开头 post 中的电子邮件),而且 a == 12
在下一个单元格中为真.因此,当您在不同的文件中定义魔术时,建议的方法 exec
不起作用。我找到的解决方案是使用 IPython 功能。
如何解决
from IPython.core.magic import line_magic, cell_magic, line_cell_magic, Magics, magics_class
@magics_class
class CustomMagics(Magics):
@cell_magic
def try_except(self, line, cell):
""" This magic wraps a cell in try_except functionality """
try:
self.shell.ex(cell) # This executes the cell in the current namespace
except Exception as e:
if ip.ev(f'callable({how})'): # check we have a callable handler
self.shell.user_ns['error'] = e # add error to namespace
ip.ev(f'{how}(error)') # call the handler with the error
else:
raise e
# Register
from IPython import get_ipython
ip = get_ipython()
ip.register_magics(CustomMagics)
从笔记本 5.1 开始,您可以使用新标签:raises-exception
这将表明特定单元格中的异常是预期的,jupyter 不会停止执行。
(要设置标签,您必须从主菜单中选择:查看 -> 单元格工具栏 -> 标签)
我在我的 Jupyter Notebook 中进行了一些长期的 运行 实验。因为我不知道他们什么时候完成,所以我在笔记本的最后一个单元格添加了一个电子邮件功能,所以当笔记本完成时我会自动收到一封电子邮件。
但是当其中一个单元格出现随机异常时,整个笔记本停止执行,我再也没有收到任何电子邮件。 所以我想知道是否有一些神奇的函数可以在异常/内核停止的情况下执行函数。
喜欢
def handle_exception(stacktrace):
send_mail_to_myself(stacktrace)
%%in_case_of_notebook_exception handle_exception # <--- this is what I'm looking for
另一种选择是将每个单元封装在 try-catch 中,对吗?但这太乏味了。
提前感谢您的任何建议。
我不认为有一种开箱即用的方法可以做到这一点,而不是在您的单元格中使用 try..except
语句。 AFAIK a 4 years old issue 提到了这一点,但仍处于开放状态。
但是,runtools extension 可能会起作用。
这样的魔法命令是不存在的,但是你可以自己写。
from IPython.core.magic import register_cell_magic
@register_cell_magic('handle')
def handle(line, cell):
try:
exec(cell)
except Exception as e:
send_mail_to_myself(e)
raise # if you want the full trace-back in the notebook
无法为整个笔记本自动加载魔术命令,您必须在需要此功能的每个单元格中添加它。
%%handle
some_code()
raise ValueError('this exception will be caught by the magic command')
@show0k 对我的问题给出了正确的答案(关于魔术方法)。非常感谢! :)
这个答案激发了我深入挖掘的灵感,我发现了一个 IPython 方法,可以让您为整个笔记本定义一个 自定义异常处理程序。
我是这样工作的:
from IPython.core.ultratb import AutoFormattedTB
# initialize the formatter for making the tracebacks into strings
itb = AutoFormattedTB(mode = 'Plain', tb_offset = 1)
# this function will be called on exceptions in any cell
def custom_exc(shell, etype, evalue, tb, tb_offset=None):
# still show the error within the notebook, don't just swallow it
shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)
# grab the traceback and make it into a list of strings
stb = itb.structured_traceback(etype, evalue, tb)
sstb = itb.stb2text(stb)
print (sstb) # <--- this is the variable with the traceback string
print ("sending mail")
send_mail_to_myself(sstb)
# this registers a custom exception handler for the whole current notebook
get_ipython().set_custom_exc((Exception,), custom_exc)
所以这可以放在任何笔记本顶部的单个单元格中,因此它会在出现问题时进行邮寄。
自我注意事项/TODO:将此片段制作成一个小 python 模块,可以将其导入笔记本并通过 line magic 激活。
不过要小心。该文档包含针对此 set_custom_exc
方法的警告:"WARNING: by putting in your own exception handler into IPython’s main execution loop, you run a very good chance of nasty crashes. This facility should only be used if you really know what you are doing."
为什么 exec
并不总是解决方案
几年后,我在尝试使用 Jupyter magics 处理错误时遇到了类似的问题。但是,我需要变量来保留在实际的 Jupyter notebook 中。
%%try_except print
a = 12
raise ValueError('test')
在此示例中,我希望打印错误(但可以是任何内容,例如开头 post 中的电子邮件),而且 a == 12
在下一个单元格中为真.因此,当您在不同的文件中定义魔术时,建议的方法 exec
不起作用。我找到的解决方案是使用 IPython 功能。
如何解决
from IPython.core.magic import line_magic, cell_magic, line_cell_magic, Magics, magics_class
@magics_class
class CustomMagics(Magics):
@cell_magic
def try_except(self, line, cell):
""" This magic wraps a cell in try_except functionality """
try:
self.shell.ex(cell) # This executes the cell in the current namespace
except Exception as e:
if ip.ev(f'callable({how})'): # check we have a callable handler
self.shell.user_ns['error'] = e # add error to namespace
ip.ev(f'{how}(error)') # call the handler with the error
else:
raise e
# Register
from IPython import get_ipython
ip = get_ipython()
ip.register_magics(CustomMagics)
从笔记本 5.1 开始,您可以使用新标签:raises-exception
这将表明特定单元格中的异常是预期的,jupyter 不会停止执行。
(要设置标签,您必须从主菜单中选择:查看 -> 单元格工具栏 -> 标签)