Commit 77658381 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add type.__instancecheck__ and __subclasscheck__

We supported classes that overrode them, but didn't provide a
default implementation in case people called it by hand.

The tricky part is making sure that these new additions don't
mess with our "does this class override __instancecheck__" optimizations.
parent 70993f0a
......@@ -185,6 +185,10 @@ extern "C" int PyObject_IsInstance(PyObject* inst, PyObject* cls) noexcept {
return recursive_isinstance(inst, cls);
}
extern "C" int _PyObject_RealIsInstance(PyObject* inst, PyObject* cls) noexcept {
return recursive_isinstance(inst, cls);
}
extern "C" int PyObject_IsSubclass(PyObject* derived, PyObject* cls) noexcept {
static PyObject* name = NULL;
......
......@@ -1924,6 +1924,18 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce
descr = NULL;
}
static BoxedString* instancecheck_str = getStaticString("__instancecheck__");
if (p->name_strobj == instancecheck_str) {
if (descr == type_cls->getattr(instancecheck_str))
descr = NULL;
}
static BoxedString* subclasscheck_str = getStaticString("__subclasscheck__");
if (p->name_strobj == subclasscheck_str) {
if (descr == type_cls->getattr(subclasscheck_str))
descr = NULL;
}
static BoxedString* getattribute_str = getStaticString("__getattribute__");
if (p->name_strobj == getattribute_str) {
if (type->tp_getattr == NULL && descr && descr->cls == &PyWrapperDescr_Type
......
......@@ -1400,6 +1400,28 @@ static int type_sub_set_dict(BORROWED(Box*) obj, BORROWED(Box*) val, void* conte
return 0;
}
static PyObject* type___instancecheck__(PyObject* type, PyObject* inst) noexcept {
switch (_PyObject_RealIsInstance(inst, type)) {
case -1:
return NULL;
case 0:
Py_RETURN_FALSE;
default:
Py_RETURN_TRUE;
}
}
static PyObject* type___subclasscheck__(PyObject* type, PyObject* inst) noexcept {
switch (_PyObject_RealIsSubclass(inst, type)) {
case -1:
return NULL;
case 0:
Py_RETURN_FALSE;
default:
Py_RETURN_TRUE;
}
}
extern "C" void PyType_SetDict(PyTypeObject* type, STOLEN(PyObject*) dict) noexcept {
type_sub_set_dict(type, dict, NULL);
Box* old_dict = type->tp_dict;
......@@ -4399,6 +4421,12 @@ void setupRuntime() {
type_cls->giveAttrDescriptor("__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods);
type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj));
type_cls->giveAttr(
"__subclasscheck__",
new BoxedFunction(BoxedCode::create((void*)type___subclasscheck__, BOXED_BOOL, 2, "type.__subclasscheck__")));
type_cls->giveAttr(
"__instancecheck__",
new BoxedFunction(BoxedCode::create((void*)type___instancecheck__, BOXED_BOOL, 2, "type.__instancecheck__")));
type_cls->giveAttr(
"__new__", new BoxedFunction(BoxedCode::create((void*)typeNewGeneric, UNKNOWN, 4, false, false, "type.__new__"),
......
assert hasattr(object, "__subclasscheck__")
assert hasattr(object, "__instancecheck__")
class M(type):
def __instancecheck__(self, rhs):
print "M.instancecheck",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment