◐ Shell
clean mode source ↗

raise TypeError when `__iter__` method is `None` by elmjag · Pull Request #7092 · RustPython/RustPython

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify what error CPython raises when __iter__ is dynamically deleted after being set
# Also check how get_special_method works and what it returns for None vs missing

echo "=== Check get_special_method implementation ==="
ast-grep --pattern 'fn get_special_method($$$) {
  $$$
}'

echo ""
echo "=== Look for get_special_method definition ==="
rg -n 'fn get_special_method' crates/vm/src/ -A 20 | head -50

Repository: RustPython/RustPython

Length of output: 1467


🏁 Script executed:

#!/bin/bash
echo "=== Check iter_wrapper and surrounding context in slot.rs ==="
rg -n 'iter_wrapper\|__iter__' crates/vm/src/types/slot.rs -B 5 -A 10

Repository: RustPython/RustPython

Length of output: 126


🏁 Script executed:

#!/bin/bash
echo "=== Check how other slot wrappers handle missing methods ==="
rg -n 'new_attribute_error|new_type_error' crates/vm/src/types/slot.rs -B 3 -A 1 | head -100

Repository: RustPython/RustPython

Length of output: 4724


🏁 Script executed:

#!/bin/bash
echo "=== Check if there are references to 'not iterable' error messages ==="
rg -n 'not iterable' crates/vm/src/ -B 2 -A 2

Repository: RustPython/RustPython

Length of output: 1234


🏁 Script executed:

#!/bin/bash
echo "=== Check get_special_method behavior in the codebase ==="
rg -n 'get_special_method.*ok_or' crates/vm/src/ -B 3 -A 3 | head -60

Repository: RustPython/RustPython

Length of output: 122


Change error type from AttributeError to TypeError when __iter__ is missing.

The code at line 551 currently raises AttributeError when get_special_method returns None (i.e., when __iter__ is not found). This is inconsistent with CPython, which raises TypeError: '<ClassName>' object is not iterable. This error type also aligns with how other slot wrappers in the codebase handle missing methods—len_wrapper, repr_wrapper, str_wrapper, and others all use new_type_error() for similar cases.

The method_is_none() check at line 557 handles the case where __iter__ exists but returns None, which should also raise the same TypeError (already correct).

Proposed fix
     let method_ident = identifier!(vm, __iter__);
     let method = vm
         .get_special_method(&zelf, method_ident)?
-        .ok_or_else(|| vm.new_attribute_error(method_ident.as_str().to_owned()))?;
+        .ok_or_else(|| vm.new_type_error(format!("'{}' object is not iterable", zelf.class().name())))?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

let method_ident = identifier!(vm, __iter__);
let method = vm
.get_special_method(&zelf, method_ident)?
.ok_or_else(|| vm.new_attribute_error(method_ident.as_str().to_owned()))?;
let method_ident = identifier!(vm, __iter__);
let method = vm
.get_special_method(&zelf, method_ident)?
.ok_or_else(|| vm.new_type_error(format!("'{}' object is not iterable", zelf.class().name())))?;
🤖 Prompt for AI Agents
In `@crates/vm/src/types/slot.rs` around lines 548 - 551, Replace the
AttributeError raised when __iter__ is missing with a TypeError: in the block
that calls vm.get_special_method(&zelf, identifier!(vm, __iter__)), change the
ok_or_else(...) from vm.new_attribute_error(...) to vm.new_type_error(...) and
construct the message as "'<ClassName>' object is not iterable" using the
object's class name (e.g., format!("'{}' object is not iterable",
zelf.class().name())). Keep the existing method_is_none() TypeError behavior
unchanged.