Commit 617a9592 authored by Syam Gadde's avatar Syam Gadde Committed by GitHub

Fix partial circular imports (GH-4392)

Follows the implementation in CPython, which does a lookup in sys.modules if the attribute lookup on a package fails.

Closes https://github.com/cython/cython/issues/4390
parent 210524ef
......@@ -238,6 +238,39 @@ static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); /*proto*/
static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) {
PyObject* value = __Pyx_PyObject_GetAttrStr(module, name);
if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) {
// 'name' may refer to a (sub-)module which has not finished initialization
// yet, and may not be assigned as an attribute to its parent, so try
// finding it by full name.
const char* module_name_str = 0;
PyObject* module_name = 0;
PyObject* module_dot = 0;
PyObject* full_name = 0;
PyErr_Clear();
module_name_str = PyModule_GetName(module);
if (unlikely(!module_name_str)) { goto modbad; }
module_name = PyUnicode_FromString(module_name_str);
if (unlikely(!module_name)) { goto modbad; }
module_dot = PyUnicode_Concat(module_name, PYUNICODE("."));
if (unlikely(!module_dot)) { goto modbad; }
full_name = PyUnicode_Concat(module_dot, name);
if (unlikely(!full_name)) { goto modbad; }
#if PY_VERSION_HEX < 0x030700A1 || (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400)
{
PyObject *modules = PyImport_GetModuleDict();
if (unlikely(!modules))
goto modbad;
value = PyObject_GetItem(modules, full_name);
}
#else
value = PyImport_GetModule(full_name);
#endif
modbad:
Py_XDECREF(full_name);
Py_XDECREF(module_dot);
Py_XDECREF(module_name);
}
if (unlikely(!value)) {
PyErr_Format(PyExc_ImportError,
#if PY_MAJOR_VERSION < 3
"cannot import name %.230s", PyString_AS_STRING(name));
......
......@@ -10,6 +10,7 @@ run.cdef_multiple_inheritance_nodict
run.extstarargs
run.cpython_capi
run.isnot
run.partial_circular_import
# pypy 2 seems to be preferring .py files to .so files
# https://foss.heptapod.net/pypy/pypy/issues/3185
......
PYTHON -c 'if __import__("sys").version_info >= (3,7): import pkg.A'
PYTHON setup.py build_ext --inplace
PYTHON -c "import pkg.A"
######## setup.py ########
from Cython.Build.Dependencies import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("*/*.py"),
)
######## pkg/__init__.py ########
######## pkg/A.py ########
from . import B
def verify(rel_B):
import pkg.B as abs_B
assert abs_B == rel_B
verify(B)
######## pkg/B.py ########
from . import C
def verify(rel_C):
import pkg.C as abs_C
assert abs_C == rel_C
verify(C)
######## pkg/C.py ########
from . import B
def verify(rel_B):
import pkg.B as abs_B
assert abs_B == rel_B
verify(B)
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