Skip to content

Commit 4ac21bb

Browse files
committed
fix reprlib.Repr.repr_int
1 parent c8319a3 commit 4ac21bb

File tree

4 files changed

+52
-10
lines changed

4 files changed

+52
-10
lines changed

Doc/library/reprlib.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ which format specific object types.
219219

220220

221221
.. method:: Repr.repr_TYPE(obj, level)
222-
:noindex:
223222

224223
Formatting methods for specific types are implemented as methods with a name
225224
based on the type name. In the method name, **TYPE** is replaced by

Lib/reprlib.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,23 @@ 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+
# When math.log10(abs(x)) is overestimated or underestimated,
196+
# the number of digits should be k - 1 or k + 1 respectively.
197+
# For simplicity, we do not compute the exact number of digits.
198+
max_digits = sys.get_int_max_str_digits()
199+
return (f'<{x.__class__.__name__} instance with roughly {k} '
200+
f'digits (limit at {max_digits}) at 0x{id(x):x}>')
185201
if len(s) > self.maxlong:
186202
i = max(0, (self.maxlong-3)//2)
187203
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+
# For k >> 1, 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :meth:`reprlib.Repr.repr_int <reprlib.Repr.repr_TYPE>` when given
2+
integers with more than :func:`sys.get_int_max_str_digits` digits. Patch by
3+
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