From c7eb1ff05cc2db01751cc6a7a2d439fc1a8aacfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Delfino?= Date: Tue, 3 Nov 2026 21:40:01 -0300 Subject: [PATCH] gh-161289: Respect fillvalue length when truncating in reprlib.Repr repr_str(), repr_int() and repr_instance() computed how many characters to keep around the fill value assuming it is always three characters long (the default '...'). With a custom Repr.fillvalue of another length, the result exceeded or fell short of maxstring, maxlong and maxother. Use len(self.fillvalue) instead. Co-Authored-By: Claude Opus 5.5 --- Lib/reprlib.py | 12 ++++++------ Lib/test/test_reprlib.py | 17 +++++++++++++++++ ...26-11-03-22-19-40.gh-issue-161289.P62n_9.rst | 4 ++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-11-03-22-19-40.gh-issue-161289.P62n_9.rst diff --git a/Lib/reprlib.py b/Lib/reprlib.py index ab18247682b69a..f2af3c991c0e9f 100644 --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -174,8 +174,8 @@ def repr_dict(self, x, level): def repr_str(self, x, level): s = builtins.repr(x[:self.maxstring]) if len(s) > self.maxstring: - i = max(0, (self.maxstring-3)//2) - j = max(0, self.maxstring-3-i) + i = max(0, (self.maxstring-len(self.fillvalue))//2) + j = max(0, self.maxstring-len(self.fillvalue)-i) s = builtins.repr(x[:i] + x[len(x)-j:]) s = s[:i] + self.fillvalue + s[len(s)-j:] return s @@ -198,8 +198,8 @@ def repr_int(self, x, level): return (f'<{x.__class__.__name__} instance with roughly {k} ' f'digits (limit at {max_digits}) at 0x{id(x):x}>') if len(s) > self.maxlong: - i = max(0, (self.maxlong-3)//2) - j = max(0, self.maxlong-3-i) + i = max(0, (self.maxlong-len(self.fillvalue))//2) + j = max(0, self.maxlong-len(self.fillvalue)-i) s = s[:i] + self.fillvalue + s[len(s)-j:] return s @@ -211,8 +211,8 @@ def repr_instance(self, x, level): except Exception: return '<%s instance at %#x>' % (x.__class__.__name__, id(x)) if len(s) > self.maxother: - i = max(0, (self.maxother-3)//2) - j = max(0, self.maxother-3-i) + i = max(0, (self.maxother-len(self.fillvalue))//2) + j = max(0, self.maxother-len(self.fillvalue)-i) s = s[:i] + self.fillvalue + s[len(s)-j:] return s diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 5a95a05c6496a2..7deb4979dd172f 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -201,6 +201,23 @@ def test_instance(self): self.assertEndsWith(s, ">") self.assertIn(s.find("..."), [12, 13]) + def test_truncation_with_custom_fillvalue(self): + # The truncated repr must fit the limit whatever the fillvalue length. + eq = self.assertEqual + s = 'abcdefghijklmnopqrstuvwxyz' + n = 12345678901234567890 + i = ClassWithRepr('x' * 100) + + r1 = Repr(maxstring=10, maxlong=10, maxother=10, fillvalue='…') + eq(r1.repr(s), "'abc…wxyz'") + eq(r1.repr(n), '1234…67890') + eq(r1.repr(i), "Clas…xxx')") + + r2 = Repr(maxstring=10, maxlong=10, maxother=10, fillvalue='') + eq(r2.repr(s), "'az'") + eq(r2.repr(n), '1290') + eq(r2.repr(i), "Cl')") + def test_lambda(self): r = repr(lambda x: x) self.assertStartsWith(r, ".