Skip to content

Commit e131b7c

Browse files
committed
raise TypeError when __iter__ method is None
Setting special `__iter__` method to `None` is used to mark objects as non-iterable. https://docs.python.org/3/reference/datamodel.html#special-method-names Check if `__iter__` is set to `None` and raise TypeError exception.
1 parent 426019e commit e131b7c

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

Lib/test/test_typing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10916,7 +10916,6 @@ class TypeIterationTests(BaseTestCase):
1091610916
Annotated[T, ''],
1091710917
)
1091810918

10919-
@unittest.expectedFailure # TODO: RUSTPYTHON
1092010919
def test_cannot_iterate(self):
1092110920
expected_error_regex = "object is not iterable"
1092210921
for test_type in self._UNITERABLE_TYPES:

crates/vm/src/types/slot.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::common::lock::{
22
PyMappedRwLockReadGuard, PyMappedRwLockWriteGuard, PyRwLockReadGuard, PyRwLockWriteGuard,
33
};
4+
use crate::vm::PyMethod;
45
use crate::{
56
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
67
builtins::{PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyTypeRef},
@@ -534,7 +535,30 @@ pub(crate) fn richcompare_wrapper(
534535
}
535536

536537
fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
537-
vm.call_special_method(&zelf, identifier!(vm, __iter__), ())
538+
fn method_is_none(method: &PyMethod, vm: &VirtualMachine) -> bool {
539+
match method {
540+
PyMethod::Attribute(meth) => vm.is_none(meth),
541+
_ => false,
542+
}
543+
}
544+
545+
//
546+
// look-up '__iter__' method
547+
//
548+
let method_ident = identifier!(vm, __iter__);
549+
let method = vm
550+
.get_special_method(&zelf, method_ident)?
551+
.ok_or_else(|| vm.new_attribute_error(method_ident.as_str().to_owned()))?;
552+
553+
//
554+
// setting '__iter__' method to 'None' value is used
555+
// to mark non-iterable objects, raise TypeError
556+
//
557+
if method_is_none(&method, vm) {
558+
return Err(vm.new_type_error(format!("'{}' object is not iterable", zelf.class().name())));
559+
}
560+
561+
method.invoke((), vm)
538562
}
539563

540564
fn bool_wrapper(num: PyNumber<'_>, vm: &VirtualMachine) -> PyResult<bool> {

0 commit comments

Comments
 (0)