Пример #1
0
def _process_source(
    source: str,
    command: str,
    magic_substitutions: List[MagicHandler],
    *,
    skip_bad_cells: bool,
) -> str:
    """Temporarily replace ipython magics - don't process if can't."""
    try:
        ast.parse(source)
    except SyntaxError:
        pass
    else:
        # Source has no IPython magic, return it directly
        return source
    body = TransformerManager().transform_cell(source)
    if len(body.splitlines()) != len(source.splitlines()):
        handler = MagicHandler(source, command, magic_type=None)
        magic_substitutions.append(handler)
        return handler.replacement
    try:
        tree = ast.parse(body)
    except SyntaxError:
        if skip_bad_cells:
            handler = MagicHandler(source, command, magic_type=None)
            magic_substitutions.append(handler)
            return handler.replacement
        return source
    system_assigns_finder = SystemAssignsFinder()
    system_assigns_finder.visit(tree)
    visitor = Visitor(system_assigns_finder.system_assigns)
    visitor.visit(tree)
    new_src = []
    for i, line in enumerate(body.splitlines(), start=1):
        if i in visitor.magics:
            col_offset, src, magic_type = visitor.magics[i][0]
            if src is None or len(visitor.magics[i]) > 1:
                # unusual case - skip cell completely for now
                handler = MagicHandler(source, command, magic_type=magic_type)
                magic_substitutions.append(handler)
                return handler.replacement
            handler = MagicHandler(
                src,
                command,
                magic_type=magic_type,
            )
            magic_substitutions.append(handler)
            line = line[:col_offset] + handler.replacement
        new_src.append(line)
    return "\n" * (len(source) - len(source.lstrip("\n"))) + "\n".join(new_src)
Пример #2
0
 def _process_source(source: str) -> str:
     """Temporarily replace ipython magics - don't process if can't."""
     try:
         ast.parse(source)
     except SyntaxError:
         pass
     else:
         # Source has no IPython magic, return it directly
         return source
     body = TransformerManager().transform_cell(source)
     try:
         tree = ast.parse(body)
     except SyntaxError:
         return source
     visitor = Visitor()
     visitor.visit(tree)
     new_src = []
     for i, line in enumerate(body.splitlines(), start=1):
         if i in visitor.magics:
             col_offset, src, magic_type = visitor.magics[i][0]
             if (src is None or line[:col_offset].strip()
                     or len(visitor.magics[i]) > 1):
                 # unusual case - skip cell completely for now
                 handler = NewMagicHandler(source,
                                           command,
                                           magic_type=magic_type)
                 magic_substitutions.append(handler)
                 return handler.replacement
             handler = NewMagicHandler(
                 src,
                 command,
                 magic_type=magic_type,
             )
             magic_substitutions.append(handler)
             line = line[:col_offset] + handler.replacement
         new_src.append(line)
     leading_newlines = len(source) - len(source.lstrip("\n"))
     return "\n" * leading_newlines + "\n".join(new_src)
Пример #3
0
    def default(self, line):
        """
        Default way of running pdb statment.

        The only difference with Pdb.default is that if line contains multiple
        statments, the code will be compiled with 'exec'. It will not print the
        result but will run without failing.
        """
        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')

                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.

                    # Check if line is an expression to print
                    print_ret = False
                    try:
                        code = ast.parse(line + '\n', '<stdin>', 'single')
                        if len(code.body) == 1:
                            print_ret = isinstance(code.body[0], ast.Expr)
                    except SyntaxError:
                        pass

                    # Create a function and load the locals
                    globals["_spyderpdb_locals"] = locals
                    # Save builtins locals in case it is shadowed
                    globals["_spyderpdb_builtins_locals"] = builtins.locals
                    indent = "    "
                    code = ["def _spyderpdb_code():"]
                    # 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 isidentifier(k)
                    ]

                    # Run the code
                    if print_ret:
                        code += [indent + 'print(' + line.strip() + ")"]
                    else:
                        code += [indent + l for l in line.splitlines()]

                    # Update the locals
                    code += [
                        indent + "_spyderpdb_locals.update("
                        "_spyderpdb_builtins_locals())"
                    ]

                    # Run the function
                    code += ["_spyderpdb_code()"]
                    code = compile('\n'.join(code) + '\n', '<stdin>', 'exec')
                    try:
                        exec(code, globals)
                    finally:
                        globals.pop("_spyderpdb_locals", None)
                        globals.pop("_spyderpdb_code", None)
                        globals.pop("_spyderpdb_builtins_locals", None)
                else:
                    try:
                        code = compile(line + '\n', '<stdin>', 'single')
                    except SyntaxError:
                        # Support multiline statments
                        code = compile(line + '\n', '<stdin>', 'exec')
                    exec(code, globals)
            finally:
                if execute_events:
                    get_ipython().events.trigger('post_execute')
                sys.stdout = save_stdout
                sys.stdin = save_stdin
                sys.displayhook = save_displayhook
        except BaseException:
            if PY2:
                t, v = sys.exc_info()[:2]
                if type(t) == type(''):
                    exc_type_name = t
                else:
                    exc_type_name = t.__name__
                print >> self.stdout, '***', exc_type_name + ':', v
            else:
                exc_info = sys.exc_info()[:2]
                self.error(
                    traceback.format_exception_only(*exc_info)[-1].strip())