diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py index aca1f427656bb5..13289b5a491a2e 100644 --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -559,6 +559,20 @@ def test_placeholder(self): placeholder=' [truncated]...') self.check_wrap(self.text, 80, [self.text], placeholder='.' * 1000) + def test_placeholder_not_needed_when_text_fits(self): + # With max_lines set, text that fits must be returned as is even when + # the placeholder would not fit in the width; the placeholder is only + # required when the text is actually truncated. + self.assertEqual(shorten('ab', width=4), 'ab') + self.assertEqual(shorten('a', width=1), 'a') + self.assertEqual( + wrap('hello world', width=20, max_lines=3, + subsequent_indent=' ' * 17), + ['hello world']) + # Truncation that cannot place the placeholder still raises. + with self.assertRaises(ValueError): + shorten('a very long text goes here', width=4) + def test_placeholder_backtrack(self): # Test special case when max_lines insufficient, but what # would be last wrapped line so long the placeholder cannot diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 2f213e34c2c329..9476656f3361b7 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -251,13 +251,6 @@ def _wrap_chunks(self, chunks): lines = [] if self.width <= 0: raise ValueError("invalid width %r (must be > 0)" % self.width) - if self.max_lines is not None: - if self.max_lines > 1: - indent = self.subsequent_indent - else: - indent = self.initial_indent - if len(indent) + len(self.placeholder.lstrip()) > self.width: - raise ValueError("placeholder too large for max width") # Arrange in reverse order so items can be efficiently popped # from a stack of chucks. @@ -333,6 +326,10 @@ def _wrap_chunks(self, chunks): self.width): lines[-1] = prev_line + self.placeholder break + if (len(indent) + len(self.placeholder.lstrip()) + > self.width): + raise ValueError( + "placeholder too large for max width") lines.append(indent + self.placeholder.lstrip()) break diff --git a/Misc/NEWS.d/next/Library/2026-10-21-23-20-22.gh-issue-160043.AlgGSI.rst b/Misc/NEWS.d/next/Library/2026-10-21-23-20-22.gh-issue-160043.AlgGSI.rst new file mode 100644 index 00000000000000..10ba97651ef83b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-21-23-20-22.gh-issue-160043.AlgGSI.rst @@ -0,0 +1,4 @@ +:func:`textwrap.shorten` and :func:`textwrap.wrap` with *max_lines* no longer +raise :exc:`ValueError` for text that fits in *width* when the *placeholder* is +wider than *width*. The placeholder is only required when the text is actually +truncated.