https://github.com/python/cpython/commit/b9e460aacec7263bca6e06b87c57657a6799ae3b commit: b9e460aacec7263bca6e06b87c57657a6799ae3b branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: terryjreedy <[email protected]> date: 2026-09-20T03:30:00Z summary:
[3.13] gh-75512: Keep the prompt with the input in progress when a thread prints in the IDLE Shell (GH-157706) (#157837) gh-75512: Keep the prompt with the input in progress when a thread prints in the IDLE Shell (GH-157706) Output written while a prompt is shown was inserted after the newline which marks the prompt, so the statement being entered lost the prompt. If the output ends with a newline, the prompt is moved to the next line. (cherry picked from commit 89c67a98aeebee80d4cddcca86d9e52ceea89874) Co-authored-by: Serhiy Storchaka <[email protected]> files: A Misc/NEWS.d/next/IDLE/2026-09-17-22-00-00.gh-issue-75512.asyncout.rst M Lib/idlelib/idle_test/test_pyshell.py M Lib/idlelib/pyshell.py diff --git a/Lib/idlelib/idle_test/test_pyshell.py b/Lib/idlelib/idle_test/test_pyshell.py index dec81bdbbccd67..0e292e7be87ee4 100644 --- a/Lib/idlelib/idle_test/test_pyshell.py +++ b/Lib/idlelib/idle_test/test_pyshell.py @@ -69,6 +69,46 @@ def test_init(self): ## self.assertIsInstance(ps, pyshell.PyShell) +class PyShellTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + cls.shell = pyshell.PyShell(pyshell.PyShellFileList(cls.root)) + + @classmethod + def tearDownClass(cls): + cls.shell.close() + del cls.shell + cls.root.destroy() + del cls.root + + def setUp(self): + text = self.shell.text + self.shell.per.bottom.delete('1.0', 'end') + text.mark_set('iomark', '1.0') # As after begin(). + text.mark_gravity('iomark', 'left') + self.shell.undo.reset_undo() + + def test_output_at_prompt(self): + # gh-75512: output from a thread while a prompt is shown goes + # before the prompt, which stays with the input in progress. + shell = self.shell + text = shell.text + shell.write('x\n', 'stdout') + shell.resetoutput() + text.tag_add('console', 'iomark-1c') # As showprompt() does. + text.insert('end-1c', 'a = (') + shell.write('hel', 'stdout') + shell.write('lo\n', 'stdout') + self.assertEqual(text.get('iomark-6c', 'end-1c'), 'hello\na = (') + self.assertIn('console', text.tag_names('iomark-1c')) + self.assertNotIn('console', text.tag_names('iomark-7c')) + self.assertEqual(shell.shell_sidebar.line_prompts, {3: '>>>'}) + + class PyShellRemoveLastNewlineAndSurroundingWhitespaceTest(unittest.TestCase): regexp = pyshell.PyShell._last_newline_re diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 171084708a61c6..12df74f2b71544 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1432,13 +1432,24 @@ def resetoutput(self): self.ctip.remove_calltip_window() def write(self, s, tags=()): + text = self.text + # Move the prompt (the "console" tag on the preceding newline) + # after output which comes while it is shown (gh-75512). + at_prompt = (s and tags in ("stdout", "stderr") + and not self.executing and not self.reading) + if at_prompt: + text.tag_remove("console", "iomark-1c") + text.tag_remove("stdin", "iomark-1c") try: - self.text.mark_gravity("iomark", "right") + text.mark_gravity("iomark", "right") count = OutputWindow.write(self, s, tags, "iomark") - self.text.mark_gravity("iomark", "left") + text.mark_gravity("iomark", "left") except: raise ###pass # ### 11Aug07 KBK if we are expecting exceptions # let's find out what they are and be specific. + if at_prompt and s.endswith('\n'): + text.tag_add("console", "iomark-1c") + self.shell_sidebar.update_sidebar() if self.canceled: self.canceled = False if not use_subprocess: diff --git a/Misc/NEWS.d/next/IDLE/2026-09-17-22-00-00.gh-issue-75512.asyncout.rst b/Misc/NEWS.d/next/IDLE/2026-09-17-22-00-00.gh-issue-75512.asyncout.rst new file mode 100644 index 00000000000000..166cb6971f9b0e --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-09-17-22-00-00.gh-issue-75512.asyncout.rst @@ -0,0 +1,2 @@ +Output from a thread printed in the IDLE Shell while a statement is being +entered no longer takes over the prompt of the statement. _______________________________________________ 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]
