Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions 7 Lib/importlib/_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,10 +925,9 @@ def _sanity_check(name, package, level):
if level > 0:
if not isinstance(package, str):
raise TypeError('__package__ not set to a string')
elif package not in sys.modules:
msg = ('Parent module {!r} not loaded, cannot perform relative '
'import')
raise SystemError(msg.format(package))
elif not package:
raise ImportError('attempted relative import with no known parent '
'package')
if not name and level == 0:
raise ValueError('Empty module name')

Expand Down
21 changes: 18 additions & 3 deletions 21 Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
EnvironmentVarGuard, TESTFN, check_warnings, forget, is_jython,
make_legacy_pyc, rmtree, run_unittest, swap_attr, swap_item, temp_umask,
unlink, unload, create_empty_file, cpython_only, TESTFN_UNENCODABLE,
temp_dir)
temp_dir, DirsOnSysPath)
from test.support import script_helper
from test.test_importlib.util import uncache


skip_if_dont_write_bytecode = unittest.skipIf(
Expand Down Expand Up @@ -600,11 +601,11 @@ def check_relative():

# Check relative import fails with only __package__ wrong
ns = dict(__package__='foo', __name__='test.notarealmodule')
self.assertRaises(SystemError, check_relative)
self.assertRaises(ImportError, check_relative)

# Check relative import fails with __package__ and __name__ wrong
ns = dict(__package__='foo', __name__='notarealpkg.notarealmodule')
self.assertRaises(SystemError, check_relative)
self.assertRaises(ImportError, check_relative)

# Check relative import fails with package set to a non-string
ns = dict(__package__=object())
Expand All @@ -619,6 +620,20 @@ def test_absolute_import_without_future(self):
self.fail("explicit relative import triggered an "
"implicit absolute import")

def test_import_from_non_package(self):
path = os.path.join(os.path.dirname(__file__), 'data', 'package2')
with uncache('submodule1', 'submodule2'), DirsOnSysPath(path):
with self.assertRaises(ImportError):
import submodule1
self.assertNotIn('submodule1', sys.modules)
self.assertNotIn('submodule2', sys.modules)

def test_import_from_unloaded_package(self):
with uncache('package2', 'package2.submodule1', 'package2.submodule2'), \
DirsOnSysPath(os.path.join(os.path.dirname(__file__), 'data')):
import package2.submodule1
package2.submodule1.submodule2


class OverridingImportBuiltinTests(unittest.TestCase):
def test_override_builtin(self):
Expand Down
3 changes: 3 additions & 0 deletions 3 Lib/test/test_import/data/package2/submodule1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import sys
sys.modules.pop(__package__, None)
from . import submodule2
Empty file.
2 changes: 1 addition & 1 deletion 2 Lib/test/test_importlib/import_/test___package__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_None_as___package__(self):

def test_bad__package__(self):
globals = {'__package__': '<not real>'}
with self.assertRaises(SystemError):
with self.assertRaises(ImportError):
self.__import__('', globals, {}, ['relimport'], 1)

def test_bunk__package__(self):
Expand Down
7 changes: 6 additions & 1 deletion 7 Lib/test/test_importlib/import_/test_relative_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,13 @@ def test_relative_import_no_globals(self):
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)

def test_relative_import_no_package_exists_absolute(self):
with self.assertRaises(SystemError):
with self.assertRaises(ImportError):
self.__import__('sys', {'__package__': '', '__spec__': None},
level=1)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Relative import from unloaded package now reimports the package instead of
failing with SystemError. Relative import from non-package now fails with
ImportError rather than SystemError.
8 changes: 3 additions & 5 deletions 8 Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -1461,11 +1461,9 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(partition);
}
}

if (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
"Parent module %R not loaded, cannot perform relative "
"import", package);
if (PyUnicode_GET_LENGTH(package) == 0) {
PyErr_SetString(PyExc_ImportError,
"attempted relative import with no known parent package");
goto error;
}
}
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.