File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1215,6 +1215,11 @@ an :term:`importer`.
12151215
12161216 .. versionadded :: 3.4
12171217
1218+ .. versionchanged :: 3.7
1219+ Raises :exc: `ModuleNotFoundError ` instead of :exc: `AttributeError ` if
1220+ **package ** is in fact not a package (i.e. lacks a :attr: `__path__ `
1221+ attribute).
1222+
12181223.. function :: module_from_spec(spec)
12191224
12201225 Create a new module based on **spec ** and
Original file line number Diff line number Diff line change @@ -84,11 +84,16 @@ def find_spec(name, package=None):
8484 if fullname not in sys .modules :
8585 parent_name = fullname .rpartition ('.' )[0 ]
8686 if parent_name :
87- # Use builtins.__import__() in case someone replaced it.
8887 parent = __import__ (parent_name , fromlist = ['__path__' ])
89- return _find_spec (fullname , parent .__path__ )
88+ try :
89+ parent_path = parent .__path__
90+ except AttributeError as e :
91+ raise ModuleNotFoundError (
92+ f"__path__ attribute not found on { parent_name !r} "
93+ f"while trying to find { fullname !r} " , name = fullname ) from e
9094 else :
91- return _find_spec (fullname , None )
95+ parent_path = None
96+ return _find_spec (fullname , parent_path )
9297 else :
9398 module = sys .modules [fullname ]
9499 if module is None :
Original file line number Diff line number Diff line change @@ -427,7 +427,7 @@ def test_dash_m_errors(self):
427427 tests = (
428428 ('builtins' , br'No code object available' ),
429429 ('builtins.x' , br'Error while finding module specification.*'
430- br'AttributeError ' ),
430+ br'ModuleNotFoundError ' ),
431431 ('builtins.x.y' , br'Error while finding module specification.*'
432432 br'ModuleNotFoundError.*No module named.*not a package' ),
433433 ('os.path' , br'loader.*cannot handle' ),
Original file line number Diff line number Diff line change @@ -522,6 +522,12 @@ def test_find_relative_module_missing_package(self):
522522 self .assertNotIn (name , sorted (sys .modules ))
523523 self .assertNotIn (fullname , sorted (sys .modules ))
524524
525+ def test_find_submodule_in_module (self ):
526+ # ModuleNotFoundError raised when a module is specified as
527+ # a parent instead of a package.
528+ with self .assertRaises (ModuleNotFoundError ):
529+ self .util .find_spec ('module.name' )
530+
525531
526532(Frozen_FindSpecTests ,
527533 Source_FindSpecTests
Original file line number Diff line number Diff line change @@ -441,6 +441,10 @@ Library
441441- bpo-30149: inspect.signature() now supports callables with
442442 variable-argument parameters wrapped with partialmethod.
443443 Patch by Dong-hee Na.
444+
445+ - bpo-30436: importlib.find_spec() raises ModuleNotFoundError instead of
446+ AttributeError if the specified parent module is not a package
447+ (i.e. lacks a __path__ attribute).
444448
445449- bpo-30301: Fix AttributeError when using SimpleQueue.empty() under
446450 *spawn* and *forkserver* start methods.
You can’t perform that action at this time.
0 commit comments