在任何(未捕获的)异常上打开IPython shell

时间:2013-04-01 21:44:59

标签: python debugging ipython

我在Python中定义了以下(嵌入式)shell:

from IPython.config.loader import Config
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = '   .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")
exit_msg = '**Leaving Nested interpreter'

from IPython.frontend.terminal.embed import InteractiveShellEmbed
ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)

我希望我的程序在异常发生的范围内时自动将我放入shell中。

我尝试过:

def excepthook(type, value, traceback):
    ipshell(msg)

sys.excepthook = excepthook

但这似乎不起作用(我只是获得标准的追溯)。此外,理想情况下,最好是:

  1. IPython打印常规追踪
  2. 然后将我放入IPython shell
  3. 如果我上面编写的代码有效,它只会让我进入一个IPython shell,而不是打印回溯。

    更新1:

    我已阅读here,当从IPython运行代码时,IPython负责捕获所有异常,并且可能无法直接覆盖sys.excepthook()。如果是这种情况,我怎样才能让IPython在发生异常的范围内以及打印回溯后执行其他异常挂钩(例如我的ipshell())?

    更新2:

    开发人员列表中似乎有一个讨论这个问题的线程:excepthook-like behavior in ipython。显然有一个函数set_custom_exc可以解决这个问题,但我不确定如何将其插入我的ipshell()

2 个答案:

答案 0 :(得分:1)

我认为几乎不可能让异常一直通过调用堆栈来查明某人是否会最终捕获并处理它,然后返回到它首次引发的范围。当异常弹出时,原始范围消失了。

您最好的选择可能是将您希望shell出现的所有部分包装起来,使用专用的try ... except块处理异常,如下所示:

try: 
   pass # stuff that may raise an exception
except KeyboardInterrupt:
   # some exception you want to handle
   raise 
except SystemExit:
   # another exception you want to handle
   raise 
except: 
   # get a hand on any unhandled exception
   ipshell(traceback.format_exc())

(不确定这是否可以更优雅地实施。我对更好的解决方案也非常感兴趣!)

答案 1 :(得分:1)

在我的ipython shell中定义以下内容似乎可以满足您的需求:

def custom_exc(shell, etype, evalue, tb, tb_offset=None):
    shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)
    ipshell()

get_ipython().set_custom_exc((Exception,), custom_exc)