Skip to content

Commit 04ffa38

Browse files
Match CPython's "argument of type ... is not a container or iterable" wording (RustPython#7714)
CPython's PySequence_Contains (Objects/abstract.c::_PySequence_IterSearch) catches the TypeError from PyObject_GetIter when neither __contains__ nor __iter__ is available, and re-raises with membership-test wording. RustPython's PySequence::contains propagated the get_iter error verbatim, so '1 in obj' produced 'X' object is not iterable — a literal but less specific message. Wrap the get_iter call in map_err: when the failure is a TypeError, re-raise with byte-identical CPython wording. Other exception types pass through unchanged. Unmasks test_contains.TestContains.test_common_tests.
1 parent ba2b619 commit 04ffa38

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

Lib/test/test_contains.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ def __getitem__(self, n):
1616
return [self.el][n]
1717

1818
class TestContains(unittest.TestCase):
19-
@unittest.expectedFailure # TODO: RUSTPYTHON; Wrong error message
2019
def test_common_tests(self):
2120
a = base_set(1)
2221
b = myset(1)

crates/vm/src/protocol/sequence.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
2+
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
33
builtins::{PyList, PyListRef, PySlice, PyTuple, PyTupleRef},
44
convert::ToPyObject,
55
function::PyArithmeticValue,
@@ -398,7 +398,19 @@ impl PySequence<'_> {
398398
return f(self, target, vm);
399399
}
400400

401-
let iter = self.obj.to_owned().get_iter(vm)?;
401+
// CPython parity: when neither __contains__ nor __iter__ is available,
402+
// `PySequence_Contains` rewords the get_iter TypeError into the
403+
// membership-test wording. Other exception types propagate unchanged.
404+
let iter = self.obj.to_owned().get_iter(vm).map_err(|e| {
405+
if e.fast_isinstance(vm.ctx.exceptions.type_error) {
406+
vm.new_type_error(format!(
407+
"argument of type '{}' is not a container or iterable",
408+
self.obj.class().name()
409+
))
410+
} else {
411+
e
412+
}
413+
})?;
402414
let iter = iter.iter::<PyObjectRef>(vm)?;
403415

404416
for elem in iter {

0 commit comments

Comments
 (0)