Skip to content

Commit 25ed9b0

Browse files
committed
Make the Debugger a singleton and do not reset the stopframe to None during postmortem.
This fixes inducer#607. Making the Debugger a singleton should be enough to fix inducer#607. HOWEVER, pytest def postmortem() calls .reset() which reset the stopframe. Somehow, this causes the debugger to stop somewhere inside internal debugger source code, instead of in the code the postmortem should be done. So, this also includes an overrid eof the .reset() method and detects when the debugger is already running and does not reset the stopframe. See also inducer#67.
1 parent f0b2aa5 commit 25ed9b0

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

pudb/debugger.py

+34-4
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,21 @@
183183

184184
# {{{ debugger interface
185185

186-
class Debugger(bdb.Bdb):
186+
class Singleton(type):
187+
_instance = None
188+
189+
def __call__(cls, *args, **kwargs):
190+
if not cls._instance:
191+
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
192+
return cls._instance
193+
194+
195+
class Debugger(bdb.Bdb, metaclass=Singleton):
187196
_current_debugger = []
188197

189198
def __init__(self, stdin=None, stdout=None, term_size=None, steal_output=False,
190199
_continue_at_start=False, tty_file=None, **kwargs):
191200

192-
if Debugger._current_debugger:
193-
raise ValueError("a Debugger instance already exists")
194-
195201
# Pass remaining kwargs to python debugger framework
196202
bdb.Bdb.__init__(self, **kwargs)
197203
self.ui = DebuggerUI(self, stdin=stdin, stdout=stdout, term_size=term_size)
@@ -214,6 +220,30 @@ def __init__(self, stdin=None, stdout=None, term_size=None, steal_output=False,
214220
# Okay, now we have a debugger
215221
self._current_debugger.append(self)
216222

223+
def reset(self):
224+
"""Set values of attributes as ready to start debugging.
225+
226+
Override from Bdb.reset()
227+
228+
When pytest starts a postmortem analysis, but the debugger is already active,
229+
calling .reset() in src/_pytest/debugging.py::post_mortem
230+
causes the self.stopframe to be set to None.
231+
This pauses the debugger somewhere in the source code of the debugger. See #67
232+
233+
We detect using _current_debugger that this is the case and do not set the
234+
stopframe to None then.
235+
236+
Related #607, #52
237+
"""
238+
import linecache
239+
linecache.checkcache()
240+
self.botframe = None
241+
if not self._current_debugger:
242+
self.stopframe = None
243+
self.returnframe = None
244+
self.quitting = False
245+
self.stoplineno = 0
246+
217247
def __del__(self):
218248
# according to https://stackoverflow.com/a/1481512/1054322, the garbage
219249
# collector cannot be relied on to call this, so we call it explicitly

0 commit comments

Comments
 (0)