出现异常时启动 IPython shell

发布于 2024-10-03 17:22:05 字数 1158 浏览 11 评论 0原文

当我的程序运行引发异常的行时,有没有办法启动 IPython shell 或提示?

我最感兴趣的是引发异常的上下文、变量和范围(和子范围)。就像 Visual Studio 的调试一样,当抛出异常但没有被任何人捕获时,Visual Studio 将停止并为我提供调用堆栈和每个级别上存在的变量。

您认为有没有办法使用 IPython 获得类似的东西?

编辑:启动IPython时的-pdb选项似乎没有达到我想要的效果(或者也许我不知道如何正确使用它,这是完全可能的) 。我运行以下脚本:

def func():
    z = 2
    g = 'b'
    raise NameError("This error will not be caught, but IPython still"
                    "won't summon pdb, and I won't be able to consult"
                    "the z or g variables.")

x = 1
y = 'a'

func()

使用命令 :

ipython -pdb exceptionTest.py

在引发错误时停止执行,但会显示 IPython 提示,在其中我可以访问脚本的全局变量,但不能访问函数 func 的局部变量。 pdb 仅当我直接在 ipython 中键入导致错误的命令时才被调用,即 raise NameError("This, sent from the IPython Prompt, will tr​​igger pdb.")

我不一定需要使用 pdb,我只是想访问 func 内的变量。

编辑2:已经有一段时间了,IPython的-pdb选项现在可以按照我想要的方式工作了。这意味着当我引发异常时,我可以返回到 func 的范围并读取其变量 z 和 g ,没有任何问题。即使不设置 -pdb 选项,也可以在交互模式下运行 IPython,然后在程序因错误退出后调用神奇函数 %debug ——这也会让你失望进入交互式 ipdb 提示符,所有范围均可访问。

Is there a way to launch an IPython shell or prompt when my program runs a line that raises an exception?

I'm mostly interested in the context, variables, in the scope (and subscopes) where the exception was raised. Something like Visual Studio's debugging, when an exception is thrown but not caught by anyone, Visual Studio will halt and give me the call stack and the variables present at every level.

Do you think there's a way to get something similar using IPython?

EDIT: The -pdb option when launching IPython doesn't seem do what I want (or maybe I don't know how to use it properly, which is entirely possible). I run the following script :

def func():
    z = 2
    g = 'b'
    raise NameError("This error will not be caught, but IPython still"
                    "won't summon pdb, and I won't be able to consult"
                    "the z or g variables.")

x = 1
y = 'a'

func()

Using the command :

ipython -pdb exceptionTest.py

Which stops execution when the error is raised, but brings me an IPython prompt where I have access to the global variables of the script, but not the local variables of function func. pdb is only invoked when I directly type a command in ipython that causes an error, i.e. raise NameError("This, sent from the IPython prompt, will trigger pdb.").

I don't necessarily need to use pdb, I'd just like to have access to the variables inside func.

EDIT 2: It has been a while, IPython's -pdb option is now working just as I want it to. That means when I raise an exception I can go back in the scope of func and read its variables z and g without any problem. Even without setting the -pdb option, one can run IPython in interactive mode then call the magic function %debug after the program has exit with error -- that will also drop you into an interactive ipdb prompt with all scopes accessibles.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

幸福还没到 2024-10-10 17:22:05

IPython v0.13:

import sys
from IPython.core import ultratb
sys.excepthook = ultratb.FormattedTB(mode='Verbose',
     color_scheme='Linux', call_pdb=1)

Update for IPython v0.13:

import sys
from IPython.core import ultratb
sys.excepthook = ultratb.FormattedTB(mode='Verbose',
     color_scheme='Linux', call_pdb=1)
执手闯天涯 2024-10-10 17:22:05

做法:

ipython --pdb -c "%run exceptionTest.py"

在 IPython 初始化后启动脚本,然后进入正常的 IPython+pdb 环境。

Doing:

ipython --pdb -c "%run exceptionTest.py"

kicks off the script after IPython initialises and you get dropped into the normal IPython+pdb environment.

树深时见影 2024-10-10 17:22:05

你可以试试这个:

from ipdb import launch_ipdb_on_exception

def main():
    with launch_ipdb_on_exception():
        # The rest of the code goes here.
        [...]

You can try this:

from ipdb import launch_ipdb_on_exception

def main():
    with launch_ipdb_on_exception():
        # The rest of the code goes here.
        [...]
情泪▽动烟 2024-10-10 17:22:05

ipdb 将 IPython 功能集成到 pdb 中。在发生未经处理的异常后,我使用以下代码将我的应用程序放入 IPython 调试器中。

import sys, ipdb, traceback

def info(type, value, tb):
    traceback.print_exception(type, value, tb)
    ipdb.pm()

sys.excepthook = info

ipdb integrates IPython features into pdb. I use the following code to throw my apps into the IPython debugger after an unhanded exception.

import sys, ipdb, traceback

def info(type, value, tb):
    traceback.print_exception(type, value, tb)
    ipdb.pm()

sys.excepthook = info
不及他 2024-10-10 17:22:05

@snapshoe 的答案不适用于较新版本的 IPython。

然而,这确实:

import sys 
from IPython import embed

def excepthook(type, value, traceback):
    embed()

sys.excepthook = excepthook

@snapshoe's answer does not work on newer versions of IPython.

This does however:

import sys 
from IPython import embed

def excepthook(type, value, traceback):
    embed()

sys.excepthook = excepthook
剩余の解释 2024-10-10 17:22:05

@Adam 的工作就像一个魅力,除了 IPython 加载有点慢(在我的机器上 800 毫秒)。这里我有一个技巧可以让负载变得懒惰。

class ExceptionHook:
    instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            from IPython.core import ultratb
            self.instance = ultratb.FormattedTB(mode='Verbose',
                 color_scheme='Linux', call_pdb=1)
        return self.instance(*args, **kwargs)
sys.excepthook = ExceptionHook()

现在我们不需要在一开始就等待。只有当程序崩溃时才会导致IPython被导入。

@Adam's works like a charm except that IPython loads a bit slowly(800ms on my machine). Here I have a trick to make the load lazy.

class ExceptionHook:
    instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            from IPython.core import ultratb
            self.instance = ultratb.FormattedTB(mode='Verbose',
                 color_scheme='Linux', call_pdb=1)
        return self.instance(*args, **kwargs)
sys.excepthook = ExceptionHook()

Now we don't need to wait at the very beginning. Only when the program crashes will cause IPython to be imported.

得不到的就毁灭 2024-10-10 17:22:05

您可以执行类似以下操作:

import sys
from IPython.Shell import IPShellEmbed
ipshell = IPShellEmbed()

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

sys.excepthook = excepthook

请参阅 sys.excepthook 和 < a href="http://ipython.readthedocs.io/en/stable/interactive/reference.html#embedding" rel="nofollow noreferrer">嵌入 IPython。

You can do something like the following:

import sys
from IPython.Shell import IPShellEmbed
ipshell = IPShellEmbed()

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

sys.excepthook = excepthook

See sys.excepthook and Embedding IPython.

迷离° 2024-10-10 17:22:05

这个 手册页 说 iPython 有 --[ no]pdb 选项在命令行中传递以启动 iPython 以处理未捕获的异常。您在寻找更多吗?

编辑:
python -m pdb pythonscript.py 可以启动pdb。但不确定 iPython 是否有类似的情况。如果您正在寻找程序异常退出的堆栈跟踪和一般事后分析,这应该可行。

This man page says iPython has --[no]pdb option to be passed at command line to start iPython for uncaught exceptions. Are you looking for more?

EDIT:
python -m pdb pythonscript.py can launch pdb. Not sure about similar thing with iPython though. If you are looking for the stack trace and general post-mortem of the abnormal exit of program, this should work.

海夕 2024-10-10 17:22:05

如果您想要获取回溯并使用异常点处的环境打开 IPython shell:

def exceptHook(*args):
    '''A routine to be called when an exception occurs. It prints the traceback
    with fancy formatting and then calls an IPython shell with the environment
    of the exception location.
    '''
    from IPython.core import ultratb
    ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
    from IPython.terminal.embed import InteractiveShellEmbed
    import inspect
    frame = inspect.getinnerframes(args[2])[-1][0]
    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)
    savehook = sys.excepthook # save the exception hook
    InteractiveShellEmbed()(msg,local_ns=frame.f_locals,global_ns=frame.f_globals)
    sys.excepthook = savehook # reset IPython's change to the exception hook

import sys
sys.excepthook = exceptHook

请注意,有必要从回溯 (arg[2]) 引用的最后一帧中提取命名空间信息

(12/ 23) 上述代码需要更改以匹配最新版本的 IPython。下面是我现在在 exceptHook 函数中使用的内容。我已经在 IPython 8.x 和 7.x 上尝试过,它可能适用于更旧的版本,但尚未经过测试。

try: 
    from IPython.terminal.embed import InteractiveShellEmbed
    import IPython.core
    if sys.platform.startswith('win'):
        IPython.core.ultratb.FormattedTB(
           call_pdb=False,color_scheme='NoColor')(*args)
    else:
        IPython.core.ultratb.FormattedTB(
           call_pdb=False,color_scheme='LightBG')(*args)
    from IPython.core import getipython
    if getipython.get_ipython() is None:
        ipshell = InteractiveShellEmbed.instance()
    else:
        ipshell = InteractiveShellEmbed()
except ImportError:
    print ('IPython not found or really old')
    return

import inspect
frame = inspect.getinnerframes(args[2])[-1][0]
msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
savehook = sys.excepthook # save the exception hook
try:
    ipshell(msg,local_ns=frame.f_locals,global_ns=frame.f_globals) # newest (IPython >= 8)
except DeprecationWarning: # IPython <=7
    try: # IPython >=5
        class c(object): pass
        pseudomod = c() # create something that acts like a module
        pseudomod.__dict__ = frame.f_locals
        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
    except: # 'IPython <5
        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
sys.excepthook = savehook # reset IPython's change to the exception hook

If you want to both get the traceback and open a IPython shell with the environment at the point of the exception:

def exceptHook(*args):
    '''A routine to be called when an exception occurs. It prints the traceback
    with fancy formatting and then calls an IPython shell with the environment
    of the exception location.
    '''
    from IPython.core import ultratb
    ultratb.FormattedTB(call_pdb=False,color_scheme='LightBG')(*args)
    from IPython.terminal.embed import InteractiveShellEmbed
    import inspect
    frame = inspect.getinnerframes(args[2])[-1][0]
    msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)
    savehook = sys.excepthook # save the exception hook
    InteractiveShellEmbed()(msg,local_ns=frame.f_locals,global_ns=frame.f_globals)
    sys.excepthook = savehook # reset IPython's change to the exception hook

import sys
sys.excepthook = exceptHook

Note that it is necessary to pull than namespace information from the last frame referenced by the traceback (arg[2])

(12/23) The above code needs to change to match the latest versions of IPython. Below is what I am using now inside my exceptHook function. I have tried it on IPython 8.x and 7.x and it might work with even older versions, but has not been tested.

try: 
    from IPython.terminal.embed import InteractiveShellEmbed
    import IPython.core
    if sys.platform.startswith('win'):
        IPython.core.ultratb.FormattedTB(
           call_pdb=False,color_scheme='NoColor')(*args)
    else:
        IPython.core.ultratb.FormattedTB(
           call_pdb=False,color_scheme='LightBG')(*args)
    from IPython.core import getipython
    if getipython.get_ipython() is None:
        ipshell = InteractiveShellEmbed.instance()
    else:
        ipshell = InteractiveShellEmbed()
except ImportError:
    print ('IPython not found or really old')
    return

import inspect
frame = inspect.getinnerframes(args[2])[-1][0]
msg   = 'Entering IPython console at {0.f_code.co_filename} at line {0.f_lineno}\n'.format(frame)
savehook = sys.excepthook # save the exception hook
try:
    ipshell(msg,local_ns=frame.f_locals,global_ns=frame.f_globals) # newest (IPython >= 8)
except DeprecationWarning: # IPython <=7
    try: # IPython >=5
        class c(object): pass
        pseudomod = c() # create something that acts like a module
        pseudomod.__dict__ = frame.f_locals
        InteractiveShellEmbed(banner1=msg)(module=pseudomod,global_ns=frame.f_globals)
    except: # 'IPython <5
        InteractiveShellEmbed(banner1=msg)(local_ns=frame.f_locals,global_ns=frame.f_globals)
sys.excepthook = savehook # reset IPython's change to the exception hook
埖埖迣鎅 2024-10-10 17:22:05

你真的想在每个异常点打开一个 pdb 会话吗? (因为我认为从 ipython 打开的 pdb 会话与在普通 shell 中打开的 pdb 会话相同)。如果是这样的话,技巧如下:
http://code.activestate.com/食谱/65287-出现异常时自动启动调试器/

Do you actually want to open a pdb session at every exception point? (as I think a pdb session opened from ipython is the same as the one open in the normal shell). If that's the case, here's the trick:
http://code.activestate.com/recipes/65287-automatically-start-the-debugger-on-an-exception/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文