diff options
author | Robert Bradshaw <robertwb@gmail.com> | 2021-04-15 13:24:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-15 13:24:49 -0700 |
commit | d5bc8147c19dd6bbbf60bfa0c8157dfb167bb804 (patch) | |
tree | 0855e6c0ac57757f4f776fdcda596c56877a4a9b | |
parent | 6d3480590ba5a10efa3288c2101090ff35e4ecbb (diff) | |
parent | b68f2585ceec37e0be245122a0fb6328f5145e8d (diff) | |
download | cython-d5bc8147c19dd6bbbf60bfa0c8157dfb167bb804.tar.gz |
Merge pull request #4107 from robertwb/cdef-mixin
Allow inheriting from cimported multiply inherited class.
-rw-r--r-- | Cython/Compiler/Nodes.py | 26 | ||||
-rw-r--r-- | Cython/Utility/ExtensionTypes.c | 29 | ||||
-rw-r--r-- | tests/run/cdef_multiple_inheritance_cimport.srctree | 44 |
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 |