Commit b6ba1a27 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Adding more CPython subclassing behavior

Supposed to call type->tp_alloc(type) instead of PyObject_New

Adding Py_TPFLAGS_BASETYPE and checking it
parent c66c9375
......@@ -120,4 +120,8 @@ extern "C" PyObject* PyErr_SetFromErrnoWithUnicodeFilename(PyObject* exc, const
extern "C" PyObject* PyErr_SetFromErrno(PyObject* exc) {
return PyErr_SetFromErrnoWithFilenameObject(exc, NULL);
}
extern "C" void PyErr_Print() {
Py_FatalError("unimplemented");
}
}
......@@ -447,7 +447,8 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
try {
return repr(self);
} catch (Box* e) {
abort();
PyErr_SetObject(e->cls, e);
return NULL;
}
}
......@@ -455,7 +456,8 @@ PyObject* slot_tp_str(PyObject* self) noexcept {
try {
return str(self);
} catch (Box* e) {
abort();
PyErr_SetObject(e->cls, e);
return NULL;
}
}
......@@ -503,7 +505,8 @@ PyObject* slot_tp_call(PyObject* self, PyObject* args, PyObject* kwds) noexcept
// TODO: runtime ICs?
return runtimeCall(self, ArgPassSpec(0, 0, true, true), args, kwds, NULL, NULL, NULL);
} catch (Box* e) {
abort();
PyErr_SetObject(e->cls, e);
return NULL;
}
}
......@@ -561,7 +564,8 @@ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexce
return runtimeCall(new_attr, ArgPassSpec(1, 0, true, true), self, args, kwds, NULL, NULL);
} catch (Box* e) {
abort();
PyErr_SetObject(e->cls, e);
return NULL;
}
}
......@@ -589,7 +593,8 @@ PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
try {
return getitem(self, boxInt(i));
} catch (Box* e) {
abort();
PyErr_SetObject(e->cls, e);
return NULL;
}
}
......
......@@ -354,6 +354,7 @@ BoxedClass::BoxedClass(BoxedClass* metaclass, BoxedClass* base, gcvisit_func gc_
tp_flags |= Py_TPFLAGS_HEAPTYPE;
tp_flags |= Py_TPFLAGS_CHECKTYPES;
tp_flags |= Py_TPFLAGS_BASETYPE;
tp_base = base;
......@@ -3306,6 +3307,8 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
RELEASE_ASSERT(_base->cls == type_cls, "");
base = static_cast<BoxedClass*>(_base);
if ((base->tp_flags & Py_TPFLAGS_BASETYPE) == 0)
raiseExcHelper(TypeError, "type '%.100s' is not an acceptable base type", base->tp_name);
BoxedClass* made;
......
......@@ -20,8 +20,7 @@ slots_tester_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
printf("slots_tester_seq.__new__, %d\n", n);
/* create attrgetterobject structure */
obj = PyObject_New(slots_tester_object, type);
obj = (slots_tester_object*)type->tp_alloc(type, 0);
if (obj == NULL)
return NULL;
......@@ -123,7 +122,7 @@ static PyTypeObject slots_tester_seq = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
slots_tester_seq_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
......@@ -145,6 +144,49 @@ static PyTypeObject slots_tester_seq = {
0, /* tp_free */
};
static PyTypeObject slots_tester_nonsubclassable = {
PyVarObject_HEAD_INIT(NULL, 0)
"slots_test.slots_tester_nonsubclassable", /* tp_name */
sizeof(slots_tester_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)slots_tester_seq_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
slots_tester_init, /* tp_init */
0, /* tp_alloc */
slots_tester_new, /* tp_new */
0, /* tp_free */
};
static Py_ssize_t slots_tester_map_length(slots_tester_object* obj) {
return obj->n;
}
......@@ -417,8 +459,13 @@ call_funcs(PyObject* _module, PyObject* args) {
if (cls->tp_new) {
PyObject* rtn = cls->tp_new(cls, PyTuple_New(0), PyDict_New());
printf("tp_new exists and returned an object of type: '%s'\n", Py_TYPE(rtn)->tp_name);
Py_DECREF(rtn);
if (!rtn) {
printf("tp_new_exists but returned an error!\n");
PyErr_Print();
} else {
printf("tp_new exists and returned an object of type: '%s'\n", Py_TYPE(rtn)->tp_name);
Py_DECREF(rtn);
}
}
if (cls->tp_new) {
......@@ -573,6 +620,10 @@ initslots_test(void)
if (res < 0)
return;
res = PyType_Ready(&slots_tester_nonsubclassable);
if (res < 0)
return;
// Not sure if the result of PyInt_FromLong needs to be decref'd
PyDict_SetItemString(slots_tester_seq.tp_dict, "set_through_tpdict", PyInt_FromLong(123));
......@@ -580,4 +631,5 @@ initslots_test(void)
PyModule_AddObject(m, "SlotsTesterMap", (PyObject *)&slots_tester_map);
PyModule_AddObject(m, "SlotsTesterNum", (PyObject *)&slots_tester_num);
PyModule_AddObject(m, "SlotsTesterSub", (PyObject *)&slots_tester_sub);
PyModule_AddObject(m, "SlotsTesterNonsubclassable", (PyObject *)&slots_tester_nonsubclassable);
}
......@@ -72,3 +72,19 @@ def add(self, rhs):
C.__add__ = add
slots_test.call_funcs(C())
class C2(C):
pass
slots_test.call_funcs(C2())
class C3(slots_test.SlotsTesterSeq):
pass
slots_test.call_funcs(C3(5))
try:
class C4(slots_test.SlotsTesterNonsubclassable):
pass
except TypeError, e:
print e
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