mirror of https://github.com/python/cpython
properly lookup __instancecheck__ and __subclasscheck__
This commit is contained in:
parent
757b3c90e6
commit
fb6fb062e8
|
@ -1683,16 +1683,25 @@ order (MRO) for bases """
|
||||||
return 0
|
return 0
|
||||||
def stop(self):
|
def stop(self):
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
def return_true(self, thing=None):
|
||||||
|
return True
|
||||||
|
def do_isinstance(obj):
|
||||||
|
return isinstance(int, obj)
|
||||||
|
def do_issubclass(obj):
|
||||||
|
return issubclass(int, obj)
|
||||||
|
|
||||||
# It would be nice to have every special method tested here, but I'm
|
# It would be nice to have every special method tested here, but I'm
|
||||||
# only listing the ones I can remember outside of typeobject.c, since it
|
# only listing the ones I can remember outside of typeobject.c, since it
|
||||||
# does it right.
|
# does it right.
|
||||||
specials = [
|
specials = [
|
||||||
("__unicode__", unicode, hello, {}),
|
("__unicode__", unicode, hello, set(), {}),
|
||||||
("__reversed__", reversed, empty_seq, {}),
|
("__reversed__", reversed, empty_seq, set(), {}),
|
||||||
("__length_hint__", list, zero,
|
("__length_hint__", list, zero, set(),
|
||||||
{"__iter__" : iden, "next" : stop}),
|
{"__iter__" : iden, "next" : stop}),
|
||||||
("__sizeof__", sys.getsizeof, zero, {}),
|
("__sizeof__", sys.getsizeof, zero, set(), {}),
|
||||||
|
("__instancecheck__", do_isinstance, return_true, set(), {}),
|
||||||
|
("__subclasscheck__", do_issubclass, return_true,
|
||||||
|
set(("__bases__",)), {}),
|
||||||
# These two fail because the compiler generates LOAD_ATTR to look
|
# These two fail because the compiler generates LOAD_ATTR to look
|
||||||
# them up. We'd have to add a new opcode to fix this, and it's
|
# them up. We'd have to add a new opcode to fix this, and it's
|
||||||
# probably not worth it.
|
# probably not worth it.
|
||||||
|
@ -1704,7 +1713,9 @@ order (MRO) for bases """
|
||||||
def __getattr__(self, attr, test=self):
|
def __getattr__(self, attr, test=self):
|
||||||
test.fail("__getattr__ called with {0}".format(attr))
|
test.fail("__getattr__ called with {0}".format(attr))
|
||||||
def __getattribute__(self, attr, test=self):
|
def __getattribute__(self, attr, test=self):
|
||||||
test.fail("__getattribute__ called with {0}".format(attr))
|
if attr not in ok:
|
||||||
|
test.fail("__getattribute__ called with {0}".format(attr))
|
||||||
|
return object.__getattribute__(attr)
|
||||||
class SpecialDescr(object):
|
class SpecialDescr(object):
|
||||||
def __init__(self, impl):
|
def __init__(self, impl):
|
||||||
self.impl = impl
|
self.impl = impl
|
||||||
|
@ -1713,7 +1724,7 @@ order (MRO) for bases """
|
||||||
return self.impl.__get__(obj, owner)
|
return self.impl.__get__(obj, owner)
|
||||||
|
|
||||||
|
|
||||||
for name, runner, meth_impl, env in specials:
|
for name, runner, meth_impl, ok, env in specials:
|
||||||
class X(Checker):
|
class X(Checker):
|
||||||
pass
|
pass
|
||||||
for attr, obj in env.iteritems():
|
for attr, obj in env.iteritems():
|
||||||
|
|
|
@ -2926,14 +2926,19 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
|
||||||
Py_LeaveRecursiveCall();
|
Py_LeaveRecursiveCall();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if (name == NULL) {
|
|
||||||
name = PyString_InternFromString("__instancecheck__");
|
if (PyInstance_Check(cls)) {
|
||||||
if (name == NULL)
|
checker = PyObject_GetAttrString(cls, "__instancecheck__");
|
||||||
return -1;
|
if (checker == NULL) {
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
PyErr_Clear();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
checker = _PyObject_LookupSpecial(cls, "__instancecheck__", &name);
|
||||||
}
|
}
|
||||||
checker = PyObject_GetAttr(cls, name);
|
|
||||||
if (checker == NULL && PyErr_Occurred())
|
|
||||||
PyErr_Clear();
|
|
||||||
if (checker != NULL) {
|
if (checker != NULL) {
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
int ok = -1;
|
int ok = -1;
|
||||||
|
@ -3008,14 +3013,21 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
|
||||||
Py_LeaveRecursiveCall();
|
Py_LeaveRecursiveCall();
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
if (name == NULL) {
|
if (PyInstance_Check(cls)) {
|
||||||
name = PyString_InternFromString("__subclasscheck__");
|
PyErr_Fetch(&t, &v, &tb);
|
||||||
if (name == NULL)
|
checker = PyObject_GetAttr(cls, name);
|
||||||
|
if (checker == NULL &&
|
||||||
|
!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
Py_XDECREF(t);
|
||||||
|
Py_XDECREF(v);
|
||||||
|
Py_XDECREF(tb);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
PyErr_Restore(t, v, tb);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
|
||||||
}
|
}
|
||||||
PyErr_Fetch(&t, &v, &tb);
|
|
||||||
checker = PyObject_GetAttr(cls, name);
|
|
||||||
PyErr_Restore(t, v, tb);
|
|
||||||
if (checker != NULL) {
|
if (checker != NULL) {
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
int ok = -1;
|
int ok = -1;
|
||||||
|
|
|
@ -585,14 +585,6 @@ type___instancecheck__(PyObject *type, PyObject *inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
type_get_instancecheck(PyObject *type, void *context)
|
|
||||||
{
|
|
||||||
static PyMethodDef ml = {"__instancecheck__",
|
|
||||||
type___instancecheck__, METH_O };
|
|
||||||
return PyCFunction_New(&ml, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
type___subclasscheck__(PyObject *type, PyObject *inst)
|
type___subclasscheck__(PyObject *type, PyObject *inst)
|
||||||
{
|
{
|
||||||
|
@ -606,13 +598,6 @@ type___subclasscheck__(PyObject *type, PyObject *inst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
type_get_subclasscheck(PyObject *type, void *context)
|
|
||||||
{
|
|
||||||
static PyMethodDef ml = {"__subclasscheck__",
|
|
||||||
type___subclasscheck__, METH_O };
|
|
||||||
return PyCFunction_New(&ml, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyGetSetDef type_getsets[] = {
|
static PyGetSetDef type_getsets[] = {
|
||||||
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
|
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
|
||||||
|
@ -622,8 +607,6 @@ static PyGetSetDef type_getsets[] = {
|
||||||
(setter)type_set_abstractmethods, NULL},
|
(setter)type_set_abstractmethods, NULL},
|
||||||
{"__dict__", (getter)type_dict, NULL, NULL},
|
{"__dict__", (getter)type_dict, NULL, NULL},
|
||||||
{"__doc__", (getter)type_get_doc, NULL, NULL},
|
{"__doc__", (getter)type_get_doc, NULL, NULL},
|
||||||
{"__instancecheck__", (getter)type_get_instancecheck, NULL, NULL},
|
|
||||||
{"__subclasscheck__", (getter)type_get_subclasscheck, NULL, NULL},
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2674,6 +2657,10 @@ static PyMethodDef type_methods[] = {
|
||||||
PyDoc_STR("mro() -> list\nreturn a type's method resolution order")},
|
PyDoc_STR("mro() -> list\nreturn a type's method resolution order")},
|
||||||
{"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS,
|
{"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS,
|
||||||
PyDoc_STR("__subclasses__() -> list of immediate subclasses")},
|
PyDoc_STR("__subclasses__() -> list of immediate subclasses")},
|
||||||
|
{"__instancecheck__", type___instancecheck__, METH_O,
|
||||||
|
PyDoc_STR("__instancecheck__() -> check if an object is an instance")},
|
||||||
|
{"__subclasscheck__", type___subclasscheck__, METH_O,
|
||||||
|
PyDoc_STR("__subclasschck__ -> check if an class is a subclass")},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue