Skip to content

Commit e5f03b9

Browse files
authored
gh-135487: fix reprlib.Repr.repr_int when given very large integers (#135506)
1 parent 15c6d63 commit e5f03b9

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.get_int_max_str_digits` digits. Patch by Bénédikt Tran.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy