调试Python时使用pdb,出现BdbQuit错误

62

最近我在将pdb调试器添加到我的Python 2.7.10代码中时,遇到了以下消息:

Traceback (most recent call last):
  File "/Users/isaachess/Programming/vivint/Platform/MessageProcessing/vivint_cloud/queues/connectors/amqplib_connector.py", line 191, in acking_callback
    callback(message.body)
  File "/Users/isaachess/Programming/vivint/Platform/MessageProcessing/vivint_cloud/queues/consumable_message_queue.py", line 32, in deserialized_callback
    self._callback_method(msg)
  File "/Users/isaachess/Programming/vivint/Platform/BusinessLogic/businesslogic/util/statsd_util.py", line 95, in _time_func
    retVal = f(*args, **kwargs)
  File "/Users/isaachess/Programming/vivint/Platform/MessageProcessing/vivint_cloud/net/router.py", line 226, in handle
    try:
  File "/Users/isaachess/Programming/vivint/Platform/MessageProcessing/vivint_cloud/net/router.py", line 226, in handle
    try:
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py", line 49, in trace_dispatch
    return self.dispatch_line(frame)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py", line 68, in dispatch_line
    if self.quitting: raise BdbQuit
BdbQuit

在代码中插入以下行后:

import pdb; pdb.set_trace()

我无法弄清楚为什么会发生这种情况。我已经阅读了有关Bdb和Bdbquit的内容,但无法弄清楚为什么我的代码会出现这种情况。是否有人可以给我一些关于通常情况下发生这种情况的提示?我真的希望能再次使调试器正常工作。


4
你是如何运行你的进程的?我猜想你的进程可能没有关联到终端之类的东西。这是一个子进程还是什么样的进程? - shx2
@shx2,subprocess?使用Luigi可能会导致这种情况吗? - toto_tico
我遇到了相同的问题。真希望它能得到解决。 - Daming Lu
11个回答

26

在我的生产代码中留下了import pdbpdb.set_trace(),导致发生了这种情况。当执行pdb.set_trace()时,Python一直等待我的输入来告诉它是continue还是step into等等...因为Python代码由Web服务器调用,我不在场无法按c键继续。经过一段时间(不确定多长时间),最终引发了BdbQuit异常。

我没有设置任何内容来捕获该异常,因此它在我的Web服务器上引发了500错误。

花了我一段时间才意识到我的调试代码在守护进程/后台中运行导致了这个问题。感觉很傻。


2
更新了我的回答,针对那些给我点踩的人。如果你给我点踩,请重新阅读我的回答,并留下解释为什么这不是回答问题的方法。 - teewuane
那你当时到底是怎么做到的呢? - Abhishek Rai
@AbhishekRai 你是在尝试在生产环境中运行PDB吗?我认为你需要做的不是在生产环境中运行它,并从你的代码中删除pdf.set_trace()。 - teewuane
1
还是不明白...那我该如何调试它呢? - Abhishek Rai

18
如果您从(pdb)提示符继续执行并允许您的代码正常完成,我不会期望看到像您指示的那样的回溯输出。但是,如果您使用quit命令或^D(EOF)退出pdb,则会出现类似于那样的回溯,因为没有任何东西可以捕获当调试器退出时引发的BdbQuit异常。在bdb.py中,set_quit方法将self.quitting设置为True(以及在各种运行方法中的finally子句)。当dispatch方法由trace_dispatch调用时,如果self.quittingTrue,则会引发BdbQuit,而对于BdbQuit的典型except:子句是一个简单的pass语句;pdbgdb继承了所有这些。

简而言之,在调试器交互结束时,使用异常处理来禁用调试器使用的系统跟踪函数。

避免完全出现该回溯的一种方法是以不同的方式使用pdb。而不是从您的代码中调用pdb.set_trace()(并且根本不处理BdbQuit),您可以在pdb内部调用您的代码(而不是相反),此时BdbQuit异常将按照pdb的意图处理。这还将使您能够选择断点位置,而无需修改您的代码(使用pdbbreak命令)。或者您可以混合两种方法;在pdb下运行您的代码,包括pdb.set_trace()调用,那些调用将是断点,您只能通过修改代码来删除它们。

您可以使用pdb命令以您的脚本调用作为其命令行参数来在pdb中调用您的代码,或使用python -m pdb


1
如果您能够指定BdbQuit的可能原因,那将非常好,因为在某些脚本中pdb不会引发它。 - Alex
3
这不是完整的答案,pdb 存在许多其他限制,例如它无法在多进程池中工作等。您未提及这些限制。 - Ishan Srivastava
即使在Python 3.7中使用“python -m pdb”运行仍然会遇到此问题。 - Noein
感谢您的回答!这实际上是99%来到这里的人最有可能出现的问题。在我的情况下,我正在通过STDIN将输入传输到Python进程。这会导致pdb调试器立即读取EOF,因此会出现BadQuit - Malcolm

17

可能的原因之一是您正在后台运行Python脚本。当进程在后台运行时,您无法通过终端向进程发送输入,因此pdb控制台无法工作。 最终它将引发BdbQuit错误。


6
除了Eirik Fuller的回答外,我想补充一点:在运行于不同进程中的程序中,您不能使用进行调试。对于调试问题,您可以查看以下答案:https://dev59.com/1m445IYBdhLWcg3wwcug#23654936,但它似乎非常粗略,或者您可以使您的程序在单个线程中运行。请参阅文档:https://docs.python.org/3/library/concurrent.futures.html。对于多处理问题,您可能需要查看以下内容:https://www.reddit.com/r/learnpython/comments/46x9sm/why_is_pdbset_trace_crashing_whenever_it_is_in_an/ 无论如何,您提出的问题缺乏重要的上下文信息,请添加更多细节到您的问题中。

3

您可以使用命令docker-compose run --rm --service-ports {YOUR_CONTAINER}。 添加后:

def your_f():
    **import pdb
    pdb.set_trace()**
    result = your_logic
    return result

例子: 在这里输入图片描述


谢谢!但是我使用了Compose服务名称而不是容器名称,并且没有使用“--service-ports”参数。 - ruslan_krivoshein

2

当我将数据传输到我的脚本时,我遇到了这个问题。似乎 pdb 不想保持管道打开状态,因此会抛出 BdbQuit。我通过将我的 stdin 数据保存到临时文件中,然后从 Python 中读取该临时文件来解决了这个问题。

之前的代码

$ pbpaste | script.py
Traceback (most recent call last):
  File "/Users/admin/Code/script.py", line 78, in <module>
    process(args)
  ... blah blah ...
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/bdb.py", line 88, in trace_dispatch
    return self.dispatch_line(frame)
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/bdb.py", line 113, in dispatch_line
    if self.quitting: raise BdbQuit
bdb.BdbQuit

之后

$ pbpaste > temp.txt
$ python3 script.py test.txt 
> /Users/admin/Code/script.py(49)f()
-> hello = "world"
(Pdb) 

1
我们需要为运行Django的docker服务启用shell输入。如果您正在使用docker compose,请在您的docker-compose文件中添加:stdin_open: true
version: '3'

services:
  ...
  django_app:
    build: .
    ports:
      - '8000:8000'
    stdin_open: true

1

对于在Django测试中遇到此问题的用户,可能是由于将--parallel标志传递给测试命令所致。正如之前的回复所指出的那样,这是由于多进程引起的。尝试删除该标志,看看是否解决了问题,对我而言有效。


0
在这个SO答案中找到了最简单的解决方案在这里
简而言之,将sys.stdin = open(0)放在pdb.set_trace()之前。
然而请注意,如果你在主进程之前使用set_trace并且与其他进程一起进入断点,那么会产生与输入/标准输入相关的竞争条件,即一部分输入将发送到一个进程,另一部分输入将发送到另一个进程。 因此,在主进程中不要在到达其他断点之前进行步进或下一步操作。

0
我在编程方面更喜欢使用 pdbpp,它是 pdb 的替代品,即它本身不需要任何其他插件、配置或选项。它支持自动完成,这正是我在使用 ipdb 时所追求的。

您可以使用 pip install pdbpp 进行安装。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接