Commit Graph
2 Commits
Author SHA1 Message Date
Jeongseop Lim 95686c08e4 Accept __index__ for the remaining int-bound arguments (#8999)
#8828 made bin(), chr() and several other arguments that were bound
as PyIntRef go through __index__, but these still downcast to int and
reject an object that only defines __index__: the start and end of the
str/bytes/bytearray find family, enumerate(start=),
itertools.combinations/combinations_with_replacement/batched,
_thread.stack_size, resource.getrlimit/setrlimit, pwd.getpwuid,
grp.getgrgid, fcntl.fcntl/lockf and mmap.move/madvise. CPython converts
all of them with _PyNumber_Index or _PyEval_SliceIndex.

Bind them as ArgIndex, as #8828 did for the others.

test_mmap.test_madvise and test_mmap_closed_by_int_scenarios now pass,
so drop their expectedFailure markers.

Assisted-by: Claude Code:claude-opus-5-5
2026-10-07 23:32:59 +09:00
Jeong, YunWonandRoshan Ramani 5c875d322f Call __index__ in default integer argument conversion (#8828)
* Accept `__index__` objects for integer arguments

CPython converts these nine arguments with `__index__`, RustPython
required an exact `int`. Uses the existing `ArgSize`/`ArgPrimitiveIndex`
converters at each call site rather than widening the blanket `int`
conversion, so argument paths CPython keeps strict (ctypes pointers,
thread handles) are unaffected, and the range check happens while the
argument is bound rather than in the method body.

Also widens `maxsplit` before adding one. `sys.maxsize` was already
reachable there with a plain `int` and overflowed in a debug build.

Assisted-by: Claude Code:claude-opus-5

* Add snippet for `__index__` argument conversion

Expectations verified against CPython 3.14.

Assisted-by: Claude Code:claude-opus-5

* Call __index__ in primitive integer conversion; add ArgStrictInt

The TryFromObject impls for isize, usize and the fixed-width integer
types now take an int (or subclass) as-is and otherwise call __index__,
instead of accepting only int instances.

ArgStrictInt<T> keeps the old int-only conversion. The ctypes address
and handle arguments (from_address, PyObj_FromPtr, dlsym, dlclose,
call_function, call_cdeclfunction, non-Windows FreeLibrary) use it.
_thread._make_thread_handle checks for an int itself and raises
"ident must be an integer".

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7

* Accept __index__ where arguments were bound as int objects

chr, bin, math.factorial, zlib.crc32/adler32, binascii.crc32/crc_hqx,
the start/stop of sequence index(), the select event mask and a
__len__ result took an int object directly and rejected other objects
with __index__. They now go through __index__.

math.ldexp still accepts only an int for its exponent and raises
"Expected an int as second argument to ldexp." otherwise.

Extend protocol_index_argument.py with the newly accepted calls, an int
subclass whose __index__ is not called, and the sites that still
reject __index__.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7

* Replace ArgPrimitiveIndex and ArgSize with PySsize/PySize aliases

The primitive integer conversions call __index__ themselves, so
ArgPrimitiveIndex<T> and its alias ArgSize behaved the same as T. They
are removed. Arguments that used ArgSize or ArgPrimitiveIndex<isize>
now take PySsize (= isize), ArgPrimitiveIndex<usize> takes PySize
(= usize), and the other ArgPrimitiveIndex<T> take T. Those with a
literal fallback take it as a `default`; those where a missing argument
is a distinct state stay OptionalArg.

list.insert is a #[pymethod] again instead of going through a wrapper.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7

---------

Co-authored-by: Roshan Ramani <roshanramani.dev@gmail.com>
2026-09-27 01:22:19 +09:00