summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bradshaw <robertwb@gmail.com>2021-04-15 13:24:49 -0700
committerGitHub <noreply@github.com>2021-04-15 13:24:49 -0700
commitd5bc8147c19dd6bbbf60bfa0c8157dfb167bb804 (patch)
tree0855e6c0ac57757f4f776fdcda596c56877a4a9b
parent6d3480590ba5a10efa3288c2101090ff35e4ecbb (diff)
parentb68f2585ceec37e0be245122a0fb6328f5145e8d (diff)
downloadcython-d5bc8147c19dd6bbbf60bfa0c8157dfb167bb804.tar.gz
Merge pull request #4107 from robertwb/cdef-mixin
Allow inheriting from cimported multiply inherited class.
-rw-r--r--Cython/Compiler/Nodes.py26
-rw-r--r--Cython/Utility/ExtensionTypes.c29
-rw-r--r--tests/run/cdef_multiple_inheritance_cimport.srctree44
3 files changed, 74 insertions, 25 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index a095b2a72..5f935360f 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -5248,13 +5248,13 @@ class CClassDefNode(ClassDefNode):
self.type_init_args.generate_disposal_code(code)
self.type_init_args.free_temps(code)
- self.generate_type_ready_code(self.entry, code, True)
+ self.generate_type_ready_code(self.entry, code)
if self.body:
self.body.generate_execution_code(code)
# Also called from ModuleNode for early init types.
@staticmethod
- def generate_type_ready_code(entry, code, heap_type_bases=False):
+ def generate_type_ready_code(entry, code):
# Generate a call to PyType_Ready for an extension
# type defined in this module.
type = entry.type
@@ -5290,15 +5290,10 @@ class CClassDefNode(ClassDefNode):
code.putln("#else")
for slot in TypeSlots.slot_table:
slot.generate_dynamic_init_code(scope, code)
- if heap_type_bases:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached('PyType_Ready', 'ExtensionTypes.c'))
- readyfunc = "__Pyx_PyType_Ready"
- else:
- readyfunc = "PyType_Ready"
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached('PyType_Ready', 'ExtensionTypes.c'))
code.putln(
- "if (%s(&%s) < 0) %s" % (
- readyfunc,
+ "if (__Pyx_PyType_Ready(&%s) < 0) %s" % (
typeobj_cname,
code.error_goto(entry.pos)))
# Don't inherit tp_print from builtin types in Python 2, restoring the
@@ -5377,12 +5372,11 @@ class CClassDefNode(ClassDefNode):
type.vtabptr_cname,
code.error_goto(entry.pos)))
code.putln("#endif")
- if heap_type_bases:
- code.globalstate.use_utility_code(
- UtilityCode.load_cached('MergeVTables', 'ImportExport.c'))
- code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % (
- typeobj_cname,
- code.error_goto(entry.pos)))
+ code.globalstate.use_utility_code(
+ UtilityCode.load_cached('MergeVTables', 'ImportExport.c'))
+ code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % (
+ typeobj_cname,
+ code.error_goto(entry.pos)))
if not type.scope.is_internal and not type.scope.directives.get('internal'):
# scope.is_internal is set for types defined by
# Cython (such as closures), the 'internal'
diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c
index d8b8353cb..26bc2d9d9 100644
--- a/Cython/Utility/ExtensionTypes.c
+++ b/Cython/Utility/ExtensionTypes.c
@@ -3,6 +3,7 @@
static int __Pyx_PyType_Ready(PyTypeObject *t);
/////////////// PyType_Ready ///////////////
+//@requires: ObjectHandling.c::PyObjectCallNoArg
// Wrapper around PyType_Ready() with some runtime checks and fixes
// to deal with multiple inheritance.
@@ -67,24 +68,35 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) {
// For details, see https://github.com/cython/cython/issues/3603
PyObject *ret, *py_status;
int gc_was_enabled;
- PyObject *gc = PyImport_Import(PYUNICODE("gc"));
- if (unlikely(!gc)) return -1;
- py_status = PyObject_CallMethodObjArgs(gc, PYUNICODE("isenabled"), NULL);
+ static PyObject *gc = NULL;
+ static PyObject *gc_isenabled = NULL, *gc_enable = NULL, *gc_disable = NULL;
+ if (unlikely(!gc)) {
+ gc = PyImport_Import(PYUNICODE("gc"));
+ if (unlikely(!gc)) return -1;
+ gc_isenabled = PyObject_GetAttr(gc, PYUNICODE("isenabled"));
+ gc_enable = PyObject_GetAttr(gc, PYUNICODE("enable"));
+ gc_disable = PyObject_GetAttr(gc, PYUNICODE("disable"));
+ if (unlikely(!gc_isenabled || !gc_enable || !gc_disable)) {
+ Py_XDECREF(gc_isenabled); gc_isenabled = NULL;
+ Py_XDECREF(gc_enable); gc_enable = NULL;
+ Py_XDECREF(gc_disable); gc_disable = NULL;
+ Py_XDECREF(gc); gc = NULL;
+ return -1;
+ }
+ }
+ py_status = __Pyx_PyObject_CallNoArg(gc_isenabled);
if (unlikely(!py_status)) {
- Py_DECREF(gc);
return -1;
}
gc_was_enabled = __Pyx_PyObject_IsTrue(py_status);
Py_DECREF(py_status);
if (gc_was_enabled > 0) {
- ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("disable"), NULL);
+ ret = __Pyx_PyObject_CallNoArg(gc_disable);
if (unlikely(!ret)) {
- Py_DECREF(gc);
return -1;
}
Py_DECREF(ret);
} else if (unlikely(gc_was_enabled == -1)) {
- Py_DECREF(gc);
return -1;
}
@@ -106,7 +118,7 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) {
if (gc_was_enabled) {
PyObject *t, *v, *tb;
PyErr_Fetch(&t, &v, &tb);
- ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("enable"), NULL);
+ ret = __Pyx_PyObject_CallNoArg(gc_enable);
if (likely(ret || r == -1)) {
Py_XDECREF(ret);
// do not overwrite exceptions raised by PyType_Ready() above
@@ -119,7 +131,6 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) {
r = -1;
}
}
- Py_DECREF(gc);
}
#endif
diff --git a/tests/run/cdef_multiple_inheritance_cimport.srctree b/tests/run/cdef_multiple_inheritance_cimport.srctree
new file mode 100644
index 000000000..dd56b3e30
--- /dev/null
+++ b/tests/run/cdef_multiple_inheritance_cimport.srctree
@@ -0,0 +1,44 @@
+# Test for https://github.com/cython/cython/issues/4106
+
+PYTHON setup.py build_ext --inplace
+PYTHON -c "import sub"
+
+######## setup.py ########
+
+from Cython.Build import cythonize
+from distutils.core import setup
+
+setup(
+ ext_modules = cythonize("*.pyx"),
+)
+
+######## base.pxd ########
+
+cdef class A:
+ cdef dict __dict__
+ cdef int a(self)
+
+cdef class B(A):
+ cdef int b(self)
+
+######## base.pyx ########
+
+cdef class A:
+ cdef int a(self):
+ return 1
+
+class PyA:
+ pass
+
+cdef class B(A, PyA):
+ cdef int b(self):
+ return 2
+
+######## sub.pyx ########
+
+from base cimport B
+print(B)
+
+cdef class C(B):
+ cdef int c(self):
+ return 3