From 6720df42163191483fce578162363354e5f53fac 2021-08-10 10:12:39 From: martinRenou Date: 2021-08-10 10:12:39 Subject: [PATCH] Improve error tracebacks so that it shows the cell prompts --- diff --git a/IPython/core/compilerop.py b/IPython/core/compilerop.py index fd7ac9a..b43e570 100644 --- a/IPython/core/compilerop.py +++ b/IPython/core/compilerop.py @@ -92,6 +92,10 @@ class CachingCompiler(codeop.Compile): # (otherwise we'd lose our tracebacks). linecache.checkcache = check_linecache_ipython + # Caching a dictionary { filename: execution_count } for nicely + # rendered tracebacks. The filename corresponds to the filename + # argument used for the builtins.compile function. + self._filename_map = {} def ast_parse(self, source, filename='', symbol='exec'): """Parse code to an AST with the current compiler flags active. @@ -153,6 +157,10 @@ class CachingCompiler(codeop.Compile): raw_code = transformed_code name = self.get_code_name(raw_code, transformed_code, number) + + # Save the execution count + self._filename_map[name] = number + entry = ( len(transformed_code), time.time(), diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index beed8c0..5d0a8e6 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -160,7 +160,7 @@ def _format_traceback_lines(lines, Colors, has_colors, lvals): else: num = '%*s' % (numbers_width, lineno) start_color = Colors.lineno - + line = '%s%s%s %s' % (start_color, num, Colors.Normal, line) res.append(line) @@ -300,7 +300,7 @@ class ListTB(TBTools): Calling requires 3 arguments: (etype, evalue, elist) as would be obtained by:: - + etype, evalue, tb = sys.exc_info() if tb: elist = traceback.extract_tb(tb) @@ -581,25 +581,31 @@ class VerboseTB(TBTools): Colors = self.Colors # just a shorthand + quicker name lookup ColorsNormal = Colors.Normal # used a lot - - if isinstance(frame_info, stack_data.RepeatedFrames): return ' %s[... skipping similar frames: %s]%s\n' % ( Colors.excName, frame_info.description, ColorsNormal) + file = frame_info.filename + + ipinst = get_ipython() + if ipinst is not None and file in ipinst.compile._filename_map: + file = "[%s]" % ipinst.compile._filename_map[file] + tpl_link = "In %s%%s%s," % (Colors.filenameEm, ColorsNormal) + else: + file = util_path.compress_user( + py3compat.cast_unicode(file, util_path.fs_encoding) + ) + tpl_link = "File %s%%s%s," % (Colors.filenameEm, ColorsNormal) + indent = ' ' * INDENT_SIZE em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal) - tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal) tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal) tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \ (Colors.vName, Colors.valEm, ColorsNormal) - tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal) tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal) - file = frame_info.filename - file = py3compat.cast_unicode(file, util_path.fs_encoding) - link = tpl_link % util_path.compress_user(file) + link = tpl_link % file args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame) func = frame_info.executing.code_qualname() diff --git a/docs/source/whatsnew/pr/traceback-improvements.rst b/docs/source/whatsnew/pr/traceback-improvements.rst new file mode 100644 index 0000000..b2fed7e --- /dev/null +++ b/docs/source/whatsnew/pr/traceback-improvements.rst @@ -0,0 +1,39 @@ +Traceback improvements +====================== + +Previously, error tracebacks for errors happening in code cells were showing a hash, the one used for compiling the Python AST. + + In [1]: def foo(): + ...: return 3 / 0 + ...: + + In [2]: foo() + --------------------------------------------------------------------------- + ZeroDivisionError Traceback (most recent call last) + in + ----> 1 foo() + + in foo() + 1 def foo(): + ----> 2 return 3 / 0 + 3 + + ZeroDivisionError: division by zero + +The error traceback is now correctly formatted, showing the cell number in which the error happened: + + In [1]: def foo(): + ...: return 3 / 0 + ...: + + In [2]: foo() + --------------------------------------------------------------------------- + ZeroDivisionError Traceback (most recent call last) + In [2], in + ----> 1 foo() + + In [1], in foo() + 1 def foo(): + ----> 2 return 3 / 0 + + ZeroDivisionError: division by zero