Commit 8c3f05e9 authored by Milan Oberkirch's avatar Milan Oberkirch Committed by Brett Cannon

bpo-30436: Raise ModuleNotFoundError for importlib.util.find_spec() when...

bpo-30436: Raise ModuleNotFoundError for importlib.util.find_spec() when parent isn't a package (GH-1899)

Previously AttributeError was raised, but that's not very reflective of the fact that the requested module can't be found since the specified parent isn't actually a package.
parent 32fd874a
......@@ -1215,6 +1215,11 @@ an :term:`importer`.
.. versionadded:: 3.4
.. versionchanged:: 3.7
Raises :exc:`ModuleNotFoundError` instead of :exc:`AttributeError` if
**package** is in fact not a package (i.e. lacks a :attr:`__path__`
attribute).
.. function:: module_from_spec(spec)
Create a new module based on **spec** and
......
......@@ -84,11 +84,16 @@ def find_spec(name, package=None):
if fullname not in sys.modules:
parent_name = fullname.rpartition('.')[0]
if parent_name:
# Use builtins.__import__() in case someone replaced it.
parent = __import__(parent_name, fromlist=['__path__'])
return _find_spec(fullname, parent.__path__)
try:
parent_path = parent.__path__
except AttributeError as e:
raise ModuleNotFoundError(
f"__path__ attribute not found on {parent_name!r}"
f"while trying to find {fullname!r}", name=fullname) from e
else:
return _find_spec(fullname, None)
parent_path = None
return _find_spec(fullname, parent_path)
else:
module = sys.modules[fullname]
if module is None:
......
......@@ -427,7 +427,7 @@ class CmdLineTest(unittest.TestCase):
tests = (
('builtins', br'No code object available'),
('builtins.x', br'Error while finding module specification.*'
br'AttributeError'),
br'ModuleNotFoundError'),
('builtins.x.y', br'Error while finding module specification.*'
br'ModuleNotFoundError.*No module named.*not a package'),
('os.path', br'loader.*cannot handle'),
......
......@@ -522,6 +522,12 @@ class FindSpecTests:
self.assertNotIn(name, sorted(sys.modules))
self.assertNotIn(fullname, sorted(sys.modules))
def test_find_submodule_in_module(self):
# ModuleNotFoundError raised when a module is specified as
# a parent instead of a package.
with self.assertRaises(ModuleNotFoundError):
self.util.find_spec('module.name')
(Frozen_FindSpecTests,
Source_FindSpecTests
......
......@@ -441,6 +441,10 @@ Library
- bpo-30149: inspect.signature() now supports callables with
variable-argument parameters wrapped with partialmethod.
Patch by Dong-hee Na.
- bpo-30436: importlib.find_spec() raises ModuleNotFoundError instead of
AttributeError if the specified parent module is not a package
(i.e. lacks a __path__ attribute).
- bpo-30301: Fix AttributeError when using SimpleQueue.empty() under
*spawn* and *forkserver* start methods.
......
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