mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-40824: Do not mask errors in __iter__ in "in" and the operator module. (GH-20537)
Unexpected errors in calling the __iter__ method are no longer masked by TypeError in the "in" operator and functions operator.contains(), operator.indexOf() and operator.countOf().
This commit is contained in:
parent
4901ea9526
commit
cafe1b6e9d
4 changed files with 21 additions and 1 deletions
|
@ -76,6 +76,10 @@ class NoIterClass:
|
||||||
return i
|
return i
|
||||||
__iter__ = None
|
__iter__ = None
|
||||||
|
|
||||||
|
class BadIterableClass:
|
||||||
|
def __iter__(self):
|
||||||
|
raise ZeroDivisionError
|
||||||
|
|
||||||
# Main test suite
|
# Main test suite
|
||||||
|
|
||||||
class TestCase(unittest.TestCase):
|
class TestCase(unittest.TestCase):
|
||||||
|
@ -658,6 +662,7 @@ class TestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertRaises(TypeError, lambda: 3 in 12)
|
self.assertRaises(TypeError, lambda: 3 in 12)
|
||||||
self.assertRaises(TypeError, lambda: 3 not in map)
|
self.assertRaises(TypeError, lambda: 3 not in map)
|
||||||
|
self.assertRaises(ZeroDivisionError, lambda: 3 in BadIterableClass())
|
||||||
|
|
||||||
d = {"one": 1, "two": 2, "three": 3, 1j: 2j}
|
d = {"one": 1, "two": 2, "three": 3, 1j: 2j}
|
||||||
for k in d:
|
for k in d:
|
||||||
|
@ -740,6 +745,7 @@ class TestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertRaises(TypeError, indexOf, 42, 1)
|
self.assertRaises(TypeError, indexOf, 42, 1)
|
||||||
self.assertRaises(TypeError, indexOf, indexOf, indexOf)
|
self.assertRaises(TypeError, indexOf, indexOf, indexOf)
|
||||||
|
self.assertRaises(ZeroDivisionError, indexOf, BadIterableClass(), 1)
|
||||||
|
|
||||||
f = open(TESTFN, "w")
|
f = open(TESTFN, "w")
|
||||||
try:
|
try:
|
||||||
|
@ -1027,6 +1033,7 @@ class TestCase(unittest.TestCase):
|
||||||
def test_error_iter(self):
|
def test_error_iter(self):
|
||||||
for typ in (DefaultIterClass, NoIterClass):
|
for typ in (DefaultIterClass, NoIterClass):
|
||||||
self.assertRaises(TypeError, iter, typ())
|
self.assertRaises(TypeError, iter, typ())
|
||||||
|
self.assertRaises(ZeroDivisionError, iter, BadIterableClass())
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
|
|
|
@ -35,6 +35,10 @@ class Seq2(object):
|
||||||
def __rmul__(self, other):
|
def __rmul__(self, other):
|
||||||
return other * self.lst
|
return other * self.lst
|
||||||
|
|
||||||
|
class BadIterable:
|
||||||
|
def __iter__(self):
|
||||||
|
raise ZeroDivisionError
|
||||||
|
|
||||||
|
|
||||||
class OperatorTestCase:
|
class OperatorTestCase:
|
||||||
def test_lt(self):
|
def test_lt(self):
|
||||||
|
@ -142,6 +146,7 @@ class OperatorTestCase:
|
||||||
operator = self.module
|
operator = self.module
|
||||||
self.assertRaises(TypeError, operator.countOf)
|
self.assertRaises(TypeError, operator.countOf)
|
||||||
self.assertRaises(TypeError, operator.countOf, None, None)
|
self.assertRaises(TypeError, operator.countOf, None, None)
|
||||||
|
self.assertRaises(ZeroDivisionError, operator.countOf, BadIterable(), 1)
|
||||||
self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 3), 1)
|
self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 3), 1)
|
||||||
self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 5), 0)
|
self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 5), 0)
|
||||||
|
|
||||||
|
@ -176,6 +181,7 @@ class OperatorTestCase:
|
||||||
operator = self.module
|
operator = self.module
|
||||||
self.assertRaises(TypeError, operator.indexOf)
|
self.assertRaises(TypeError, operator.indexOf)
|
||||||
self.assertRaises(TypeError, operator.indexOf, None, None)
|
self.assertRaises(TypeError, operator.indexOf, None, None)
|
||||||
|
self.assertRaises(ZeroDivisionError, operator.indexOf, BadIterable(), 1)
|
||||||
self.assertEqual(operator.indexOf([4, 3, 2, 1], 3), 1)
|
self.assertEqual(operator.indexOf([4, 3, 2, 1], 3), 1)
|
||||||
self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0)
|
self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0)
|
||||||
|
|
||||||
|
@ -258,6 +264,7 @@ class OperatorTestCase:
|
||||||
operator = self.module
|
operator = self.module
|
||||||
self.assertRaises(TypeError, operator.contains)
|
self.assertRaises(TypeError, operator.contains)
|
||||||
self.assertRaises(TypeError, operator.contains, None, None)
|
self.assertRaises(TypeError, operator.contains, None, None)
|
||||||
|
self.assertRaises(ZeroDivisionError, operator.contains, BadIterable(), 1)
|
||||||
self.assertTrue(operator.contains(range(4), 2))
|
self.assertTrue(operator.contains(range(4), 2))
|
||||||
self.assertFalse(operator.contains(range(4), 5))
|
self.assertFalse(operator.contains(range(4), 5))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Unexpected errors in calling the ``__iter__`` method are no longer masked by
|
||||||
|
``TypeError`` in the :keyword:`in` operator and functions
|
||||||
|
:func:`~operator.contains`, :func:`~operator.indexOf` and
|
||||||
|
:func:`~operator.countOf` of the :mod:`operator` module.
|
|
@ -2083,7 +2083,9 @@ _PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation)
|
||||||
|
|
||||||
it = PyObject_GetIter(seq);
|
it = PyObject_GetIter(seq);
|
||||||
if (it == NULL) {
|
if (it == NULL) {
|
||||||
type_error("argument of type '%.200s' is not iterable", seq);
|
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
|
||||||
|
type_error("argument of type '%.200s' is not iterable", seq);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue