Repository: ipython/ipython
Pull request: Restore lineno's for Input mapped files
This restores line number information in tracebacks from input, which got removed during the transition to v8 enhanced traceback reporting.

Problem statement:
v8 Errors: input line numbers missing
I quite like the new (v8) simple format for syntax and other compile errors from Input, like `Input In [25]`.  But compared to the old (v7) error header with pseudo-files (e.g. `File "<ipython-input-6-9e0b5ab16b5e>", line 4`), the line number has gone missing.  There are tools which parse iPython's errors which will be missing this line information.  This is also particularly problematic for syntax/indentation errors in `Plain` style with multi-line input:

```
In [25]: if True:
    ...:     same_var = 1
    ...: else:
    ...:    same_var = 2
    ...:     same_var = 1
    ...:     same_var = 1
  Input In [25]
    same_var = 1
    ^
IndentationError: unexpected indent
```

I think `Input In [25], line 5` would be perfect, or, for consistency with the file version, `Input In [25]:5`.

Hints from issue discussion:
I've been testing with the following in ultratb.py's `_format_filename`:

```python
    if ipinst is not None and file in ipinst.compile._filename_map:
        file = "[%s]" % ipinst.compile._filename_map[file]
        if lineno is None:
            tpl_link = f"Input {ColorFilename}In {{file}}{ColorNormal}"
        else:
            tpl_link = f"Input {ColorFilename}In {{file}}:{{lineno}}{ColorNormal}"
```

and it's working well. 
@jdtsmith Nice. I don't think anyone would have any issue with adding this, could you please turn it into a PR?
Thanks, see #13560.  
Seems like this has been fixed in 8.1.0 with #13535. My apologies go to @jdtsmith for not checking this properly and wasting their time on this.
No worries.  But in fact #13535 only adds line information for run errors like ZeroDivisionError, not Syntax/Indentation Errors, and related.  See #13560. (And it gives me incorrect line numbers too).  
You're right. Some of my brain cells might be off today :smile:. Back to PR it is.

Let's reopen this issue though and link the PR, then it will get closed automatically on merge. 
Hi @MrMino, just checking on the status of this issue.  I have tooling standing by to learn the final decision on restoring line numbers for input blocks across the board.  Thanks.
In case you haven't checked in on PR #13560 recently, I got confirmation that the <cell line...> stuff was no longer needed and can be reverted.  I also went ahead a just pushed the small change changing "Input cell" -> "Cell" for a short and consistent layout. Let me know if you see anything else needed in #13560 before it could be merged.

Commit message: Remove <module> from traceback doctests

Patch to review:
diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py
index 790a75e7d4e..96e7cd1dd4b 100644
--- a/IPython/core/interactiveshell.py
+++ b/IPython/core/interactiveshell.py
@@ -15,7 +15,6 @@
 import ast
 import atexit
 import builtins as builtin_mod
-import dis
 import functools
 import inspect
 import os
@@ -3183,29 +3182,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],
@@ -3304,7 +3280,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
diff --git a/IPython/core/tests/test_iplib.py b/IPython/core/tests/test_iplib.py
index 94ce5185865..d988fcb6811 100644
--- a/IPython/core/tests/test_iplib.py
+++ b/IPython/core/tests/test_iplib.py
@@ -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()
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py
index 85697919408..68507bc3c44 100644
--- a/IPython/core/ultratb.py
+++ b/IPython/core/ultratb.py
@@ -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)
@@ -464,29 +467,38 @@ 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" % (
+            item = "  %s" % (
                 _format_filename(
                     filename, Colors.filename, Colors.Normal, lineno=lineno
-                ),
-                Colors.name,
-                name,
-                Colors.Normal,
+                )
             )
+
+            if name != "<module>":
+                item += " in %s%s%s\n" % (
+                    Colors.name,
+                    name,
+                    Colors.Normal,
+                )
+            else:
+                item += "\n"
             if line:
                 item += '    %s\n' % line.strip()
             list.append(item)
         # Emphasize the last entry
         filename, lineno, name, line = extracted_list[-1]
-        item = "%s  %s in %s%s%s%s\n" % (
+        item = "%s  %s" % (
             Colors.normalEm,
             _format_filename(
                 filename, Colors.filenameEm, Colors.normalEm, lineno=lineno
             ),
-            Colors.nameEm,
-            name,
-            Colors.normalEm,
-            Colors.Normal,
         )
+        if name != "<module>":
+            item += " in %s%s%s" % (
+                Colors.nameEm,
+                name,
+                Colors.normalEm,
+            )
+        item += "%s\n" % (Colors.Normal)
         if line:
             item += '%s    %s%s\n' % (Colors.line, line.strip(),
                                       Colors.Normal)
@@ -687,7 +699,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
@@ -731,7 +743,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 = "%s%s%s\n" % (link, ", " if call else "", call)
 
         result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
         return result
diff --git a/docs/source/whatsnew/pr/restore-line-numbers.rst b/docs/source/whatsnew/pr/restore-line-numbers.rst
new file mode 100644
index 00000000000..9b699eaca4f
--- /dev/null
+++ b/docs/source/whatsnew/pr/restore-line-numbers.rst
@@ -0,0 +1,5 @@
+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.


Code review comments:
diff_hunk: @@ -464,29 +467,38 @@ 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" % (
+            item = "  %s" % (
                 _format_filename(
                     filename, Colors.filename, Colors.Normal, lineno=lineno
-                ),
-                Colors.name,
-                name,
-                Colors.Normal,
+                )
             )
+
+            if name != "<module>":
+                item += " in %s%s%s\n" % (
+                    Colors.name,
+                    name,
+                    Colors.Normal,
+                )
+            else:
+                item += "\n"
             if line:
                 item += '    %s\n' % line.strip()
             list.append(item)
         # Emphasize the last entry
         filename, lineno, name, line = extracted_list[-1]
-        item = "%s  %s in %s%s%s%s\n" % (
+        item = "%s  %s" % (
             Colors.normalEm,
             _format_filename(
                 filename, Colors.filenameEm, Colors.normalEm, lineno=lineno
             ),
-            Colors.nameEm,
-            name,
-            Colors.normalEm,
-            Colors.Normal,
         )
+        if name != "<module>":
+            item += " in %s%s%s" % (
path: IPython/core/ultratb.py
text: @user1:
Since we are changing this anyway, can we please get rid of `%`-formatting and use f-strings?

You can leave other lines in the module as is, but let's be good scouts and rice up the ones that you are changing.