* Unskip passing flaky CPython tests
Remove RUSTPYTHON skip overlays after Linux release repeats passed
for enum, threading, logging, subprocess, socket, int, re, strtod,
and regrtest cases.
Assisted-by: Grok:4.6
* Fix fork-child SIGSEGV and yield-from throw args
Forget JoinHandle of threads that did not survive fork instead
of dropping them. Zero-reinit the import lock and condvars in
the child rather than unlock/notify. Resume the world if
os.fork() fails.
Call a yield-from subiterator throw() without None fillers so
a 1-arg throw stays 1-arg.
Drop the stale Windows expectedFailure on logging queue config
and unskip test_reinit_tls_after_fork plus the asyncio
local_addr family test.
Assisted-by: Grok:4.6
* Restore import lock depth after fork; add WASI clock info
Zeroing IMP_LOCK in the child discarded its recursion count, so
imp.release_lock() raised and test_fork1 exited 1. Re-acquire the
saved depth, then drop the extra pre-fork hold.
Expose time.get_clock_info on WASI via clock_getres so test_int
Stopwatch can run.
Unskip lock_tests test_acquire_contended and test_thread_leak.
Assisted-by: Grok:4.6
* Honor chmod follow_symlinks=False via fchmodat
Linux chmod followed the symlink, so dangling links raised
FileNotFoundError instead of NotImplementedError. Use fchmodat
with AT_SYMLINK_NOFOLLOW and map ENOTSUP to NotImplementedError.
Unskip httpservers truncated Content-Length (CPython already
skips as root) and tempfile symlink-mode cleanup on Linux.
Assisted-by: Grok:4.6
* Unskip httplib local bad-hostname HTTPS test
The skip was leftover. With default ssl-rustls the test passes
under -W error on Linux.
Assisted-by: Grok:4.6
* Fix list cmp deadlock, wasm digit overflow, REPL prompt
Do not hold list/deque locks across item comparison callbacks.
Compute int-to-str digit bounds in u64 so the check cannot wrap
on wasm32. Snapshot set contents when list.extend copies a set.
For a non-TTY stdin, write the REPL prompt to stderr and read
lines from stdin. Flush stdout/stderr after each interactive
command. Set sys.ps1/ps2 to ">>> " and "... ".
Unskip list mutation compares, asyncio all_tasks race, importlib
deadlock/parallel/circular-import tests, and REPL stdout flush.
Assisted-by: Grok:4.6
* Avoid unnecessary u64 cast in int-to-str digit check
bits() is already u64, so `bits as u64` fails clippy
unnecessary_cast under -Dwarnings.
Assisted-by: Grok:4.6
* Accept Unicode decimal digits in int(), Decimal() and complex()
CPython runs a string argument through
_PyUnicode_TransformDecimalAndSpaceToASCII before parsing it, so decimal
digits from any script are accepted:
int('١٢٣') # 123
int('0x١f', 16) # 31
Decimal('١٢٣') # Decimal('123')
complex('1+2j') # (1+2j)
RustPython only did this for float(), which had the transform inlined.
int() handed the raw UTF-8 bytes to bytes_to_int(), whose digit check is
is_ascii_alphanumeric(), so every non-ASCII digit was rejected — even
though float() accepted the same string.
Lift the inlined transform out of float_from_string() into
common::str::transform_decimal_and_space_to_ascii() and apply it to the
str paths of int() and complex() too. The result is always ASCII: as in
CPython, a character that is neither ASCII, whitespace nor a decimal
digit becomes '?' and truncates the string, which no parser accepts at
any base, leaving the caller to raise the error from the original string.
Bytes-like input keeps going straight to the parser, matching CPython's
split between PyLong_FromUnicodeObject and PyLong_FromString.
This unmarks two expectedFailure tests: test_int.test_unicode and
test_decimal.test_unicode_digits.
* Share one PyStr-to-numeric-literal step across int, float and complex
All three constructors need the same thing from a str argument: trim it,
fold Unicode decimal digits and whitespace to ASCII, and give up on a
string holding surrogates. Each expressed that last part differently —
float matched PyKindStr and returned b"", complex leaned on to_str()
returning None, int returned an empty Cow — so the rule lived in three
places at once.
Move it into protocol::numeric_literal_from_str() and have all three call
it. CPython repeats this per type because its wrapper is three lines over
a single PyUnicode representation; ours has to match over Ascii/Utf8/Wtf8,
which is worth writing once.
Only the shared step moves. int keeps its base handling, int and float
keep accepting bytes-like input, complex keeps rejecting it, and each
keeps raising its own error, because none of that is shared.
No behavior change: the CPython differential suite is byte-identical
before and after.
* Drop the now-empty test_unicode_digits override in test_decimal
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
CPython 3.14 fully removed the long-deprecated fallback from int() to
__trunc__. Classes that want int(x) support must implement __int__ or
__index__; math.trunc(x) continues to use __trunc__.
Delete the __trunc__ branch in PyObject::try_int so a class with only
__trunc__ now reaches the existing TypeError arm, matching CPython.
Unmasks test_int.IntTestCases.test_intconversion.
* Enforce int_max_str_digits on int-to-str conversions
The str-to-int direction already enforced sys.get_int_max_str_digits()
via bytes_to_int; the int-to-str direction did not. CPython 3.14 enforces
both per PEP 644.
Adds check_int_to_str_digits helper in builtins::int (bit-count fast path
+ digit upper-bound from log10(2)), wired into the four Python-level
entry points: repr, the str fast path in protocol::object, int.__format__
(decimal/n/empty spec only — binary bases x/o/b are exempt per CPython),
and the DecimalD/I/U branches of vm::cformat for both str % and bytes %.
Unmasks 8 expectedFailure tests across test_int (max_str_digits, DoS
prevention, int_from_other_bases — each mirrored in IntSubclass),
test_ast (test_repr_large_input_crash) and test_reprlib (test_numbers).
Boundary cases (4299/4300/4301 digits at limit=4300) match CPython 3.14.4.
* Skip int-to-str DoS test on platforms without time.get_clock_info
The test_denial_of_service_prevented_int_to_str regression test uses
support.Stopwatch, which calls time.get_clock_info('monotonic'). In
RustPython that function is gated to unix/windows targets only, so on
wasm32-wasip1 it surfaces as AttributeError and breaks the wasm-wasi CI.
Guard the test with skipUnless(hasattr(time, 'get_clock_info'), ...) so
it runs everywhere it can and is skipped on wasm.
Also narrow is_decimal_int_format to Number(Case::Lower): 'N' is rejected
by format_int as UnknownFormatCode, so excluding it preserves that error
path instead of intercepting it with the digit-limit check.
* Add TODO: RUSTPYTHON marker to skipUnless reason
scripts/update_lib uses TODO: RUSTPYTHON markers inside unittest
decorator reason strings to identify and migrate custom RustPython
patches across CPython library updates.
* Use expectedFailureIf for wasm get_clock_info gap
skipUnless silently hides the test forever; expectedFailureIf surfaces
unexpected success once RustPython implements time.get_clock_info on
wasm, prompting marker removal.