diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 5872cc0ee0f..158dad3efe4 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -278,6 +278,10 @@ Changes in the Python API to ``__spec__.parent`` then :exc:`ImportWarning` is raised. (Contributed by Brett Cannon in :issue:`25791`.) +* When a relative import is performed and no parent package is known, then + :exc:`ImportError` will be raised. Previously, :exc:`SystemError` could be + raised. (Contribute by Brett Cannon in :issue:`18018`.) + Changes in the C API -------------------- diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py index 0409f22b4d9..1cad6b360a2 100644 --- a/Lib/test/test_importlib/import_/test_relative_imports.py +++ b/Lib/test/test_importlib/import_/test_relative_imports.py @@ -213,6 +213,11 @@ class RelativeImports: with self.assertRaises(KeyError): self.__import__('sys', level=1) + def test_relative_import_no_package(self): + with self.assertRaises(ImportError): + self.__import__('a', {'__package__': '', '__spec__': None}, + level=1) + (Frozen_RelativeImports, Source_RelativeImports diff --git a/Misc/NEWS b/Misc/NEWS index 165b428c513..676f2cac835 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Release date: tba Core and Builtins ----------------- +- Issue #18018: Import raises ImportError instead of SystemError if a relative + import is attempted without a known parent package. + - Issue #25843: When compiling code, don't merge constants if they are equal but have a different types. For example, ``f1, f2 = lambda: 1, lambda: 1.0`` is now correctly compiled to two different functions: ``f1()`` returns ``1`` diff --git a/Python/import.c b/Python/import.c index 22f9d2127ad..8ad5b4c1674 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1424,7 +1424,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals, PyErr_SetString(PyExc_TypeError, "package must be a string"); goto error; } - else if (spec != NULL) { + else if (spec != NULL && spec != Py_None) { int equal; PyObject *parent = PyObject_GetAttrString(spec, "parent"); if (parent == NULL) { @@ -1444,7 +1444,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals, } } } - else if (spec != NULL) { + else if (spec != NULL && spec != Py_None) { package = PyObject_GetAttrString(spec, "parent"); if (package == NULL) { goto error; @@ -1491,7 +1491,12 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals, } } - if (PyDict_GetItem(interp->modules, package) == NULL) { + if (PyUnicode_CompareWithASCIIString(package, "") == 0) { + PyErr_SetString(PyExc_ImportError, + "attempted relative import with no known parent package"); + goto error; + } + else if (PyDict_GetItem(interp->modules, package) == NULL) { PyErr_Format(PyExc_SystemError, "Parent module %R not loaded, cannot perform relative " "import", package);