https://github.com/python/cpython/commit/c68ce16cee99df38405da127eefe1eeb40d37e99
commit: c68ce16cee99df38405da127eefe1eeb40d37e99
branch: main
author: Ćukasz Langa <[email protected]>
committer: gaogaotiantian <[email protected]>
date: 2026-09-14T20:41:55-07:00
summary:
gh-154470: Fix spurious ^J in pdb's colorized list command (#154473)
files:
A Misc/NEWS.d/next/Library/2026-07-22-13-39-58.gh-issue-154470.zGcz6K.rst
M Lib/pdb.py
M Lib/test/test_pdb.py
M Lib/test/test_remote_pdb.py
diff --git a/Lib/pdb.py b/Lib/pdb.py
index c3440a5d11a588..1ef877cce4dd96 100644
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -2440,9 +2440,13 @@ def _print_lines(self, lines, start, breaks=(),
frame=None):
s += '->'
elif lineno == exc_lineno:
s += '>>'
+ # Strip the trailing newline before colorizing: the colorizer
+ # renders control characters (like '\n') in caret notation, so a
+ # later rstrip() could not remove the resulting '^J'.
+ line = line.rstrip()
if self.colorize:
line = self._colorize_code(line)
- self.message(s + '\t' + line.rstrip())
+ self.message(s + '\t' + line)
def do_whatis(self, arg):
"""whatis expression
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index e7b66031a86a6c..0aa4ceb71c866f 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -4996,6 +4996,16 @@ def test_code_display(self):
p.set_trace(commands=['ll', 'c'])
self.assertNotIn("\x1b", output.getvalue())
+ def test_list_does_not_colorize_trailing_newlines(self):
+ # Keep the marker split so it is not present in the listed source.
+ caret_newline = "^" + "J"
+ output = io.StringIO()
+ p = pdb.Pdb(stdout=output, colorize=True)
+ p.set_trace(commands=['list', 'continue'])
+ result = output.getvalue()
+ self.assertIn("\x1b", result)
+ self.assertNotIn(caret_newline, result)
+
def test_stack_entry(self):
output = io.StringIO()
p = pdb.Pdb(stdout=output, colorize=True)
diff --git a/Lib/test/test_remote_pdb.py b/Lib/test/test_remote_pdb.py
index 5b23a194098b01..e5387526090536 100644
--- a/Lib/test/test_remote_pdb.py
+++ b/Lib/test/test_remote_pdb.py
@@ -1337,6 +1337,55 @@ def test_handle_eof(self):
self.assertEqual(process.returncode, 0)
self.assertEqual(stderr, "")
+ def test_colorized_list_has_no_caret_encoded_newlines(self):
+ """A colorized ``list`` must not append "^J" to each source line.
+
+ The remote server colorizes the source it sends to the client. The
+ colorizer renders control characters in caret notation, so a source
+ line's trailing newline has to be stripped *before* it is colorized;
+ otherwise every listed line ends with a spurious "^J". ``where`` was
+ unaffected because it strips the line before colorizing. See
+ gh-154470.
+ """
+ # colorize=True is what attaching from a color-capable terminal passes
+ # to the server, and it is what makes the server colorize ``list``.
+ script = textwrap.dedent(f"""
+ import pdb, sys
+ def helper():
+ x = 42
+ return x
+ def connect():
+ frame = sys._getframe()
+ pdb._connect(
+ host='127.0.0.1',
+ port={self.port},
+ frame=frame,
+ commands="",
+ version=pdb._PdbServer.protocol_version(),
+ signal_raising_thread=False,
+ colorize=True,
+ )
+ return helper()
+ connect()
+ """)
+ self._create_script(script=script)
+ process, client_file = self._connect_and_get_client_file()
+
+ with kill_on_error(process):
+ self._read_until_prompt(client_file)
+ self._send_command(client_file, "l 1, 15")
+ messages = self._read_until_prompt(client_file)
+ source = "".join(m["message"] for m in messages if "message" in m)
+
+ # Sanity: we really did receive colorized source ...
+ self.assertIn("helper", source)
+ self.assertIn("\x1b[", source) # ANSI color escapes are present
+ # ... and no trailing newline leaked through as caret notation.
+ self.assertNotIn("^J", source)
+ self._send_command(client_file, "c")
+ process.wait(timeout=SHORT_TIMEOUT)
+ self.assertEqual(process.returncode, 0)
+
@unittest.skipUnless(pty, "requires pty")
def test_prompt_with_interactive_terminal(self):
"""The server must send "(Pdb) " even when the target owns a terminal.
diff --git
a/Misc/NEWS.d/next/Library/2026-07-22-13-39-58.gh-issue-154470.zGcz6K.rst
b/Misc/NEWS.d/next/Library/2026-07-22-13-39-58.gh-issue-154470.zGcz6K.rst
new file mode 100644
index 00000000000000..e3d8e3c27cf638
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-07-22-13-39-58.gh-issue-154470.zGcz6K.rst
@@ -0,0 +1,4 @@
+Fixed a spurious ``^J`` printed at the end of every source line by the
+``list`` command of :mod:`pdb` when the output is colorized (for example
+when attaching to a running process). The source line is now stripped before
+it is colorized, like the ``where`` command already did.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]