Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 64559) +++ Objects/abstract.c (working copy) @@ -2915,6 +2915,24 @@ checker = PyObject_GetAttr(cls, name); if (checker == NULL && PyErr_Occurred()) PyErr_Clear(); + + /* Ignore the checker if it comes as an unbound method: + * we call it with 'inst' as first argument, which is wrong + * anyway, and leads to an infinite recursion because of the + * isinstance(self, cls) check. + * This may happen however when the class is actually a + * metaclass, as in + * isintance(x, abc.ABCMeta) + */ + if (checker && PyObject_TypeCheck(checker, &PyMethod_Type) && + PyMethod_GET_SELF(checker) == NULL) { + Py_DECREF(checker); + checker = PyObject_GetAttr((PyObject*)Py_TYPE(cls->ob_type), name); + if (checker == NULL && PyErr_Occurred()) + PyErr_Clear(); + Py_XINCREF(checker); + } + if (checker != NULL) { PyObject *res; int ok = -1; Index: Lib/test/test_typechecks.py =================================================================== --- Lib/test/test_typechecks.py (revision 64559) +++ Lib/test/test_typechecks.py (working copy) @@ -29,10 +29,6 @@ pass -class Evil: - def __instancecheck__(self, inst): return False - - class TypeChecksTest(unittest.TestCase): def testIsSubclassInternal(self): @@ -62,13 +58,23 @@ self.assertEqual(isinstance(SubInt(), SubInt), True) self.assertEqual(isinstance(42, SubInt), False) - def testInfiniteRecursionCaughtProperly(self): - e = Evil() - # This invokes isinstance() recursively, until the stack is exhausted. - self.assertRaises(RuntimeError, isinstance, e, Evil) - # XXX How to check the same situation for issubclass()? + def testUnboundCheckMethod(self): + class Class: + # Not a @classmethod: __instancecheck__ is not used + def __instancecheck__(self, inst): + raise ValueError("test failed") + self.assertEqual(isinstance(3, Class), False) + class SubInt2(Integer): + # Not a @classmethod: __instancecheck__ is not used + # its metaclass.__instancecheck__ is used + def __instancecheck__(self, inst): + raise ValueError("test failed") + + self.assertEqual(isinstance(3, SubInt2), False) + self.assertEqual(isinstance(SubInt2(), SubInt2), True) + def test_main(): test_support.run_unittest(TypeChecksTest)