From daa0a4434fa3ef281f9df65f7bb6098d31e1e400 Mon Sep 17 00:00:00 2001 From: da-woods Date: Tue, 28 Sep 2021 08:48:12 +0100 Subject: Fix the name of attributes in the common ABI module (GH-4376) Attribute names used to be fully qualified like "_cython_3_0_0a9.cython_function_or_method" instead of the plain name. Closes https://github.com/cython/cython/issues/4373 --- Cython/Utility/CommonStructures.c | 20 ++++++++++++++------ tests/run/common_utility_types.srctree | 13 +++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Cython/Utility/CommonStructures.c b/Cython/Utility/CommonStructures.c index c596e15bb..34778e341 100644 --- a/Cython/Utility/CommonStructures.c +++ b/Cython/Utility/CommonStructures.c @@ -8,6 +8,7 @@ static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec /////////////// FetchCommonType /////////////// //@requires:ExtensionTypes.c::FixUpExtensionType +//@requires:StringTools.c::IncludeStringH static PyObject *__Pyx_FetchSharedCythonABIModule(void) { PyObject *abi_module = PyImport_AddModule((char*) __PYX_ABI_MODULE_NAME); @@ -37,15 +38,19 @@ static int __Pyx_VerifyCachedType(PyObject *cached_type, #if !CYTHON_USE_TYPE_SPECS static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { PyObject* abi_module; + const char* object_name; PyTypeObject *cached_type = NULL; abi_module = __Pyx_FetchSharedCythonABIModule(); if (!abi_module) return NULL; - cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, type->tp_name); + // get the final part of the object name (after the last dot) + object_name = strrchr(type->tp_name, '.'); + object_name = object_name ? object_name+1 : type->tp_name; + cached_type = (PyTypeObject*) PyObject_GetAttrString(abi_module, object_name); if (cached_type) { if (__Pyx_VerifyCachedType( (PyObject *)cached_type, - type->tp_name, + object_name, cached_type->tp_basicsize, type->tp_basicsize) < 0) { goto bad; @@ -56,7 +61,7 @@ static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto bad; PyErr_Clear(); if (PyType_Ready(type) < 0) goto bad; - if (PyObject_SetAttrString(abi_module, type->tp_name, (PyObject *)type) < 0) + if (PyObject_SetAttrString(abi_module, object_name, (PyObject *)type) < 0) goto bad; Py_INCREF(type); cached_type = type; @@ -75,11 +80,14 @@ bad: static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { PyObject *abi_module, *cached_type = NULL; + // get the final part of the object name (after the last dot) + const char* object_name = strrchr(spec->name, '.'); + object_name = object_name ? object_name+1 : spec->name; abi_module = __Pyx_FetchSharedCythonABIModule(); if (!abi_module) return NULL; - cached_type = PyObject_GetAttrString(abi_module, spec->name); + cached_type = PyObject_GetAttrString(abi_module, object_name); if (cached_type) { Py_ssize_t basicsize; #if CYTHON_COMPILING_IN_LIMITED_API @@ -95,7 +103,7 @@ static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec #endif if (__Pyx_VerifyCachedType( cached_type, - spec->name, + object_name, basicsize, spec->basicsize) < 0) { goto bad; @@ -110,7 +118,7 @@ static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); if (unlikely(!cached_type)) goto bad; if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; - if (PyObject_SetAttrString(abi_module, spec->name, cached_type) < 0) goto bad; + if (PyObject_SetAttrString(abi_module, object_name, cached_type) < 0) goto bad; done: Py_DECREF(abi_module); diff --git a/tests/run/common_utility_types.srctree b/tests/run/common_utility_types.srctree index 35daad505..e978accc3 100644 --- a/tests/run/common_utility_types.srctree +++ b/tests/run/common_utility_types.srctree @@ -36,3 +36,16 @@ assert type(a.funcA) is type(b.funcB) assert a.funcA.func_globals is a.__dict__ assert b.funcB.func_globals is b.__dict__ + +# Test that it's possible to look up the name of the class +from sys import modules +cy_modules = [ mod for n, mod in modules.items() if n.startswith("_cython_") ] +# In principle it's possible to have "_cython_" internal modules for multiple +# different versions of Cython. However, since this is run in an end-to-end test +# with a very short list of imports it should not happen here. +assert(len(cy_modules)==1) +mod = cy_modules[0] + +assert '.' not in type(a.funcA).__name__ +func_t = getattr(mod, type(a.funcA).__name__) +assert func_t is type(a.funcA) -- cgit v1.2.1