def postloop(self): """Notifies spyder that the loop has ended.""" try: frontend_request(blocking=True).set_debug_state(False) except (CommError, TimeoutError): logger.debug("Could not send debugging state to the frontend.") super(SpyderPdb, self).postloop()
def set_spyder_breakpoints(self, breakpoints): """Set Spyder breakpoints.""" self.clear_all_breaks() # -----Really deleting all breakpoints: for bp in bdb.Breakpoint.bpbynumber: if bp: bp.deleteMe() bdb.Breakpoint.next = 1 bdb.Breakpoint.bplist = {} bdb.Breakpoint.bpbynumber = [None] # ----- for fname, data in list(breakpoints.items()): for linenumber, condition in data: try: self.set_break(self.canonic(fname), linenumber, cond=condition) except ValueError: # Fixes spyder/issues/15546 # The file is not readable pass # Jump to first breakpoint. # Fixes issue 2034 if self.starting: # Only run this after a Pdb session is created self.starting = False # Get all breakpoints for the file we're going to debug frame = self.curframe if not frame: # We are not debugging, return. Solves #10290 return lineno = frame.f_lineno breaks = self.get_file_breaks(frame.f_code.co_filename) # Do 'continue' if the first breakpoint is *not* placed # where the debugger is going to land. # Fixes issue 4681 if self.pdb_stop_first_line: do_continue = ( self.continue_if_has_breakpoints and breaks and lineno < breaks[0]) else: # The breakpoint could be in another file. do_continue = ( self.continue_if_has_breakpoints and not (breaks and lineno >= breaks[0])) if do_continue: try: if self.pdb_use_exclamation_mark: cont_cmd = '!continue' else: cont_cmd = 'continue' frontend_request(blocking=False).pdb_execute(cont_cmd) except (CommError, TimeoutError): logger.debug( "Could not send a Pdb continue call to the frontend.")
def __exit__(self, exc_type, exc_val, exc_tb): """ Debugging ends. """ self.pdb_obj._frontend_notified = False try: frontend_request(blocking=True).set_debug_state(False) except (CommError, TimeoutError): logger.debug("Could not send debugging state to the frontend.")
def __enter__(self): """ Debugging starts. """ self.pdb_obj._frontend_notified = True try: frontend_request(blocking=True).set_debug_state(True) except (CommError, TimeoutError): logger.debug("Could not send debugging state to the frontend.")
def do_where(self, arg): """w(here) Print a stack trace, with the most recent frame at the bottom. An arrow indicates the "current frame", which determines the context of most commands. 'bt' is an alias for this command. Take a number as argument as an (optional) number of context line to print""" super(SpyderPdb, self).do_where(arg) frontend_request().do_where()
def preloop(self): """Ask Spyder for breakpoints before the first prompt is created.""" try: frontend_request(blocking=True).set_debug_state(True) pdb_settings = frontend_request().get_pdb_settings() self.pdb_ignore_lib = pdb_settings['pdb_ignore_lib'] self.pdb_execute_events = pdb_settings['pdb_execute_events'] if self.starting: self.set_spyder_breakpoints(pdb_settings['breakpoints']) except (CommError, TimeoutError): logger.debug("Could not get breakpoints from the frontend.")
def publish_pdb_state(self): """ Send debugger state (frame position) to the frontend. The state is only sent if it has changed since the last update. """ frame = self.curframe if frame is None: self._previous_step = None return # Get filename and line number of the current frame fname = self.canonic(frame.f_code.co_filename) if fname == self.mainpyfile and self.remote_filename is not None: fname = self.remote_filename lineno = frame.f_lineno if self._previous_step == (fname, lineno): return # Set step of the current frame (if any) step = {} self._previous_step = None if isinstance(fname, str) and isinstance(lineno, int): step = dict(fname=fname, lineno=lineno) self._previous_step = (fname, lineno) try: frontend_request(blocking=False).pdb_state(dict(step=step)) except (CommError, TimeoutError): logger.debug("Could not send Pdb state to the frontend.") # Publish Pdb stack so we can update the Variable Explorer # and the Editor on the Spyder side pdb_stack = traceback.StackSummary.extract(self.stack) pdb_index = self.curindex skip_hidden = getattr(self, 'skip_hidden', False) if skip_hidden: # Filter out the hidden frames hidden = self.hidden_frames(self.stack) pdb_stack = [f for f, h in zip(pdb_stack, hidden) if not h] # Adjust the index pdb_index -= sum(hidden[:pdb_index]) try: frontend_request(blocking=False).set_pdb_stack( pdb_stack, pdb_index) except (CommError, TimeoutError): logger.debug("Could not send Pdb stack to the frontend.")
def runcell(cellname, filename=None, post_mortem=False): """ Run a code cell from an editor as a file. Currently looks for code in an `ipython` property called `cell_code`. This property must be set by the editor prior to calling this function. This function deletes the contents of `cell_code` upon completion. Parameters ---------- cellname : str or int Cell name or index. filename : str Needed to allow for proper traceback links. """ if filename is None: filename = get_current_file_name() if filename is None: return else: # get_debugger replaces \\ by / so we must undo that here # Otherwise code caching doesn't work if os.name == 'nt': filename = filename.replace('/', '\\') try: filename = filename.decode('utf-8') except (UnicodeError, TypeError, AttributeError): # UnicodeError, TypeError --> eventually raised in Python 2 # AttributeError --> systematically raised in Python 3 pass ipython_shell = get_ipython() try: # Get code from spyder cell_code = frontend_request().run_cell(cellname, filename) except Exception: _print("This command failed to be executed because an error occurred" " while trying to get the cell code from Spyder's" " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return if not cell_code or cell_code.strip() == '': _print("Nothing to execute, this cell is empty.\n") return # Trigger `post_execute` to exit the additional pre-execution. # See Spyder PR #7310. ipython_shell.events.trigger('post_execute') try: file_code = get_file_code(filename) except Exception: file_code = None with NamespaceManager(filename, current_namespace=True, file_code=file_code) as (ns_globals, ns_locals): exec_code(cell_code, filename, ns_globals, ns_locals, post_mortem=post_mortem)
def get_current_file_name(): """Get the current file name.""" try: return frontend_request().current_filename() except Exception: _print("This command failed to be executed because an error occurred" " while trying to get the current file name from Spyder's" " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return None
def set_spyder_breakpoints(self, breakpoints): """Set Spyder breakpoints.""" self.clear_all_breaks() # -----Really deleting all breakpoints: for bp in bdb.Breakpoint.bpbynumber: if bp: bp.deleteMe() bdb.Breakpoint.next = 1 bdb.Breakpoint.bplist = {} bdb.Breakpoint.bpbynumber = [None] # ----- i = 0 for fname, data in list(breakpoints.items()): for linenumber, condition in data: i += 1 self.set_break(self.canonic(fname), linenumber, cond=condition) # Jump to first breakpoint. # Fixes issue 2034 if self.starting: # Only run this after a Pdb session is created self.starting = False # Get all breakpoints for the file we're going to debug frame = self.curframe if not frame: # We are not debugging, return. Solves #10290 return lineno = frame.f_lineno breaks = self.get_file_breaks(frame.f_code.co_filename) # Do 'continue' if the first breakpoint is *not* placed # where the debugger is going to land. # Fixes issue 4681 if (self.continue_if_has_breakpoints and breaks and lineno < breaks[0]): try: frontend_request(blocking=False).pdb_execute('continue') except (CommError, TimeoutError): logger.debug( "Could not send a Pdb continue call to the frontend.")
def _exec_cell(cellname, filename=None, post_mortem=False, stack_depth=0, exec_fun=None, canonic_filename=None): """ Execute a code cell with a given exec function. """ # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True if filename is None: filename = get_current_file_name() if filename is None: return ipython_shell = get_ipython() try: # Get code from spyder cell_code = frontend_request(blocking=True).run_cell( cellname, filename) except Exception: print("This command failed to be executed because an error occurred" " while trying to get the cell code from Spyder's" " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return if not cell_code or cell_code.strip() == '': print("Nothing to execute, this cell is empty.\n") return # Trigger `post_execute` to exit the additional pre-execution. # See Spyder PR #7310. ipython_shell.events.trigger('post_execute') file_code = get_file_code(filename, save_all=False) # Here the remote filename has been used. It must now be valid locally. if canonic_filename is not None: filename = canonic_filename else: # Normalise the filename filename = canonic(filename) with NamespaceManager(filename, current_namespace=True, file_code=file_code, stack_depth=stack_depth + 1) as (ns_globals, ns_locals): return exec_code(cell_code, filename, ns_globals, ns_locals, post_mortem=post_mortem, exec_fun=exec_fun, capture_last_expression=True)
def get_file_code(filename): """Retrive the content of a file.""" # Get code from spyder try: file_code = frontend_request().get_file_code(filename) except (CommError, TimeoutError): file_code = None if file_code is None: with open(filename, 'r') as f: return f.read() return file_code
def _cmdloop(self): """Modifies the error text.""" while True: try: # keyboard interrupts allow for an easy way to cancel # the current command, so allow them during interactive input self.allow_kbdint = True self.cmdloop() self.allow_kbdint = False break except KeyboardInterrupt: _print("--KeyboardInterrupt--\n" "For copying text while debugging, use Ctrl+Shift+C", file=self.stdout) except Exception: try: frontend_request(blocking=True).set_debug_state(False) except (CommError, TimeoutError): logger.debug( "Could not send debugging state to the frontend.") raise
def get_file_code(filename, save_all=True): """Retrive the content of a file.""" # Get code from spyder try: file_code = frontend_request(blocking=True).get_file_code( filename, save_all=save_all) except (CommError, TimeoutError, RuntimeError, FileNotFoundError): file_code = None if file_code is None: with open(filename, 'r') as f: return f.read() return file_code
def preloop(self): """Ask Spyder for breakpoints before the first prompt is created.""" try: pdb_settings = frontend_request().get_pdb_settings() self.pdb_ignore_lib = pdb_settings['pdb_ignore_lib'] self.pdb_execute_events = pdb_settings['pdb_execute_events'] self.pdb_use_exclamation_mark = pdb_settings[ 'pdb_use_exclamation_mark'] self.pdb_stop_first_line = pdb_settings['pdb_stop_first_line'] if self.starting: self.set_spyder_breakpoints(pdb_settings['breakpoints']) if self.send_initial_notification: self.notify_spyder() except (CommError, TimeoutError): logger.debug("Could not get breakpoints from the frontend.") super(SpyderPdb, self).preloop()
def get_file_code(filename, save_all=True, raise_exception=False): """Retrieve the content of a file.""" # Get code from spyder try: return frontend_request(blocking=True).get_file_code(filename, save_all=save_all) except Exception: # Maybe this is a local file try: with open(filename, 'r') as f: return f.read() except FileNotFoundError: pass if raise_exception: raise # Else return None return None
def cell_count(filename=None): """ Get the number of cells in a file. Parameters ---------- filename : str The file to get the cells from. If None, the currently opened file. """ if filename is None: filename = get_current_file_name() if filename is None: raise RuntimeError('Could not get cell count from frontend.') try: # Get code from spyder cell_count = frontend_request().cell_count(filename) return cell_count except Exception: etype, error, tb = sys.exc_info() raise etype(error)
def default(self, line): """ Default way of running pdb statment. """ execute_events = self.pdb_execute_events if line[:1] == '!': line = line[1:] elif self.pdb_use_exclamation_mark: self.print_exclamation_warning() self.error("Unknown command '" + line.split()[0] + "'") return # Disallow the use of %debug magic in the debugger if line.startswith("%debug"): self.error("Please don't use '%debug' in the debugger.\n" "For a recursive debugger, use the pdb 'debug'" " command instead") return locals = self.curframe_locals globals = self.curframe.f_globals if self.pdb_use_exclamation_mark: # Find pdb commands executed without ! cmd, arg, line = self.parseline(line) if cmd: cmd_in_namespace = ( cmd in globals or cmd in locals or cmd in builtins.__dict__ ) # Special case for quit and exit if cmd in ("quit", "exit"): if cmd in globals and isinstance( globals[cmd], ZMQExitAutocall): # Use the pdb call cmd_in_namespace = False cmd_func = getattr(self, 'do_' + cmd, None) is_pdb_cmd = cmd_func is not None # Look for assignment is_assignment = False try: for node in ast.walk(ast.parse(line)): if isinstance(node, ast.Assign): is_assignment = True break except SyntaxError: pass if is_pdb_cmd: if not cmd_in_namespace and not is_assignment: # This is a pdb command without the '!' prefix. self.lastcmd = line return cmd_func(arg) else: # The pdb command is masked by something self.print_exclamation_warning() try: line = TransformerManager().transform_cell(line) save_stdout = sys.stdout save_stdin = sys.stdin save_displayhook = sys.displayhook try: sys.stdin = self.stdin sys.stdout = self.stdout sys.displayhook = self.displayhook if execute_events: get_ipython().events.trigger('pre_execute') code_ast = ast.parse(line) if line.rstrip()[-1] == ";": # Supress output with ; capture_last_expression = False else: code_ast, capture_last_expression = capture_last_Expr( code_ast, "_spyderpdb_out") if locals is not globals: # Mitigates a behaviour of CPython that makes it difficult # to work with exec and the local namespace # See: # - https://bugs.python.org/issue41918 # - https://bugs.python.org/issue46153 # - https://bugs.python.org/issue21161 # - spyder-ide/spyder#13909 # - spyder-ide/spyder-kernels#345 # # The idea here is that the best way to emulate being in a # function is to actually execute the code in a function. # A function called `_spyderpdb_code` is created and # called. It will first load the locals, execute the code, # and then update the locals. # # One limitation of this approach is that locals() is only # a copy of the curframe locals. This means that closures # for example are early binding instead of late binding. # Create a function indent = " " code = ["def _spyderpdb_code():"] # Load the locals globals["_spyderpdb_builtins_locals"] = builtins.locals # Save builtins locals in case it is shadowed globals["_spyderpdb_locals"] = locals # Load locals if they have a valid name # In comprehensions, locals could contain ".0" for example code += [indent + "{k} = _spyderpdb_locals['{k}']".format( k=k) for k in locals if k.isidentifier()] # Update the locals code += [indent + "_spyderpdb_locals.update(" "_spyderpdb_builtins_locals())"] # Run the function code += ["_spyderpdb_code()"] # Cleanup code += [ "del _spyderpdb_code", "del _spyderpdb_locals", "del _spyderpdb_builtins_locals" ] # Parse the function fun_ast = ast.parse('\n'.join(code) + '\n') # Inject code_ast in the function before the locals update fun_ast.body[0].body = ( fun_ast.body[0].body[:-1] # The locals + code_ast.body # Code to run + fun_ast.body[0].body[-1:] # Locals update ) code_ast = fun_ast exec(compile(code_ast, "<stdin>", "exec"), globals) if capture_last_expression: out = globals.pop("_spyderpdb_out", None) if out is not None: sys.stdout.flush() sys.stderr.flush() frontend_request(blocking=False).show_pdb_output( repr(out)) finally: if execute_events: get_ipython().events.trigger('post_execute') sys.stdout = save_stdout sys.stdin = save_stdin sys.displayhook = save_displayhook except BaseException: exc_info = sys.exc_info()[:2] self.error( traceback.format_exception_only(*exc_info)[-1].strip())
def _exec_cell(cellname, filename=None, post_mortem=False, stack_depth=0, exec_fun=None): """ Execute a code cell with a given exec function. """ # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True if filename is None: filename = get_current_file_name() if filename is None: return else: # get_debugger replaces \\ by / so we must undo that here # Otherwise code caching doesn't work if os.name == 'nt': filename = filename.replace('/', '\\') try: filename = filename.decode('utf-8') except (UnicodeError, TypeError, AttributeError): # UnicodeError, TypeError --> eventually raised in Python 2 # AttributeError --> systematically raised in Python 3 pass ipython_shell = get_ipython() try: # Get code from spyder cell_code = frontend_request(blocking=True).run_cell( cellname, filename) except Exception: _print("This command failed to be executed because an error occurred" " while trying to get the cell code from Spyder's" " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return if not cell_code or cell_code.strip() == '': _print("Nothing to execute, this cell is empty.\n") return # Trigger `post_execute` to exit the additional pre-execution. # See Spyder PR #7310. ipython_shell.events.trigger('post_execute') try: file_code = get_file_code(filename, save_all=False) except Exception: file_code = None # Normalise the filename filename = os.path.abspath(filename) filename = os.path.normcase(filename) with NamespaceManager(filename, current_namespace=True, file_code=file_code, stack_depth=stack_depth + 1) as (ns_globals, ns_locals): return exec_code(cell_code, filename, ns_globals, ns_locals, post_mortem=post_mortem, exec_fun=exec_fun, capture_last_expression=True)