Skip to content
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
4 changes: 4 additions & 0 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ def test_import(self):
self.assertRaises(TypeError, __import__, 1, 2, 3, 4)
self.assertRaises(ValueError, __import__, '')
self.assertRaises(TypeError, __import__, 'sys', name='sys')
# Relative import outside of a package with no __package__ or __spec__ (bpo-37409).
self.assertRaises(ImportError, __import__, '',
{'__package__': None, '__spec__': None, '__name__': '__main__'},
locals={}, fromlist=('foo',), level=1)
# embedded null character
self.assertRaises(ModuleNotFoundError, __import__, 'string\x00')

Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,11 @@ def check_relative():
ns = dict(__package__=object())
self.assertRaises(TypeError, check_relative)

def test_parentless_import_shadowed_by_global(self):
# Test as if this were done from the REPL where this error most commonly occurs (bpo-37409).
script_helper.assert_python_failure('-W', 'ignore', '-c',
"foo = 1; from . import foo")

def test_absolute_import_without_future(self):
# If explicit relative import syntax is used, then do not try
# to perform an absolute import in the face of failure.
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ Alain Leufroy
Mark Levinson
Mark Levitt
Ivan Levkivskyi
Ben Lewis
William Lewis
Akira Li
Robert Li
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Ensure explicit relative imports from interactive sessions and scripts (having no parent package) always raise ImportError, rather than treating the current module as the package.
Patch by Ben Lewis.
24 changes: 13 additions & 11 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -1647,23 +1647,20 @@ resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level
if (dot == -2) {
goto error;
}

if (dot >= 0) {
PyObject *substr = PyUnicode_Substring(package, 0, dot);
if (substr == NULL) {
goto error;
}
Py_SETREF(package, substr);
else if (dot == -1) {
goto no_parent_error;
}
PyObject *substr = PyUnicode_Substring(package, 0, dot);
if (substr == NULL) {
goto error;
}
Py_SETREF(package, substr);
}
}

last_dot = PyUnicode_GET_LENGTH(package);
if (last_dot == 0) {
_PyErr_SetString(tstate, PyExc_ImportError,
"attempted relative import "
"with no known parent package");
goto error;
goto no_parent_error;
}

for (level_up = 1; level_up < level; level_up += 1) {
Expand All @@ -1689,6 +1686,11 @@ resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level
Py_DECREF(base);
return abs_name;

no_parent_error:
_PyErr_SetString(tstate, PyExc_ImportError,
"attempted relative import "
"with no known parent package");

error:
Py_XDECREF(package);
return NULL;
Expand Down