summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorWalter Dörwald <walter@livinglogic.de>2002-12-12 16:41:44 (GMT)
committerWalter Dörwald <walter@livinglogic.de>2002-12-12 16:41:44 (GMT)
commitd9a6ad3bebc2b451482db152171fca3144b2cd97 (patch)
tree59624bf7be4191d6d918fd91a821636a4157aa6a /Objects
parentb083cb3901fcb7487c04ad996148d1cf0aa32350 (diff)
downloadcpython-d9a6ad3bebc2b451482db152171fca3144b2cd97.zip
cpython-d9a6ad3bebc2b451482db152171fca3144b2cd97.tar.gz
cpython-d9a6ad3bebc2b451482db152171fca3144b2cd97.tar.bz2
Enhance issubclass() and PyObject_IsSubclass() so that a tuple is
supported as the second argument. This has the same meaning as for isinstance(), i.e. issubclass(X, (A, B)) is equivalent to issubclass(X, A) or issubclass(X, B). Compared to isinstance(), this patch does not search the tuple recursively for classes, i.e. any entry in the tuple that is not a class, will result in a TypeError. This closes SF patch #649608.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/abstract.c70
-rw-r--r--Objects/classobject.c7
2 files changed, 49 insertions, 28 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index e77cde3..47d2f31 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1914,6 +1914,15 @@ abstract_issubclass(PyObject *derived, PyObject *cls)
if (derived == cls)
return 1;
+ if (PyTuple_Check(cls)) {
+ /* Not a general sequence -- that opens up the road to
+ recursion and stack overflow. */
+ n = PyTuple_GET_SIZE(cls);
+ for (i = 0; i < n; i++) {
+ if (derived == PyTuple_GET_ITEM(cls, i))
+ return 1;
+ }
+ }
bases = abstract_get_bases(derived);
if (bases == NULL) {
if (PyErr_Occurred())
@@ -1932,6 +1941,20 @@ abstract_issubclass(PyObject *derived, PyObject *cls)
return r;
}
+static int
+check_class(PyObject *cls, const char *error)
+{
+ PyObject *bases = abstract_get_bases(cls);
+ if (bases == NULL) {
+ /* Do not mask errors. */
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError, error);
+ return 0;
+ }
+ Py_DECREF(bases);
+ return -1;
+}
+
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
@@ -1962,16 +1985,10 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
return retval;
}
else {
- PyObject *cls_bases = abstract_get_bases(cls);
- if (cls_bases == NULL) {
- /* Do not mask errors. */
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_TypeError,
- "isinstance() arg 2 must be a class, type,"
- " or tuple of classes and types");
+ if (!check_class(cls,
+ "isinstance() arg 2 must be a class, type,"
+ " or tuple of classes and types"))
return -1;
- }
- Py_DECREF(cls_bases);
if (__class__ == NULL) {
__class__ = PyString_FromString("__class__");
if (__class__ == NULL)
@@ -1997,28 +2014,25 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
int retval;
if (!PyClass_Check(derived) || !PyClass_Check(cls)) {
- PyObject *derived_bases;
- PyObject *cls_bases;
-
- derived_bases = abstract_get_bases(derived);
- if (derived_bases == NULL) {
- /* Do not mask errors */
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_TypeError,
- "issubclass() arg 1 must be a class");
+ if (!check_class(derived, "issubclass() arg 1 must be a class"))
return -1;
+
+ if (PyTuple_Check(cls)) {
+ int i;
+ int n = PyTuple_GET_SIZE(cls);
+ for (i = 0; i < n; ++i) {
+ if (!check_class(PyTuple_GET_ITEM(cls, i),
+ "issubclass() arg 2 must be a class"
+ " or tuple of classes"))
+ return -1;
+ }
}
- Py_DECREF(derived_bases);
-
- cls_bases = abstract_get_bases(cls);
- if (cls_bases == NULL) {
- /* Do not mask errors */
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_TypeError,
- "issubclass() arg 2 must be a class");
- return -1;
+ else {
+ if (!check_class(cls,
+ "issubclass() arg 2 must be a class"
+ " or tuple of classes"))
+ return -1;
}
- Py_DECREF(cls_bases);
retval = abstract_issubclass(derived, cls);
}
diff --git a/Objects/classobject.c b/Objects/classobject.c
index f7b442a..f3b9873 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -487,6 +487,13 @@ PyClass_IsSubclass(PyObject *class, PyObject *base)
PyClassObject *cp;
if (class == base)
return 1;
+ if (PyTuple_Check(base)) {
+ n = PyTuple_GET_SIZE(base);
+ for (i = 0; i < n; i++) {
+ if (class == PyTuple_GET_ITEM(base, i))
+ return 1;
+ }
+ }
if (class == NULL || !PyClass_Check(class))
return 0;
cp = (PyClassObject *)class;