https://github.com/python/cpython/commit/a030bae58498aa9e1bdecc355638383a109168bd
commit: a030bae58498aa9e1bdecc355638383a109168bd
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2024-04-30T14:52:44Z
summary:

[3.12] gh-117860: Add tests for resolving names when import rebind names 
(GH-118176) (GH-118432)

Add tests for "import", pkgutil.resolve_name() and unittest.mock.path()
for cases when "import a.b as x" and "from a import b as x" give
different results.
(cherry picked from commit c0eaa232f63a62e0e0408911ab5f118dca2af607)

Co-authored-by: Serhiy Storchaka <[email protected]>

files:
A Lib/test/test_import/data/package3/__init__.py
A Lib/test/test_import/data/package3/submodule.py
A Lib/test/test_import/data/package4/__init__.py
A Lib/test/test_import/data/package4/submodule.py
M Lib/test/test_import/__init__.py
M Lib/test/test_pkgutil.py
M Lib/test/test_unittest/testmock/testpatch.py
M Makefile.pre.in

diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 0e38e483dc28db..c6accc4183a67f 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -1089,6 +1089,34 @@ def test_import_from_unloaded_package(self):
             import package2.submodule1
             package2.submodule1.submodule2
 
+    def test_rebinding(self):
+        # The same data is also used for testing pkgutil.resolve_name()
+        # in test_pkgutil and mock.patch in test_unittest.
+        path = os.path.join(os.path.dirname(__file__), 'data')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            from package3 import submodule
+            self.assertEqual(submodule.attr, 'rebound')
+            import package3.submodule as submodule
+            self.assertEqual(submodule.attr, 'rebound')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            import package3.submodule as submodule
+            self.assertEqual(submodule.attr, 'rebound')
+            from package3 import submodule
+            self.assertEqual(submodule.attr, 'rebound')
+
+    def test_rebinding2(self):
+        path = os.path.join(os.path.dirname(__file__), 'data')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            import package4.submodule as submodule
+            self.assertEqual(submodule.attr, 'submodule')
+            from package4 import submodule
+            self.assertEqual(submodule.attr, 'submodule')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            from package4 import submodule
+            self.assertEqual(submodule.attr, 'origin')
+            import package4.submodule as submodule
+            self.assertEqual(submodule.attr, 'submodule')
+
 
 class OverridingImportBuiltinTests(unittest.TestCase):
     def test_override_builtin(self):
diff --git a/Lib/test/test_import/data/package3/__init__.py 
b/Lib/test/test_import/data/package3/__init__.py
new file mode 100644
index 00000000000000..7033c22a719ec4
--- /dev/null
+++ b/Lib/test/test_import/data/package3/__init__.py
@@ -0,0 +1,2 @@
+"""Rebinding the package attribute after importing the module."""
+from .submodule import submodule
diff --git a/Lib/test/test_import/data/package3/submodule.py 
b/Lib/test/test_import/data/package3/submodule.py
new file mode 100644
index 00000000000000..cd7b30db15e449
--- /dev/null
+++ b/Lib/test/test_import/data/package3/submodule.py
@@ -0,0 +1,7 @@
+attr = 'submodule'
+class A:
+    attr = 'submodule'
+class submodule:
+    attr = 'rebound'
+    class B:
+        attr = 'rebound'
diff --git a/Lib/test/test_import/data/package4/__init__.py 
b/Lib/test/test_import/data/package4/__init__.py
new file mode 100644
index 00000000000000..d8af60ab38a319
--- /dev/null
+++ b/Lib/test/test_import/data/package4/__init__.py
@@ -0,0 +1,5 @@
+"""Binding the package attribute without importing the module."""
+class submodule:
+    attr = 'origin'
+    class B:
+        attr = 'origin'
diff --git a/Lib/test/test_import/data/package4/submodule.py 
b/Lib/test/test_import/data/package4/submodule.py
new file mode 100644
index 00000000000000..c861417aece9c3
--- /dev/null
+++ b/Lib/test/test_import/data/package4/submodule.py
@@ -0,0 +1,3 @@
+attr = 'submodule'
+class A:
+    attr = 'submodule'
diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py
index 6fcd726345eeac..e19dce1dbd2583 100644
--- a/Lib/test/test_pkgutil.py
+++ b/Lib/test/test_pkgutil.py
@@ -12,6 +12,9 @@
 import shutil
 import zipfile
 
+from test.support.import_helper import DirsOnSysPath
+from test.test_importlib.util import uncache
+
 # Note: pkgutil.walk_packages is currently tested in test_runpy. This is
 # a hack to get a major issue resolved for 3.3b2. Longer term, it should
 # be moved back here, perhaps by factoring out the helper code for
@@ -318,6 +321,38 @@ def test_name_resolution(self):
                 with self.assertRaises(exc):
                     pkgutil.resolve_name(s)
 
+    def test_name_resolution_import_rebinding(self):
+        # The same data is also used for testing import in test_import and
+        # mock.patch in test_unittest.
+        path = os.path.join(os.path.dirname(__file__), 'test_import', 'data')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package3.submodule.attr'), 
'submodule')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package3.submodule:attr'), 
'submodule')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 
'rebound')
+            self.assertEqual(pkgutil.resolve_name('package3.submodule.attr'), 
'submodule')
+            self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 
'rebound')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 
'rebound')
+            self.assertEqual(pkgutil.resolve_name('package3.submodule:attr'), 
'submodule')
+            self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 
'rebound')
+
+    def test_name_resolution_import_rebinding2(self):
+        path = os.path.join(os.path.dirname(__file__), 'test_import', 'data')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package4.submodule.attr'), 
'submodule')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package4.submodule:attr'), 
'submodule')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 
'origin')
+            self.assertEqual(pkgutil.resolve_name('package4.submodule.attr'), 
'submodule')
+            self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 
'submodule')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 
'origin')
+            self.assertEqual(pkgutil.resolve_name('package4.submodule:attr'), 
'submodule')
+            self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 
'submodule')
+
 
 class PkgutilPEP302Tests(unittest.TestCase):
 
diff --git a/Lib/test/test_unittest/testmock/testpatch.py 
b/Lib/test/test_unittest/testmock/testpatch.py
index d0046d702a53f4..be75fda7826af1 100644
--- a/Lib/test/test_unittest/testmock/testpatch.py
+++ b/Lib/test/test_unittest/testmock/testpatch.py
@@ -7,9 +7,11 @@
 from collections import OrderedDict
 
 import unittest
+import test
 from test.test_unittest.testmock import support
 from test.test_unittest.testmock.support import SomeClass, is_instance
 
+from test.support.import_helper import DirsOnSysPath
 from test.test_importlib.util import uncache
 from unittest.mock import (
     NonCallableMock, CallableMixin, sentinel,
@@ -1728,6 +1730,71 @@ def test(mock):
                             'exception traceback not propagated')
 
 
+    def test_name_resolution_import_rebinding(self):
+        # Currently mock.patch uses pkgutil.resolve_name(), but repeat
+        # similar tests just for the case.
+        # The same data is also used for testing import in test_import and
+        # pkgutil.resolve_name() in test_pkgutil.
+        path = os.path.join(os.path.dirname(test.__file__), 'test_import', 
'data')
+        def check(name):
+            p = patch(name)
+            p.start()
+            p.stop()
+        def check_error(name):
+            p = patch(name)
+            self.assertRaises(AttributeError, p.start)
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            check('package3.submodule.A.attr')
+            check_error('package3.submodule.B.attr')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            check('package3.submodule:A.attr')
+            check_error('package3.submodule:B.attr')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            check('package3:submodule.B.attr')
+            check_error('package3:submodule.A.attr')
+            check('package3.submodule.A.attr')
+            check_error('package3.submodule.B.attr')
+            check('package3:submodule.B.attr')
+            check_error('package3:submodule.A.attr')
+        with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
+            check('package3:submodule.B.attr')
+            check_error('package3:submodule.A.attr')
+            check('package3.submodule:A.attr')
+            check_error('package3.submodule:B.attr')
+            check('package3:submodule.B.attr')
+            check_error('package3:submodule.A.attr')
+
+    def test_name_resolution_import_rebinding2(self):
+        path = os.path.join(os.path.dirname(test.__file__), 'test_import', 
'data')
+        def check(name):
+            p = patch(name)
+            p.start()
+            p.stop()
+        def check_error(name):
+            p = patch(name)
+            self.assertRaises(AttributeError, p.start)
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            check('package4.submodule.A.attr')
+            check_error('package4.submodule.B.attr')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            check('package4.submodule:A.attr')
+            check_error('package4.submodule:B.attr')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            check('package4:submodule.B.attr')
+            check_error('package4:submodule.A.attr')
+            check('package4.submodule.A.attr')
+            check_error('package4.submodule.B.attr')
+            check('package4:submodule.A.attr')
+            check_error('package4:submodule.B.attr')
+        with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
+            check('package4:submodule.B.attr')
+            check_error('package4:submodule.A.attr')
+            check('package4.submodule:A.attr')
+            check_error('package4.submodule:B.attr')
+            check('package4:submodule.A.attr')
+            check_error('package4:submodule.B.attr')
+
+
     def test_create_and_specs(self):
         for kwarg in ('spec', 'spec_set', 'autospec'):
             p = patch('%s.doesnotexist' % __name__, create=True,
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 27a26c225230b4..548a4ec8a58c76 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2157,6 +2157,8 @@ TESTSUBDIRS=      idlelib/idle_test \
                test/test_import/data/circular_imports/subpkg2/parent \
                test/test_import/data/package \
                test/test_import/data/package2 \
+               test/test_import/data/package3 \
+               test/test_import/data/package4 \
                test/test_import/data/unwritable \
                test/test_importlib \
                test/test_importlib/builtin \

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to