Skip to content

operator.length_hint() rejects a negative default and a default that defines __index__ #9509

Closed

Description

@jseop-lim

Feature

operator.length_hint(obj, default) raises in RustPython when default is negative or is not an int instance, but CPython accepts any default with __index__ and returns a negative one as-is.

Reproduction

import operator

print(operator.length_hint(object(), -1))

RustPython:

ValueError: can't convert negative number to unsigned

CPython:

-1

A default with __index__ is refused as well: operator.length_hint(object(), Index()) raises TypeError: 'Index' object cannot be interpreted as an integer where CPython returns the __index__ value, and an exception raised inside that __index__ is replaced by the same TypeError.

Root cause

length_hint accepts default only as an int instance and converts it to usize, and PyObject::length_hint takes a usize default as well. CPython converts default to Py_ssize_t with _PyNumber_Index, so any object with __index__ and any negative value are accepted, and PyObject_LengthHint returns the default unchanged when there is no hint.

Fix

Bind default as isize, whose conversion calls __index__, and return vm.length_hint_opt(obj)?.map_or(default, |hint| hint as isize).

Environment

  • RustPython 713e14c (0.6.1, macOS arm64), also reproduced on 0.4.0
  • CPython v3.15.2, v3.14.4 and v3.12.10 (macOS arm64)

Python Documentation or reference to CPython source code

  • CPython _operator_length_hint: Modules/clinic/_operator.c.h#L1448-L1461 converts default with _PyNumber_Index into a signed Py_ssize_t:

    {
        Py_ssize_t ival = -1;
        PyObject *iobj = _PyNumber_Index(args[1]);
        if (iobj != NULL) {
            ival = PyLong_AsSsize_t(iobj);
            Py_DECREF(iobj);
        }
        if (ival == -1 && PyErr_Occurred()) {
            goto exit;
        }
        default_value = ival;
    }
    skip_optional:
    _return_value = _operator_length_hint_impl(module, obj, default_value);
  • Documentation: operator.length_hint

AI disclosure: this report was drafted with Claude Code (claude-opus-5-5) and reviewed by me before submission. The divergences were found by differential testing against CPython, checked against CPython 3.15.2, and every source reference above was checked against the linked revisions.

Activity

  1. added
    C-compatA discrepancy between RustPython and CPython
    on Nov 1, 2026
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

    C-compatA discrepancy between RustPython and CPython

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions