Esempio n. 1
0
 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()
Esempio n. 2
0
    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.")
Esempio n. 3
0
 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.")
Esempio n. 4
0
 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.")
Esempio n. 5
0
    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()
Esempio n. 6
0
 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.")
Esempio n. 7
0
    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.")
Esempio n. 8
0
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)
Esempio n. 9
0
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
Esempio n. 10
0
    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.")
Esempio n. 11
0
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)
Esempio n. 12
0
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
Esempio n. 13
0
 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
Esempio n. 14
0
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
Esempio n. 15
0
 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()
Esempio n. 16
0
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
Esempio n. 17
0
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)
Esempio n. 18
0
    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())
Esempio n. 19
0
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)