summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2020-04-24 22:58:57 +0200
committerStefan Behnel <stefan_ml@behnel.de>2020-04-24 22:58:57 +0200
commit538a40df472658baeca7e085dc7a38fb3e01daef (patch)
tree3c63866443a1ea2c2c1d38fe5ca46817a75d4d1c
parent5204d86989493855fdd0acd20debd9d0a270bb23 (diff)
downloadcython-gh3545_reduce_cython_reimport.tar.gz
Work around error that "__reduce_cython__ cannot be found" when re-importing an extension module that was already initialised before.gh3545_reduce_cython_reimport
Closes #3545.
-rw-r--r--Cython/Utility/ExtensionTypes.c24
-rw-r--r--tests/run/reimport_failure.srctree38
2 files changed, 56 insertions, 6 deletions
diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c
index efdfd35ef..a75863d02 100644
--- a/Cython/Utility/ExtensionTypes.c
+++ b/Cython/Utility/ExtensionTypes.c
@@ -235,16 +235,28 @@ static int __Pyx_setup_reduce(PyObject* type_obj) {
reduce = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce__")); if (unlikely(!reduce)) goto __PYX_BAD;
if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, PYIDENT("__reduce_cython__"))) {
- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce_cython__")); if (unlikely(!reduce_cython)) goto __PYX_BAD;
- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__reduce_cython__"));
+ if (likely(reduce_cython)) {
+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ } else if (reduce == object_reduce || PyErr_Occurred()) {
+ // Ignore if we're done, i.e. if 'reduce' already has the right name and the original is gone.
+ // Otherwise: error.
+ goto __PYX_BAD;
+ }
setstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__setstate__"));
if (!setstate) PyErr_Clear();
if (!setstate || __Pyx_setup_reduce_is_named(setstate, PYIDENT("__setstate_cython__"))) {
- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__setstate_cython__")); if (unlikely(!setstate_cython)) goto __PYX_BAD;
- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__setstate_cython__"));
+ if (likely(setstate_cython)) {
+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ } else if (!setstate || PyErr_Occurred()) {
+ // Ignore if we're done, i.e. if 'setstate' already has the right name and the original is gone.
+ // Otherwise: error.
+ goto __PYX_BAD;
+ }
}
PyType_Modified((PyTypeObject*)type_obj);
}
diff --git a/tests/run/reimport_failure.srctree b/tests/run/reimport_failure.srctree
new file mode 100644
index 000000000..498c9bd36
--- /dev/null
+++ b/tests/run/reimport_failure.srctree
@@ -0,0 +1,38 @@
+# mode: run
+# tag: pep489
+
+"""
+PYTHON setup.py build_ext -i
+PYTHON tester.py
+"""
+
+######## setup.py ########
+
+from Cython.Build.Dependencies import cythonize
+from distutils.core import setup
+
+setup(
+ ext_modules = cythonize("*.pyx"),
+)
+
+
+######## failure.pyx ########
+
+if globals(): # runtime True to confuse dead code removal
+ raise ImportError
+
+cdef class C:
+ cdef int a
+
+
+######## tester.py ########
+
+try:
+ try:
+ import failure # 1
+ except ImportError:
+ import failure # 2
+except ImportError:
+ pass
+else:
+ raise RuntimeError("ImportError was not raised on second import!")