Skip to content

Item assignment and deletion on a tuple or str raise TypeError before calling the key's __index__ #9510

Closed

Description

@jseop-lim

Feature

Assigning to or deleting an item of a tuple, str, bytes or range raises TypeError in RustPython without calling the key's __index__, but CPython calls __index__ first, so an exception from it propagates.

Reproduction

class RaisingIndex:
    def __index__(self):
        raise ZeroDivisionError

t = ()
t[RaisingIndex()] = 0

RustPython:

TypeError: 'tuple' object does not support item assignment

CPython:

ZeroDivisionError

del t[RaisingIndex()], operator.setitem(), operator.delitem() and instances of a class without __setitem__ or __delitem__ diverge the same way.

Root cause

PyObject::set_item and PyObject::del_item convert the key only when the type has an ass_item slot and otherwise raise TypeError straight away. CPython's PyObject_SetItem and PyObject_DelItem convert an __index__ key whenever the type has a sequence table, and only then does PySequence_SetItem or PySequence_DelItem refuse the operation.

Fix

When the type has a sequence table (the has_any() || heaptype_ext() test del_item already uses for its message) and the key has __index__, convert the key to isize before raising the TypeError, raising IndexError for a value that does not fit, as PyNumber_AsSsize_t(key, PyExc_IndexError) does.

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 PyObject_SetItem: Objects/abstract.c#L250-L265 converts an index key before the assignment is refused:

    if (Py_TYPE(o)->tp_as_sequence) {
        if (_PyIndex_Check(key)) {
            Py_ssize_t key_value;
            key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
            if (key_value == -1 && PyErr_Occurred())
                return -1;
            return PySequence_SetItem(o, key_value, value);
        }
  • CPython PyObject_DelItem: Objects/abstract.c#L284-L299 does the same before PySequence_DelItem.

  • Documentation: object.__index__

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