From 5086589305ff5538709856b27314b68f06ae93db Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 22 Mar 2019 15:16:50 -0700 Subject: bpo-36298: Raise ModuleNotFoundError in pyclbr when a module can't be found (GH-12358) Before, an `AttributeError` was raised due to trying to access an attribute that exists on specs but having received `None` instead for a non-existent module. https://bugs.python.org/issue36298 --- Lib/pyclbr.py | 7 +++++-- Lib/test/test_pyclbr.py | 24 ++++++++++++++++++++-- .../2019-03-15-13-54-07.bpo-36298.amEVK2.rst | 2 ++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-03-15-13-54-07.bpo-36298.amEVK2.rst diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 2c798df..8fd0523 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -160,17 +160,20 @@ def _readmodule(module, path, inpackage=None): else: search_path = path + sys.path spec = importlib.util._find_spec_from_path(fullmodule, search_path) + if spec is None: + raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) _modules[fullmodule] = tree # Is module a package? if spec.submodule_search_locations is not None: tree['__path__'] = spec.submodule_search_locations try: source = spec.loader.get_source(fullmodule) - if source is None: - return tree except (AttributeError, ImportError): # If module is not Python source, we cannot do anything. return tree + else: + if source is None: + return tree fname = spec.loader.get_filename(fullmodule) return _create_tree(fullmodule, path, fname, source, tree, inpackage) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 9e970d9..839c58f 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -10,6 +10,7 @@ from types import FunctionType, MethodType, BuiltinFunctionType import pyclbr from unittest import TestCase, main as unittest_main from test import support +from test.test_importlib import util as test_importlib_util from functools import partial StaticMethodType = type(staticmethod(lambda: None)) @@ -235,11 +236,30 @@ class PyclbrTest(TestCase): cm('email.parser') cm('test.test_pyclbr') - def test_issue_14798(self): + +class ReadmoduleTests(TestCase): + + def setUp(self): + self._modules = pyclbr._modules.copy() + + def tearDown(self): + pyclbr._modules = self._modules + + + def test_dotted_name_not_a_package(self): # test ImportError is raised when the first part of a dotted name is - # not a package + # not a package. + # + # Issue #14798. self.assertRaises(ImportError, pyclbr.readmodule_ex, 'asyncore.foo') + def test_module_has_no_spec(self): + module_name = "doesnotexist" + assert module_name not in pyclbr._modules + with test_importlib_util.uncache(module_name): + with self.assertRaises(ModuleNotFoundError): + pyclbr.readmodule_ex(module_name) + if __name__ == "__main__": unittest_main() diff --git a/Misc/NEWS.d/next/Library/2019-03-15-13-54-07.bpo-36298.amEVK2.rst b/Misc/NEWS.d/next/Library/2019-03-15-13-54-07.bpo-36298.amEVK2.rst new file mode 100644 index 0000000..14be079 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-03-15-13-54-07.bpo-36298.amEVK2.rst @@ -0,0 +1,2 @@ +Raise ModuleNotFoundError in pyclbr when a module can't be found. +Thanks to 'mental' for the bug report. -- cgit v0.12