GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — `str()` of an int with exactly `sys.get_int_max_str_digits()` digits raises `ValueError` when its leading digits are large · Issue #9797 · RustPython/RustPython

str() of an int with exactly sys.get_int_max_str_digits() digits raises ValueError when its leading digits are large #9797

New issue
Copy link
New issue
Copy link
Open
Open
str() of an int with exactly sys.get_int_max_str_digits() digits raises ValueError when its leading digits are large#9797
Copy link

Description

@taxor03
taxor03
opened on Nov 11, 2026
Issue body actions

Summary

Converting an int to a decimal string raises ValueError: Exceeds the limit (4300 digits) for integer string conversion for many ints that have exactly as many digits as the limit. CPython raises only when the result would have more digits than the limit. With the default limit of 4300, int() accepts any 4300-digit string, but str() of the result fails for every value from 2**14284 (about 8.17e4299) up, which is about the top 20% of 4300-digit values. So str(int(s)) does not round-trip for those values. With sys.set_int_max_str_digits(5000) the failures start at 2**16609 (about 6.4e4999), about 40% of 5000-digit values.

The same happens in repr(), f-strings, format(x, "d"), format(x, ","), "%d" % x and b"%d" % x, and for negative values. Smaller values with the same number of digits, like 2**14284 - 1, still convert, and so do all values with fewer digits than the limit.

The docs say: "The limit is applied to the number of digit characters in the input or output string ... When an operation would exceed the limit, a ValueError is raised".

Reproducer

import sys

print(sys.get_int_max_str_digits())   # the default limit, 4300
n = int("9" * 4300)                   # parsing 4300 digits is allowed
for x in (n, 2**14284 - 1, 2**14284):
    try:
        s = str(x)
        print("ok,", len(s), "digits, starts with", s[:4])
    except ValueError as e:
        print("ValueError:", e)

Expected

CPython 3.15.2 (same on 3.13.18 and 3.12.16):

4300
ok, 4300 digits, starts with 9999
ok, 4300 digits, starts with 8174
ok, 4300 digits, starts with 8174

Actual

RustPython main (dd8c343), same on a8bd43e and b66534d:

4300
ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit
ok, 4300 digits, starts with 8174
ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit

Cause

check_int_to_str_digits (int.rs#L831-L853), added in #7688, estimates the digit count from the bit length as bits * 30103 / 100_000 + 1 and raises whenever that estimate is over the limit. The estimate is an upper bound and is one too high for the larger values of each digit count. For example, 2**14284 has 14285 bits, so the estimate is 4301, but the value has 4300 digits. CPython also starts with a quick check, but that check only rejects values that are certainly too long. The real comparison is made against the exact length of the converted string (longobject.c#L2120-L2134, #L2207-L2217).

The value has either digits_upper or digits_upper - 1 digits, so one way to fix it is to raise right away only when digits_upper - 1 > limit. When digits_upper == limit + 1, compare exactly: raise only if abs(value) >= 10**limit. I tried this locally. It matched the exact rule (raise only when len(str(abs(x))) > limit) on 1,280 values around the boundary for limits 640, 1000, 4300, 5000 and 12345, and test_int still passes.

The existing tests do not catch this. test_max_str_digits_edge_cases only converts 10 ** (maxdigits - 1), the smallest value with that many digits, and the snippet in extra_tests/snippets/builtin_int.py uses 10**4001 (4002 digits) with a limit of 4000.

Drafted with help from Claude Code; I reviewed and checked it before posting.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.