Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Doc/library/reprlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ which format specific object types.


.. method:: Repr.repr_TYPE(obj, level)
:noindex:

Formatting methods for specific types are implemented as methods with a name
based on the type name. In the method name, **TYPE** is replaced by
Expand Down
18 changes: 17 additions & 1 deletion Lib/reprlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,23 @@ def repr_str(self, x, level):
return s

def repr_int(self, x, level):
s = builtins.repr(x) # XXX Hope this isn't too slow...
try:
s = builtins.repr(x)
except ValueError as exc:
assert 'sys.set_int_max_str_digits()' in str(exc)
# Those imports must be deferred due to Python's build system
# where the reprlib module is imported before the math module.
import math, sys
# Integers with more than sys.get_int_max_str_digits() digits
# are rendered differently as their repr() raises a ValueError.
# See https://github.com/python/cpython/issues/135487.
k = 1 + int(math.log10(abs(x)))
# When math.log10(abs(x)) is overestimated or underestimated,
# the number of digits should be k - 1 or k + 1 respectively.
# For simplicity, we do not compute the exact number of digits.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can differ more than by 1 for large numbers with more than 2**53 digits. Yes, it will take long time (years?) to calculate the decimal digits, but let be more future proof.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I actually didn't consider the possibility of having 2**53 digits...

max_digits = sys.get_int_max_str_digits()
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)
Expand Down
40 changes: 32 additions & 8 deletions Lib/test/test_reprlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,38 @@ def test_frozenset(self):
eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})")

def test_numbers(self):
eq = self.assertEqual
eq(r(123), repr(123))
eq(r(123), repr(123))
eq(r(1.0/3), repr(1.0/3))

n = 10**100
expected = repr(n)[:18] + "..." + repr(n)[-19:]
eq(r(n), expected)
for x in [123, 1.0 / 3]:
self.assertEqual(r(x), repr(x))

max_digits = sys.get_int_max_str_digits()
for k in [100, max_digits - 1]:
with self.subTest(f'10 ** {k}', k=k):
n = 10 ** k
expected = repr(n)[:18] + "..." + repr(n)[-19:]
self.assertEqual(r(n), expected)

def re_msg(n, d):
return (rf'<{n.__class__.__name__} instance with roughly {d} '
rf'digits \(limit at {max_digits}\) at 0x[a-f0-9]+>')

k = max_digits
with self.subTest(f'10 ** {k}', k=k):
n = 10 ** k
self.assertRaises(ValueError, repr, n)
self.assertRegex(r(n), re_msg(n, k + 1))

for k in [max_digits + 1, 2 * max_digits]:
self.assertGreater(k, 100)
with self.subTest(f'10 ** {k}', k=k):
n = 10 ** k
self.assertRaises(ValueError, repr, n)
self.assertRegex(r(n), re_msg(n, k + 1))
with self.subTest(f'10 ** {k} - 1', k=k):
n = 10 ** k - 1
# For k >> 1, since math.log10(n) == math.log10(n-1),
# the number of digits of n - 1 is overestimated.
self.assertRaises(ValueError, repr, n)
self.assertRegex(r(n), re_msg(n, k + 1))

def test_instance(self):
eq = self.assertEqual
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :meth:`reprlib.Repr.repr_int <reprlib.Repr.repr_TYPE>` when given
integers with more than :func:`sys.get_int_max_str_digits` digits. Patch by
Bénédikt Tran.
Loading