Skip to content

Commit

Permalink
Restore lineno's for Input mapped files (#13560)
Browse files Browse the repository at this point in the history
* Implement lineno's for Input mapped files
* Adopt In [123], line 123 format
* Revert "Set co_name for cells run line by line. Fixes ipython/ipykernel#841"
  (This reverts commit d11e987.)
* Omit mention of ", in <module>" for input tracebacks
* Input cell -> Cell
* Remove <module> from traceback doctests
* Use f-string for `in ...' format
* Simplify _format_list logic, converting to f-strings
  • Loading branch information
jdtsmith authored Jun 16, 2022
1 parent ccd5325 commit a72418e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 59 deletions.
25 changes: 0 additions & 25 deletions IPython/core/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import atexit
import bdb
import builtins as builtin_mod
import dis
import functools
import inspect
import os
Expand Down Expand Up @@ -3212,29 +3211,6 @@ def transform_ast(self, node):
ast.fix_missing_locations(node)
return node

def _update_code_co_name(self, code):
"""Python 3.10 changed the behaviour so that whenever a code object
is assembled in the compile(ast) the co_firstlineno would be == 1.
This makes pydevd/debugpy think that all cells invoked are the same
since it caches information based on (co_firstlineno, co_name, co_filename).
Given that, this function changes the code 'co_name' to be unique
based on the first real lineno of the code (which also has a nice
side effect of customizing the name so that it's not always <module>).
See: https://github.com/ipython/ipykernel/issues/841
"""
if not hasattr(code, "replace"):
# It may not be available on older versions of Python (only
# available for 3.8 onwards).
return code
try:
first_real_line = next(dis.findlinestarts(code))[1]
except StopIteration:
return code
return code.replace(co_name="<cell line: %s>" % (first_real_line,))

async def run_ast_nodes(
self,
nodelist: ListType[stmt],
Expand Down Expand Up @@ -3333,7 +3309,6 @@ def compare(code):
else 0x0
):
code = compiler(mod, cell_name, mode)
code = self._update_code_co_name(code)
asy = compare(code)
if await self.run_code(code, result, async_=asy):
return True
Expand Down
12 changes: 6 additions & 6 deletions IPython/core/tests/test_iplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def doctest_tb_plain():
In [19]: run simpleerr.py
Traceback (most recent call last):
File ...:... in <module>
File ...:...
bar(mode)
File ...:... in bar
div0()
Expand All @@ -64,7 +64,7 @@ def doctest_tb_context():
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
...
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
Expand Down Expand Up @@ -93,7 +93,7 @@ def doctest_tb_verbose():
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
...
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
Expand Down Expand Up @@ -134,7 +134,7 @@ def doctest_tb_sysexit():
Traceback (most recent call last):
File ...:... in execfile
exec(compiler(f.read(), fname, "exec"), glob, loc)
File ...:... in <module>
File ...:...
bar(mode)
File ...:... in bar
sysexit(stat, mode)
Expand All @@ -152,7 +152,7 @@ def doctest_tb_sysexit():
... with open(fname, "rb") as f:
... compiler = compiler or compile
---> ... exec(compiler(f.read(), fname, "exec"), glob, loc)
...<module>
...
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
Expand Down Expand Up @@ -189,7 +189,7 @@ def doctest_tb_sysexit_verbose():
---------------------------------------------------------------------------
SystemExit Traceback (most recent call last)
<BLANKLINE>
... in <module>
...
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
Expand Down
50 changes: 22 additions & 28 deletions IPython/core/ultratb.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,10 @@ def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):

if ipinst is not None and file in ipinst.compile._filename_map:
file = "[%s]" % ipinst.compile._filename_map[file]
tpl_link = f"Input {ColorFilename}In {{file}}{ColorNormal}"
if lineno is None:
tpl_link = f"Cell {ColorFilename}In {{file}}{ColorNormal}"
else:
tpl_link = f"Cell {ColorFilename}In {{file}}, line {{lineno}}{ColorNormal}"
else:
file = util_path.compress_user(
py3compat.cast_unicode(file, util_path.fs_encoding)
Expand Down Expand Up @@ -463,34 +466,25 @@ def _format_list(self, extracted_list):

Colors = self.Colors
list = []
for filename, lineno, name, line in extracted_list[:-1]:
item = " %s in %s%s%s\n" % (
_format_filename(
filename, Colors.filename, Colors.Normal, lineno=lineno
),
Colors.name,
name,
Colors.Normal,
for ind, (filename, lineno, name, line) in enumerate(extracted_list):
normalCol, nameCol, fileCol, lineCol = (
# Emphasize the last entry
(Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
if ind == len(extracted_list) - 1
else (Colors.Normal, Colors.name, Colors.filename, "")
)

fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
item = f"{normalCol} {fns}"

if name != "<module>":
item += f" in {nameCol}{name}{normalCol}\n"
else:
item += "\n"
if line:
item += ' %s\n' % line.strip()
item += f"{lineCol} {line.strip()}{normalCol}\n"
list.append(item)
# Emphasize the last entry
filename, lineno, name, line = extracted_list[-1]
item = "%s %s in %s%s%s%s\n" % (
Colors.normalEm,
_format_filename(
filename, Colors.filenameEm, Colors.normalEm, lineno=lineno
),
Colors.nameEm,
name,
Colors.normalEm,
Colors.Normal,
)
if line:
item += '%s %s%s\n' % (Colors.line, line.strip(),
Colors.Normal)
list.append(item)

return list

def _format_exception_only(self, etype, value):
Expand Down Expand Up @@ -687,7 +681,7 @@ def format_record(self, frame_info):

func = frame_info.executing.code_qualname()
if func == "<module>":
call = tpl_call.format(file=func, scope="")
call = ""
else:
# Decide whether to include variable details or not
var_repr = eqrepr if self.include_vars else nullrepr
Expand Down Expand Up @@ -731,7 +725,7 @@ def format_record(self, frame_info):
if lvals_list:
lvals = '%s%s' % (indent, em_normal.join(lvals_list))

result = "%s, %s\n" % (link, call)
result = f'{link}{", " if call else ""}{call}\n'

result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
return result
Expand Down
50 changes: 50 additions & 0 deletions docs/source/whatsnew/pr/restore-line-numbers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Restore line numbers for Input
==================================

Line number information in tracebacks from input are restored.
Line numbers from input were removed during the transition to v8 enhanced traceback reporting.

So, instead of::

---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 myfunc(2)

Input In [2], in myfunc(z)
1 def myfunc(z):
----> 2 foo.boo(z-1)

File ~/code/python/ipython/foo.py:3, in boo(x)
2 def boo(x):
----> 3 return 1/(1-x)

ZeroDivisionError: division by zero

The error traceback now looks like::

---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In [3], line 1
----> 1 myfunc(2)

Cell In [2], line 2, in myfunc(z)
1 def myfunc(z):
----> 2 foo.boo(z-1)

File ~/code/python/ipython/foo.py:3, in boo(x)
2 def boo(x):
----> 3 return 1/(1-x)

ZeroDivisionError: division by zero

or, with xmode=Plain::

Traceback (most recent call last):
Cell In [12], line 1
myfunc(2)
Cell In [6], line 2 in myfunc
foo.boo(z-1)
File ~/code/python/ipython/foo.py:3 in boo
return 1/(1-x)
ZeroDivisionError: division by zero

0 comments on commit a72418e

Please sign in to comment.