def exec_code(code, filename, ns_globals, ns_locals=None): """Execute code and display any exception.""" if PY2: filename = encode(filename) code = encode(code) ipython_shell = get_ipython() is_ipython = os.path.splitext(filename)[1] == '.ipy' try: if is_ipython: # transform code tm = TransformerManager() if not PY2: # Avoid removing lines tm.cleanup_transforms = [] code = tm.transform_cell(code) exec(compile(code, filename, 'exec'), ns_globals, ns_locals) except SystemExit as status: # ignore exit(0) if status.code: ipython_shell.showtraceback(exception_only=True) except BaseException as error: if (isinstance(error, bdb.BdbQuit) and ipython_shell.kernel._pdb_obj): # Ignore BdbQuit if we are debugging, as it is expected. ipython_shell.kernel._pdb_obj = None else: # We ignore the call to exec ipython_shell.showtraceback(tb_offset=1)
def transform_cell(code): """Transform ipython code to python code.""" tm = TransformerManager() number_empty_lines = count_leading_empty_lines(code) code = tm.transform_cell(code) if PY2: return code return '\n' * number_empty_lines + code
def _is_pdb_complete(self, source): """ Check if the pdb input is ready to be executed. """ if source and source[0] == '!': source = source[1:] tm = TransformerManager() complete, indent = tm.check_complete(source) if indent is not None: indent = indent * ' ' return complete != 'incomplete', indent
def transform_cell(code, indent_only=False): """Transform IPython code to Python code.""" number_empty_lines = count_leading_empty_lines(code) if indent_only: if not code.endswith('\n'): code += '\n' # Ensure the cell has a trailing newline lines = code.splitlines(keepends=True) lines = leading_indent(leading_empty_lines(lines)) code = ''.join(lines) else: tm = TransformerManager() code = tm.transform_cell(code) return '\n' * number_empty_lines + code
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)
def get_ipython_magic_type( ipython_magic: str) -> Optional[IPythonMagicType]: """Return the type of ipython magic. This function assumes the input parameter to be a ipython magic. It is recommended to call this method after checking `is_ipython_magic`. Parameters ---------- ipython_magic : str Ipython magic statement Returns ------- Optional[IPythonMagicType] Type of the IPython magic """ python_code = TransformerManager().transform_cell(ipython_magic) magic_type: Optional[IPythonMagicType] = None for magic, prefixes in MagicHandler._MAGIC_PREFIXES.items(): if any(prefix in python_code for prefix in prefixes): magic_type = magic break else: magic_type = IPythonMagicType.NO_MAGIC return magic_type
def ipython2python(code): """Transform IPython syntax to pure Python syntax Parameters ---------- code : str IPython code, to be transformed to pure Python """ try: from IPython.core.inputtransformer2 import TransformerManager except ImportError: warnings.warn( "IPython is needed to transform IPython syntax to pure Python." " Install ipython if you need this functionality." ) return code else: isp = TransformerManager() return isp.transform_cell(code)
def find_imports(path): from IPython.core.inputtransformer2 import TransformerManager tm = TransformerManager() collector = ImportCollector() for nb_file in pathlib.Path(path).glob("**/*.ipynb"): with nb_file.open("r") as f: nb = nbformat.read(f, as_version=4) for cell in nb.cells: if cell.cell_type == "code": source = tm.transform_cell(cell.source) try: node = ast.parse(source) except SyntaxError: # invalid cell # e.g. cell with magics pass else: collector.visit(node) for py_file in pathlib.Path(path).glob("**/*.py"): with py_file.open("r") as f: source = f.read() try: node = ast.parse(source) except SyntaxError: # invalid cell # e.g. cell with magics pass else: collector.visit(node) print("All counts") pprint(collector.imports) print("Top-level packages") for mod, count in sorted( collector.imports.items(), key=lambda x: (x[1], len(x[0]), x[0]), reverse=True, ): if "." not in mod: print(f"{mod:20}: {count:3}")
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:] # 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 try: line = TransformerManager().transform_cell(line) try: code = compile(line + '\n', '<stdin>', 'single') except SyntaxError: # support multiline statments code = compile(line + '\n', '<stdin>', 'exec') 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') exec(code, globals, locals) if execute_events: get_ipython().events.trigger('post_execute') finally: 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())
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)
def mask_cell(src: str) -> Tuple[str, List[Replacement]]: """Mask IPython magics so content becomes parseable Python code. For example, %matplotlib inline 'foo' becomes "25716f358c32750e" 'foo' The replacements are returned, along with the transformed code. """ replacements: List[Replacement] = [] try: ast.parse(src) except SyntaxError: # Might have IPython magics, will process below. pass else: # Syntax is fine, nothing to mask, early return. return src, replacements from IPython.core.inputtransformer2 import TransformerManager transformer_manager = TransformerManager() transformed = transformer_manager.transform_cell(src) transformed, cell_magic_replacements = replace_cell_magics(transformed) replacements += cell_magic_replacements transformed = transformer_manager.transform_cell(transformed) transformed, magic_replacements = replace_magics(transformed) if len(transformed.splitlines()) != len(src.splitlines()): # Multi-line magic, not supported. raise NothingChanged replacements += magic_replacements return transformed, replacements
def _is_pdb_complete(self, source): """ Check if the pdb input is ready to be executed. """ if source and source[0] == '!': source = source[1:] if LooseVersion(ipy_version) < LooseVersion('7.0.0'): tm = IPythonInputSplitter() else: tm = TransformerManager() complete, indent = tm.check_complete(source) if indent is not None: indent = indent * ' ' return complete != 'incomplete', indent
def _should_ignore_code_cell( source: Sequence[str], process_cells: Sequence[str] ) -> bool: """ Return True if the current cell should be ignored from processing. Parameters ---------- source Source from the notebook cell process_cells Extra cells which nbqa should process. Returns ------- bool True if the cell should ignored else False """ if not "".join(source): return True try: ast.parse("".join(source)) except SyntaxError: # Deal with this below pass else: # No need to ignore return False cell_magic_finder = CellMagicFinder() body = TransformerManager().transform_cell("".join(source)) try: tree = ast.parse(body) except SyntaxError: # Don't ignore, let tool deal with syntax error return False cell_magic_finder.visit(tree) if cell_magic_finder.header is None: # If there's no cell magic, don't ignore. return False magic_name = remove_prefix(cell_magic_finder.header.split()[0], "%%") return magic_name not in MAGIC and magic_name not in { i.strip() for i in process_cells }
def transform_cell(code, indent_only=False): """Transform ipython code to python code.""" number_empty_lines = count_leading_empty_lines(code) if indent_only: # Not implemented for PY2 if LooseVersion(ipy_version) < LooseVersion('7.0.0'): return code if not code.endswith('\n'): code += '\n' # Ensure the cell has a trailing newline lines = code.splitlines(keepends=True) lines = leading_indent(leading_empty_lines(lines)) code = ''.join(lines) else: if LooseVersion(ipy_version) < LooseVersion('7.0.0'): tm = IPythonInputSplitter() return tm.transform_cell(code) else: tm = TransformerManager() code = tm.transform_cell(code) return '\n' * number_empty_lines + code
def _transform_magic_commands(cell, hidden_variables): def __cell_magic(lines): # https://github.com/ipython/ipython/blob/1879ed27bb0ec3be5fee499ac177ad14a9ef7cfd/IPython/core/inputtransformer2.py#L91 if not lines or not lines[0].startswith("%%"): return lines if re.match(r"%%\w+\?", lines[0]): # This case will be handled by help_end return lines magic_name, _, first_line = lines[0][2:-1].partition(" ") body = "".join(lines[1:]) hidden_variables.append("".join(lines)) return [__BF_SIGNATURE__.format(len(hidden_variables) - 1)] class __MagicAssign(MagicAssign): def transform(self, lines): # https://github.com/ipython/ipython/blob/1879ed27bb0ec3be5fee499ac177ad14a9ef7cfd/IPython/core/inputtransformer2.py#L223 """Transform a magic assignment found by the ``find()`` classmethod.""" start_line, start_col = self.start_line, self.start_col lhs = lines[start_line][:start_col] end_line = find_end_of_continued_line(lines, start_line) rhs = assemble_continued_line(lines, (start_line, start_col), end_line) assert rhs.startswith("%"), rhs magic_name, _, args = rhs[1:].partition(" ") lines_before = lines[:start_line] hidden_variables.append(rhs) call = __BF_SIGNATURE__.format(len(hidden_variables) - 1) new_line = lhs + call + "\n" lines_after = lines[end_line + 1:] return lines_before + [new_line] + lines_after class __SystemAssign(SystemAssign): def transform(self, lines): # https://github.com/ipython/ipython/blob/1879ed27bb0ec3be5fee499ac177ad14a9ef7cfd/IPython/core/inputtransformer2.py#L262 """Transform a system assignment found by the ``find()`` classmethod.""" start_line, start_col = self.start_line, self.start_col lhs = lines[start_line][:start_col] end_line = find_end_of_continued_line(lines, start_line) rhs = assemble_continued_line(lines, (start_line, start_col), end_line) assert rhs.startswith("!"), rhs cmd = rhs[1:] lines_before = lines[:start_line] hidden_variables.append(rhs) call = __BF_SIGNATURE__.format(len(hidden_variables) - 1) new_line = lhs + call + "\n" lines_after = lines[end_line + 1:] return lines_before + [new_line] + lines_after class __EscapedCommand(EscapedCommand): def transform(self, lines): # https://github.com/ipython/ipython/blob/1879ed27bb0ec3be5fee499ac177ad14a9ef7cfd/IPython/core/inputtransformer2.py#L382 """Transform an escaped line found by the ``find()`` classmethod.""" start_line, start_col = self.start_line, self.start_col indent = lines[start_line][:start_col] end_line = find_end_of_continued_line(lines, start_line) line = assemble_continued_line(lines, (start_line, start_col), end_line) if len(line) > 1 and line[:2] in ESCAPE_DOUBLES: escape, content = line[:2], line[2:] else: escape, content = line[:1], line[1:] if escape in tr: hidden_variables.append(line) call = __BF_SIGNATURE__.format(len(hidden_variables) - 1) else: call = "" lines_before = lines[:start_line] new_line = indent + call + "\n" lines_after = lines[end_line + 1:] return lines_before + [new_line] + lines_after class __HelpEnd(HelpEnd): def transform(self, lines): # https://github.com/ipython/ipython/blob/1879ed27bb0ec3be5fee499ac177ad14a9ef7cfd/IPython/core/inputtransformer2.py#L439 """Transform a help command found by the ``find()`` classmethod.""" piece = "".join(lines[self.start_line:self.q_line + 1]) indent, content = piece[:self.start_col], piece[self.start_col:] lines_before = lines[:self.start_line] lines_after = lines[self.q_line + 1:] m = _help_end_re.search(content) if not m: raise SyntaxError(content) assert m is not None, content target = m.group(1) esc = m.group(3) # If we're mid-command, put it back on the next prompt for the user. next_input = None if (not lines_before) and ( not lines_after) and content.strip() != m.group(0): next_input = content.rstrip("?\n") hidden_variables.append(content) call = __BF_SIGNATURE__.format(len(hidden_variables) - 1) new_line = indent + call + "\n" return lines_before + [new_line] + lines_after transformer_manager = TransformerManager() transformer_manager.line_transforms = [__cell_magic] transformer_manager.token_transformers = [ __MagicAssign, __SystemAssign, __EscapedCommand, __HelpEnd, ] return transformer_manager.transform_cell(cell)
def _replace_magics( source: Sequence[str], magic_substitutions: List[MagicHandler], command: str, *, skip_bad_cells: bool, ) -> str: """ Replace IPython line magics with valid python code. Parameters ---------- source Source from notebook cell. magic_substitutions List to store all the ipython magics substitutions Returns ------- str Line from cell, with line magics replaced with python code """ try: ast.parse("".join(source)) except SyntaxError: pass else: # Source has no IPython magic, return it directly return "".join(source) cell_magic_finder = CellMagicFinder() body = TransformerManager().transform_cell("".join(source)) try: tree = ast.parse(body) except SyntaxError: if skip_bad_cells: handler = MagicHandler("".join(source), command, magic_type=None) magic_substitutions.append(handler) return handler.replacement return "".join(source) cell_magic_finder.visit(tree) # if first line is cell magic, process it separately if cell_magic_finder.header is not None: assert cell_magic_finder.body is not None header = _process_source( cell_magic_finder.header, command, magic_substitutions, skip_bad_cells=skip_bad_cells, ) cell = _process_source( cell_magic_finder.body, command, magic_substitutions, skip_bad_cells=skip_bad_cells, ) return "\n".join([header, cell]) return _process_source( "".join(source), command, magic_substitutions, skip_bad_cells=skip_bad_cells )
""" import sys import warnings import ast import nbformat # try to fight the advertising/deprecation warnings and get an # ipython2python function without confusing messages appearing # all over the place try: from IPython.core.inputtransformer2 import TransformerManager ipython2python = TransformerManager().transform_cell except: # this is the import I wanted to use, but it generates # deprecation wanrings when all the latest packages are # installed (as of 12 June 2019). from nbconvert.filters.strings import ipython2python from . import holoviews_support from . import builtins_support # TODO: still nede to investigate the following line magics (and what # does ipython convert do to them?): # # ? cd # ? dirs # macro
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 # This is necessary to allow running comprehensions with the # frame locals. It also fallbacks to the right globals if the # user wants to work with them instead. # See spyder-ide/spyder#13909. if not 'globals()' in line: ns = self.curframe.f_globals.copy() ns.update(locals) else: ns = 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 ns or cmd in builtins.__dict__) # Special case for quit and exit if cmd in ("quit", "exit"): if cmd in ns and isinstance(ns[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 is_assignment = arg and arg[0] == "=" 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) try: code = compile(line + '\n', '<stdin>', 'single') except SyntaxError: # support multiline statments code = compile(line + '\n', '<stdin>', 'exec') 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') exec(code, ns, locals) if execute_events: get_ipython().events.trigger('post_execute') finally: 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())
def ipython_cell_transform(source): out = TransformerManager().transform_cell(source) return source, out
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) try: code = compile(line + '\n', '<stdin>', 'single') except SyntaxError: # support multiline statments code = compile(line + '\n', '<stdin>', 'exec') 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') # Mitigates a CPython bug (https://bugs.python.org/issue41918) # that prevents running comprehensions with the frame locals # in Pdb. # See https://bugs.python.org/issue21161 and # spyder-ide/spyder#13909. if uses_comprehension(line): # There are three potential problems with this approach: # 1. If the code access a globals variable that is # masked by a locals variable, it will get the locals # one. # 2. Any edit to that variable will be lost. # 3. The globals will appear to contain all the locals # variables. # 4. Any new locals variable will be saved to globals # instead fake_globals = globals.copy() fake_globals.update(locals) locals_keys = locals.keys() # Don't pass locals, solves spyder-ide/spyder#16790 exec(code, fake_globals) # Avoid mixing locals and globals for key in locals_keys: locals[key] = fake_globals.pop(key, None) globals.update(fake_globals) else: exec(code, globals, locals) if execute_events: get_ipython().events.trigger('post_execute') finally: 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())
def init_line_transforms(self): """ Set up transforms (like the preparser). TESTS: Check that :trac:`31951` is fixed:: sage: from IPython import get_ipython sage: ip = get_ipython() sage: ip.input_transformer_manager.check_complete(''' # indirect doctest ....: for i in [1 .. 2]: ....: a = 2''') ('incomplete', 2) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(L) ....: K.<a> = L''') ('invalid', None) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(L): ....: K.<a> = L''') ('incomplete', 4) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(L): ....: K.<a> = L''') ('incomplete', 4) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(R): ....: a = R.0''') ('incomplete', 4) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(a): ....: b = 2a''') ('invalid', None) sage: implicit_multiplication(True) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(a): ....: b = 2a''') ('incomplete', 4) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(): ....: f(x) = x^2''') ('incomplete', 4) sage: ip.input_transformer_manager.check_complete(''' ....: def foo(): ....: 2.factor()''') ('incomplete', 4) """ from IPython.core.inputtransformer2 import TransformerManager from .interpreter import SagePromptTransformer, SagePreparseTransformer self.shell.input_transformer_manager.cleanup_transforms.insert( 1, SagePromptTransformer) self.shell.input_transformers_post.append(SagePreparseTransformer) # Create an input transformer that does Sage's special syntax in the first step. # We append Sage's preparse to the cleanup step, so that ``check_complete`` recognizes # Sage's special syntax. # Behaviour is somewhat inconsistent, but the syntax is recognized as desired. M = TransformerManager() M.token_transformers = self.shell.input_transformer_manager.token_transformers M.cleanup_transforms.insert(1, SagePromptTransformer) M.cleanup_transforms.append(SagePreparseTransformer) self.shell._check_complete_transformer = M self.shell.input_transformer_manager.check_complete = M.check_complete
def is_complete(self, source): tm = TransformerManager() check_complete = tm.check_complete(source) responses.append(check_complete)
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())
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())