Issue #17636: Circular imports involving relative imports are now supported.
This commit is contained in:
parent
dfbeb160de
commit
0373a106a1
|
@ -568,7 +568,7 @@ class RelativeImportTests(unittest.TestCase):
|
|||
|
||||
def test_relimport_star(self):
|
||||
# This will import * from .test_import.
|
||||
from . import relimport
|
||||
from .. import relimport
|
||||
self.assertTrue(hasattr(relimport, "RelativeImportTests"))
|
||||
|
||||
def test_issue3221(self):
|
||||
|
@ -1068,6 +1068,46 @@ class ImportTracebackTests(unittest.TestCase):
|
|||
__isolated=False)
|
||||
|
||||
|
||||
class CircularImportTests(unittest.TestCase):
|
||||
|
||||
"""See the docstrings of the modules being imported for the purpose of the
|
||||
test."""
|
||||
|
||||
def tearDown(self):
|
||||
"""Make sure no modules pre-exist in sys.modules which are being used to
|
||||
test."""
|
||||
for key in list(sys.modules.keys()):
|
||||
if key.startswith('test.test_import.data.circular_imports'):
|
||||
del sys.modules[key]
|
||||
|
||||
def test_direct(self):
|
||||
try:
|
||||
import test.test_import.data.circular_imports.basic
|
||||
except ImportError:
|
||||
self.fail('circular import through relative imports failed')
|
||||
|
||||
def test_indirect(self):
|
||||
try:
|
||||
import test.test_import.data.circular_imports.indirect
|
||||
except ImportError:
|
||||
self.fail('relative import in module contributing to circular '
|
||||
'import failed')
|
||||
|
||||
def test_subpackage(self):
|
||||
try:
|
||||
import test.test_import.data.circular_imports.subpackage
|
||||
except ImportError:
|
||||
self.fail('circular import involving a subpackage failed')
|
||||
|
||||
def test_rebinding(self):
|
||||
try:
|
||||
import test.test_import.data.circular_imports.rebinding as rebinding
|
||||
except ImportError:
|
||||
self.fail('circular import with rebinding of module attribute failed')
|
||||
from test.test_import.data.circular_imports.subpkg import util
|
||||
self.assertIs(util.util, rebinding.util)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Test needs to be a package, so we can do relative imports.
|
||||
unittest.main()
|
|
@ -0,0 +1,3 @@
|
|||
import unittest
|
||||
|
||||
unittest.main('test.test_import')
|
|
@ -0,0 +1,2 @@
|
|||
"""Circular imports through direct, relative imports."""
|
||||
from . import basic2
|
|
@ -0,0 +1 @@
|
|||
from . import basic
|
|
@ -0,0 +1 @@
|
|||
from . import basic, basic2
|
|
@ -0,0 +1,3 @@
|
|||
"""Test the binding of names when a circular import shares the same name as an
|
||||
attribute."""
|
||||
from .rebinding2 import util
|
|
@ -0,0 +1,3 @@
|
|||
from .subpkg import util
|
||||
from . import rebinding
|
||||
util = util.util
|
|
@ -0,0 +1,2 @@
|
|||
"""Circular import involving a sub-package."""
|
||||
from .subpkg import subpackage2
|
|
@ -0,0 +1,2 @@
|
|||
#from .util import util
|
||||
from .. import subpackage
|
|
@ -0,0 +1,2 @@
|
|||
def util():
|
||||
pass
|
|
@ -0,0 +1,2 @@
|
|||
def util():
|
||||
pass
|
|
@ -10,6 +10,9 @@ Release date: TBA
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #17636: Circular imports involving relative imports are now
|
||||
supported.
|
||||
|
||||
- Issue #22604: Fix assertion error in debug mode when dividing a complex
|
||||
number by (nan+0j).
|
||||
|
||||
|
|
|
@ -4693,11 +4693,29 @@ static PyObject *
|
|||
import_from(PyObject *v, PyObject *name)
|
||||
{
|
||||
PyObject *x;
|
||||
_Py_IDENTIFIER(__name__);
|
||||
PyObject *fullmodname, *pkgname;
|
||||
|
||||
x = PyObject_GetAttr(v, name);
|
||||
if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
if (x != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return x;
|
||||
/* Issue #17636: in case this failed because of a circular relative
|
||||
import, try to fallback on reading the module directly from
|
||||
sys.modules. */
|
||||
PyErr_Clear();
|
||||
pkgname = _PyObject_GetAttrId(v, &PyId___name__);
|
||||
if (pkgname == NULL)
|
||||
return NULL;
|
||||
fullmodname = PyUnicode_FromFormat("%U.%U", pkgname, name);
|
||||
Py_DECREF(pkgname);
|
||||
if (fullmodname == NULL)
|
||||
return NULL;
|
||||
x = PyDict_GetItem(PyImport_GetModuleDict(), fullmodname);
|
||||
if (x == NULL)
|
||||
PyErr_Format(PyExc_ImportError, "cannot import name %R", name);
|
||||
}
|
||||
else
|
||||
Py_INCREF(x);
|
||||
Py_DECREF(fullmodname);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue