diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index c4c3a4b..228cbd9 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -422,7 +422,8 @@ class ExecutionMagics(Magics): ) @no_var_expand @line_cell_magic - def debug(self, line='', cell=None): + @needs_local_scope + def debug(self, line="", cell=None, local_ns=None): """Activate the interactive debugger. This magic command support two ways of activating debugger. @@ -453,7 +454,7 @@ class ExecutionMagics(Magics): self._debug_post_mortem() elif not (args.breakpoint or cell): # If there is no breakpoints, the line is just code to execute - self._debug_exec(line, None) + self._debug_exec(line, None, local_ns) else: # Here we try to reconstruct the code from the output of # parse_argstring. This might not work if the code has spaces @@ -461,18 +462,20 @@ class ExecutionMagics(Magics): code = "\n".join(args.statement) if cell: code += "\n" + cell - self._debug_exec(code, args.breakpoint) + self._debug_exec(code, args.breakpoint, local_ns) def _debug_post_mortem(self): self.shell.debugger(force=True) - def _debug_exec(self, code, breakpoint): + def _debug_exec(self, code, breakpoint, local_ns=None): if breakpoint: (filename, bp_line) = breakpoint.rsplit(':', 1) bp_line = int(bp_line) else: (filename, bp_line) = (None, None) - self._run_with_debugger(code, self.shell.user_ns, filename, bp_line) + self._run_with_debugger( + code, self.shell.user_ns, filename, bp_line, local_ns=local_ns + ) @line_magic def tb(self, s): @@ -867,8 +870,9 @@ class ExecutionMagics(Magics): return stats - def _run_with_debugger(self, code, code_ns, filename=None, - bp_line=None, bp_file=None): + def _run_with_debugger( + self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None + ): """ Run `code` in debugger with a break point. @@ -885,6 +889,8 @@ class ExecutionMagics(Magics): bp_file : str, optional Path to the file in which break point is specified. `filename` is used if not given. + local_ns : dict, optional + A local namespace in which `code` is executed. Raises ------ @@ -941,7 +947,7 @@ class ExecutionMagics(Magics): while True: try: trace = sys.gettrace() - deb.run(code, code_ns) + deb.run(code, code_ns, local_ns) except Restart: print("Restarting") if filename: diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 8963705..da998fa 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -715,6 +715,7 @@ def doctest_precision(): Out[5]: '3.141593e+00' """ + def test_debug_magic(): """Test debugging a small code with %debug @@ -727,6 +728,22 @@ def test_debug_magic(): In [2]: """ + +def test_debug_magic_locals(): + """Test debugging a small code with %debug with locals + + In [1]: with PdbTestInput(['c']): + ...: def fun(): + ...: res = 1 + ...: %debug print(res) + ...: fun() + ...: + ... + ipdb> c + 1 + In [2]: + """ + def test_psearch(): with tt.AssertPrints("dict.fromkeys"): _ip.run_cell("dict.fr*?")