Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Fix recursive debugger #271

Merged
merged 3 commits into from
Feb 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions spyder_kernels/customize/spydercustomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from spyder_kernels.comms.frontendcomm import CommError, frontend_request
from spyder_kernels.customize.namespace_manager import NamespaceManager
from spyder_kernels.customize.spyderpdb import SpyderPdb
from spyder_kernels.customize.spyderpdb import SpyderPdb, enter_debugger
from spyder_kernels.customize.umr import UserModuleReloader
from spyder_kernels.py3compat import TimeoutError, PY2, _print, encode

Expand Down Expand Up @@ -374,18 +374,6 @@ def get_current_file_name():
return None


def get_debugger(filename):
"""Get a debugger for a given filename."""
debugger = pdb.Pdb()
filename = debugger.canonic(filename)
debugger._wait_for_mainpyfile = 1
debugger.mainpyfile = filename
debugger._user_requested_quit = 0
if os.name == 'nt':
filename = filename.replace('\\', '/')
return debugger, filename


def count_leading_empty_lines(cell):
"""Count the number of leading empty cells."""
if PY2:
Expand Down Expand Up @@ -597,10 +585,12 @@ def debugfile(filename=None, args=None, wdir=None, post_mortem=False,
filename = get_current_file_name()
if filename is None:
return
debugger, filename = get_debugger(filename)
debugger.continue_if_has_breakpoints = True
debugger.run("runfile(%r, args=%r, wdir=%r, current_namespace=%r)" % (
filename, args, wdir, current_namespace))

enter_debugger(
filename, True,
"runfile({}" +
", args=%r, wdir=%r, current_namespace=%r)" % (
args, wdir, current_namespace))


builtins.debugfile = debugfile
Expand Down Expand Up @@ -678,11 +668,10 @@ def debugcell(cellname, filename=None, post_mortem=False):
if filename is None:
return

debugger, filename = get_debugger(filename)
# The breakpoint might not be in the cell
debugger.continue_if_has_breakpoints = False
debugger.run("runcell({}, {})".format(
repr(cellname), repr(filename)))
enter_debugger(
filename, False,
"runcell({}, ".format(repr(cellname)) +
"{})")


builtins.debugcell = debugcell
Expand Down
46 changes: 44 additions & 2 deletions spyder_kernels/customize/spyderpdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
"""Spyder debugger."""

import bdb
import sys
import logging
import os
import sys
import traceback
from collections import namedtuple

Expand Down Expand Up @@ -512,7 +513,7 @@ def user_return(self, frame, return_value):
if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
or frame.f_lineno <= 0):
return
self._wait_for_mainpyfile = 0
self._wait_for_mainpyfile = False
super(SpyderPdb, self).user_return(frame, return_value)

def _cmdloop(self):
Expand Down Expand Up @@ -700,3 +701,44 @@ def runcall(self, *args, **kwds):
"""
with DebugWrapper(self):
super(SpyderPdb, self).runcall(*args, **kwds)


def enter_debugger(filename, continue_if_has_breakpoints, code_format):
"""Enter debugger. Code format should be a format that accept filename."""
kernel = get_ipython().kernel
recursive = kernel.is_debugging()
if recursive:
parent_debugger = kernel._pdb_obj
sys.settrace(None)
globals = parent_debugger.curframe.f_globals
locals = parent_debugger.curframe_locals
# Create child debugger
debugger = SpyderPdb(
completekey=parent_debugger.completekey,
stdin=parent_debugger.stdin, stdout=parent_debugger.stdout)
debugger.use_rawinput = parent_debugger.use_rawinput
debugger.prompt = "(%s) " % parent_debugger.prompt.strip()
else:
debugger = SpyderPdb()

filename = debugger.canonic(filename)
debugger._wait_for_mainpyfile = True
debugger.mainpyfile = filename
debugger.continue_if_has_breakpoints = continue_if_has_breakpoints
debugger._user_requested_quit = False

if os.name == 'nt':
filename = filename.replace('\\', '/')

code = code_format.format(repr(filename))

if recursive:
# Enter recursive debugger
sys.call_tracing(debugger.run, (code, globals, locals))
# Reset parent debugger
sys.settrace(parent_debugger.trace_dispatch)
parent_debugger.lastcmd = debugger.lastcmd
kernel._register_pdb_session(parent_debugger)
else:
# The breakpoint might not be in the cell
debugger.run(code)