diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py index aca1f427656bb5..99fce6f241e007 100644 --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -760,6 +760,14 @@ def test_subsequent_indent(self): initial_indent=" * ", subsequent_indent=" ") self.check(result, expect) + def test_indent_longer_than_width(self): + # gh-160558: wrap() looped forever when an indent was longer than + # width. + self.check_wrap(" ", 3, [], initial_indent="----") + self.check_wrap(" a", 3, ["----a"], initial_indent="----") + self.check_wrap("aaaa", 3, ["aaa", "----a", "----"], + subsequent_indent="----", drop_whitespace=False) + # Despite the similar names, DedentTestCase is *not* the inverse # of IndentTestCase! diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 2f213e34c2c329..ca87df5f46cb56 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -288,7 +288,7 @@ def _wrap_chunks(self, chunks): l = len(chunks[-1]) # Can at least squeeze this chunk onto the current line. - if cur_len + l <= width: + if cur_len + l <= width or not l: cur_line.append(chunks.pop()) cur_len += l diff --git a/Misc/NEWS.d/next/Library/2026-10-24-00-53-48.gh-issue-160558.XyEOEz.rst b/Misc/NEWS.d/next/Library/2026-10-24-00-53-48.gh-issue-160558.XyEOEz.rst new file mode 100644 index 00000000000000..0c0e2c6632df7a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-24-00-53-48.gh-issue-160558.XyEOEz.rst @@ -0,0 +1,2 @@ +Fix :func:`textwrap.wrap` and :func:`textwrap.fill` hanging in some cases +when *initial_indent* or *subsequent_indent* is longer than *width*.