From cafea0a6de333229da88be6cb710d5ca2029f2de Mon Sep 17 00:00:00 2001 From: Piotr Karkut Date: Wed, 20 Feb 2019 17:40:44 +0100 Subject: [PATCH 1/2] bpo-36053 fix pkgutil.walk_packages pkgutil.walk_packages jumps out from given path if there is package with the same name in sys.path --- Lib/pkgutil.py | 5 +-- Lib/test/test_pkgutil.py | 36 +++++++++++++++++++ .../2019-02-20-17-44-00.bpo-36053.cER52b.rst | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-02-20-17-44-00.bpo-36053.cER52b.rst diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index 8474a773e7c732..6a9e97b58417ae 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -88,8 +88,9 @@ def seen(p, m={}): yield info if info.ispkg: + loader = info.module_finder.find_module(info.name) try: - __import__(info.name) + module = loader.load_module(info.name) except ImportError: if onerror is not None: onerror(info.name) @@ -99,7 +100,7 @@ def seen(p, m={}): else: raise else: - path = getattr(sys.modules[info.name], '__path__', None) or [] + path = module.__path__ # don't traverse path items we've seen before path = [p for p in path if not seen(p)] diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index 2887ce6cc055da..2b093695db9706 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -176,6 +176,42 @@ def test_walkpackages_zipfile(self): continue del sys.modules[pkg] + def test_walk_packages_with_same_package_name_in_pythonpath(self): + pkg1 = 'test_walk_packages_with_same_package_name_in_pythonpath' + pkg1_dir = os.path.join(self.dirname, pkg1) + os.mkdir(pkg1_dir) + f = open(os.path.join(pkg1_dir, '__init__.py'), "wb") + f.close() + os.mkdir(os.path.join(pkg1_dir, 'same_name')) + f = open(os.path.join(pkg1_dir, 'same_name', '__init__.py'), "wb") + f.close() + f = open(os.path.join(pkg1_dir, 'same_name', 'mod.py'), "wb") + f.close() + + # Add another package in the path, with the same name as the one inside pkg1 + pkg2 = 'same_name' + pkg2_dir = os.path.join(self.dirname, pkg2) + os.mkdir(pkg2_dir) + f = open(os.path.join(pkg2_dir, '__init__.py'), "wb") + f.close() + os.mkdir(os.path.join(pkg2_dir, 'test_same_name')) + f = open(os.path.join(pkg2_dir, 'test_same_name', '__init__.py'), "wb") + f.close() + f = open(os.path.join(pkg2_dir, 'test_same_name', 'another_mod.py'), "wb") + f.close() + + expected = [ + 'same_name', + 'same_name.mod' + ] + actual = [e[1] for e in pkgutil.walk_packages([os.path.join(self.dirname, pkg1)])] + self.assertEqual(actual, expected) + + for pkg in expected: + if pkg.endswith('mod'): + continue + del sys.modules[pkg] + def test_walk_packages_raises_on_string_or_bytes_input(self): str_input = 'test_dir' diff --git a/Misc/NEWS.d/next/Library/2019-02-20-17-44-00.bpo-36053.cER52b.rst b/Misc/NEWS.d/next/Library/2019-02-20-17-44-00.bpo-36053.cER52b.rst new file mode 100644 index 00000000000000..93ccd0598e7275 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-02-20-17-44-00.bpo-36053.cER52b.rst @@ -0,0 +1 @@ +Fix ``pkgutil.walk_packages()`` jumping outside given path if a package with the same name is available inside ``sys.path``. Patch by Piotr Karkut. From 0e6192352666aa090076294620494178441c7756 Mon Sep 17 00:00:00 2001 From: Piotr Karkut Date: Tue, 11 Jun 2019 08:35:23 +0200 Subject: [PATCH 2/2] bpo-36053 fix tests cleanup --- Lib/test/test_pkgutil.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index 2b093695db9706..ec88bc017438ad 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -1,4 +1,4 @@ -from test.support import run_unittest, unload, check_warnings, CleanImport +from test.support import forget, run_unittest, unload, check_warnings, CleanImport import unittest import sys import importlib @@ -204,13 +204,12 @@ def test_walk_packages_with_same_package_name_in_pythonpath(self): 'same_name', 'same_name.mod' ] - actual = [e[1] for e in pkgutil.walk_packages([os.path.join(self.dirname, pkg1)])] - self.assertEqual(actual, expected) for pkg in expected: - if pkg.endswith('mod'): - continue - del sys.modules[pkg] + self.addCleanup(forget, pkg) + + actual = [e[1] for e in pkgutil.walk_packages([os.path.join(self.dirname, pkg1)])] + self.assertEqual(actual, expected) def test_walk_packages_raises_on_string_or_bytes_input(self):