Fix error checking done by abstract_issubclass and abstract_isinstance.

isinstance() now allows any object as the first argument and a class, a
type or something with a __bases__ tuple attribute for the second
argument.  This closes SF patch #464992.
This commit is contained in:
Neil Schemenauer 2001-10-18 03:18:43 +00:00
parent 9f6c37df26
commit 6b47129424
1 changed files with 62 additions and 45 deletions

View File

@ -1740,45 +1740,46 @@ PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
/* isinstance(), issubclass() */ /* isinstance(), issubclass() */
static int static PyObject *
abstract_issubclass(PyObject *derived, PyObject *cls, int first) abstract_get_bases(PyObject *cls)
{ {
static PyObject *__bases__ = NULL; static PyObject *__bases__ = NULL;
PyObject *bases; PyObject *bases;
int i, n;
int r = 0;
if (__bases__ == NULL) { if (__bases__ == NULL) {
__bases__ = PyString_FromString("__bases__"); __bases__ = PyString_FromString("__bases__");
if (__bases__ == NULL) if (__bases__ == NULL)
return -1; return NULL;
} }
if (first) { bases = PyObject_GetAttr(cls, __bases__);
bases = PyObject_GetAttr(cls, __bases__); if (bases == NULL || !PyTuple_Check(bases)) {
if (bases == NULL || !PyTuple_Check(bases)) { Py_XDECREF(bases);
Py_XDECREF(bases); return NULL;
PyErr_SetString(PyExc_TypeError,
"issubclass() arg 2 must be a class");
return -1;
}
Py_DECREF(bases);
} }
return bases;
}
static int
abstract_issubclass(PyObject *derived, PyObject *cls)
{
PyObject *bases;
int i, n;
int r = 0;
if (derived == cls) if (derived == cls)
return 1; return 1;
bases = PyObject_GetAttr(derived, __bases__); bases = abstract_get_bases(derived);
if (bases == NULL || !PyTuple_Check(bases)) { if (bases == NULL)
Py_XDECREF(bases); return 0;
PyErr_SetString(PyExc_TypeError,
"issubclass() arg 1 must be a class");
return -1;
}
n = PyTuple_GET_SIZE(bases); n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls, 0); r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls);
if (r != 0) if (r != 0)
break; break;
} }
@ -1795,12 +1796,10 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
static PyObject *__class__ = NULL; static PyObject *__class__ = NULL;
int retval = 0; int retval = 0;
if (PyClass_Check(cls)) { if (PyClass_Check(cls) && PyInstance_Check(inst)) {
if (PyInstance_Check(inst)) { PyObject *inclass =
PyObject *inclass = (PyObject*)((PyInstanceObject*)inst)->in_class;
(PyObject*)((PyInstanceObject*)inst)->in_class; retval = PyClass_IsSubclass(inclass, cls);
retval = PyClass_IsSubclass(inclass, cls);
}
} }
else if (PyType_Check(cls)) { else if (PyType_Check(cls)) {
retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
@ -1819,31 +1818,30 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
} }
return retval; return retval;
} }
else if (!PyInstance_Check(inst)) { else {
PyObject *cls_bases = abstract_get_bases(cls);
if (cls_bases == NULL) {
PyErr_SetString(PyExc_TypeError,
"isinstance() arg 2 must be a class or type");
return -1;
}
Py_DECREF(cls_bases);
if (__class__ == NULL) { if (__class__ == NULL) {
__class__ = PyString_FromString("__class__"); __class__ = PyString_FromString("__class__");
if (__class__ == NULL) if (__class__ == NULL)
return -1; return -1;
} }
icls = PyObject_GetAttr(inst, __class__); icls = PyObject_GetAttr(inst, __class__);
if (icls != NULL) { if (icls == NULL) {
retval = abstract_issubclass(icls, cls, 1); PyErr_Clear();
Py_DECREF(icls); retval = 0;
if (retval < 0 && }
!PyErr_ExceptionMatches(PyExc_TypeError)) else {
return -1; retval = abstract_issubclass(icls, cls);
Py_DECREF(icls);
} }
else
retval = -1;
} }
else
retval = -1;
if (retval < 0) {
PyErr_SetString(PyExc_TypeError,
"isinstance() arg 2 must be a class or type "
"or tuple of those");
}
return retval; return retval;
} }
@ -1853,7 +1851,26 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
int retval; int retval;
if (!PyClass_Check(derived) || !PyClass_Check(cls)) { if (!PyClass_Check(derived) || !PyClass_Check(cls)) {
retval = abstract_issubclass(derived, cls, 1); PyObject *derived_bases;
PyObject *cls_bases;
derived_bases = abstract_get_bases(derived);
if (derived_bases == NULL) {
PyErr_SetString(PyExc_TypeError,
"issubclass() arg 1 must be a class");
return -1;
}
Py_DECREF(derived_bases);
cls_bases = abstract_get_bases(cls);
if (cls_bases == NULL) {
PyErr_SetString(PyExc_TypeError,
"issubclass() arg 2 must be a class");
return -1;
}
Py_DECREF(cls_bases);
retval = abstract_issubclass(derived, cls);
} }
else { else {
/* shortcut */ /* shortcut */