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:
parent
9f6c37df26
commit
6b47129424
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue