8000 [3.14] gh-135487: fix `reprlib.Repr.repr_int` when given very large i… · python/cpython@3cdb659 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3cdb659

Browse files
[3.14] gh-135487: fix reprlib.Repr.repr_int when given very large integers (GH-135506) (#135887)
gh-135487: fix `reprlib.Repr.repr_int` when given very large integers (GH-135506) (cherry picked from commit e5f03b9) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>

1 parent 961dd80 commit 3cdb659

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

Lib/reprlib.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,22 @@ def repr_str(self, x, level):
181181
return s
182182

183183
def repr_int(self, x, level):
184-
s = builtins.repr(x) # XXX Hope this isn't too slow...
184+
try:
185+
s = builtins.repr(x)
186+
except ValueError as exc:
187+
assert 'sys.set_int_max_str_digits()' in str(exc)
188+
# Those imports must be deferred due to Python's build system
189+
# where the reprlib module is imported before the math module.
190+
import math, sys
191+
# Integers with more than sys.get_int_max_str_digits() digits
192+
# are rendered differently as their repr() raises a ValueError.
193+
# See https://github.com/python/cpython/issues/135487.
194+
k = 1 + int(math.log10(abs(x)))
195+
# Note: math.log10(abs(x)) may be overestimated or underestimated,
196+
# but for simplicity, we do not compute the exact number of digits.
197+
max_digits = sys.get_int_max_str_digits()
198+
return (f'<{x.__class__.__name__} instance with roughly {k} '
199+
f'digits (limit at {max_digits}) at 0x{id(x):x}>')
185200
if len(s) > self.maxlong:
186201
i = max(0, (self.maxlong-3)//2)
187202
j = max(0, self.maxlong-3-i)

Lib/test/test_reprlib.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,38 @@ def test_frozenset(self):
151151
eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})")
152152

153153
def test_numbers(self):
154-
eq = self.assertEqual
155-
eq(r(123), repr(123))
156-
eq(r(123), repr(123))
157-
eq(r(1.0/3), repr(1.0/3))
158-
159-
n = 10**100
160-
expected = repr(n)[:18] + "..." + repr(n)[-19:]
161-
eq(r(n), expected)
154+
for x in [123, 1.0 / 3]:
155+
self.assertEqual(r(x), repr(x))
156+
157+
max_digits = sys.get_int_max_str_digits()
158+
for k in [100, max_digits - 1]:
159+
with self.subTest(f'10 ** {k}', k=k):
160+
n = 10 ** k
161+
expected = repr(n)[:18] + "..." + repr(n)[-19:]
162+
self.assertEqual(r(n), expected)
163+
164+
def re_msg(n, d):
165+
return (rf'<{n.__class__.__name__} instance with roughly {d} '
166+
rf'digits \(limit at {max_digits}\) at 0x[a-f0-9]+>')
167+
168+
k = max_digits
169+
with self.subTest(f'10 ** {k}', k=k):
170+
n = 10 ** k
171+
self.assertRaises(ValueError, repr, n)
172+
self.assertRegex(r(n), re_msg(n, k + 1))
173+
174+
for k in [max_digits + 1, 2 * max_digits]:
175+
self.assertGreater(k, 100)
176+
with self.subTest(f'10 ** {k}', k=k):
177+
n = 10 ** k
178+
self.assertRaises(ValueError, repr, n)
179+
self.assertRegex(r(n), re_msg(n, k + 1))
180+
with self.subTest(f'10 ** {k} - 1', k=k):
181+
n = 10 ** k - 1
182+
# Here, since math.log10(n) == math.log10(n-1),
183+
# the number of digits of n - 1 is overestimated.
184+
self.assertRaises(ValueError, repr, n)
185+
self.assertRegex(r(n), re_msg(n, k + 1))
162186

163187
def test_instance(self):
164188
eq = self.assertEqual
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :meth:`!reprlib.Repr.repr_int` when given integers with more than
2+
:func:`sys.g 31DF et_int_max_str_digits` digits. Patch by Bénédikt Tran.

0 commit comments

Comments
 (0)
0