Skip to content

Commit b60a43e

Browse files
committed
Add a reset_name argument to importlib.util.module_to_load in order to
control whether to reset the module's __name__ attribute in case a reload is being done.
1 parent 028d512 commit b60a43e

3 files changed

Lines changed: 30 additions & 2 deletions

File tree

Doc/library/importlib.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,14 +788,18 @@ an :term:`importer`.
788788

789789
.. versionadded:: 3.3
790790

791-
.. function:: module_to_load(name)
791+
.. function:: module_to_load(name, *, reset_name=True)
792792

793793
Returns a :term:`context manager` which provides the module to load. The
794794
module will either come from :attr:`sys.modules` in the case of reloading or
795795
a fresh module if loading a new module. Proper cleanup of
796796
:attr:`sys.modules` occurs if the module was new and an exception was
797797
raised.
798798

799+
If **reset_name** is true and the module requested is being reloaded then
800+
the module's :attr:`__name__` attribute will
801+
be reset to **name**, else it will be left untouched.
802+
799803
.. versionadded:: 3.4
800804

801805
.. decorator:: module_for_loader

Lib/importlib/_bootstrap.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,14 @@ class _ModuleManager:
493493
494494
"""
495495

496-
def __init__(self, name):
496+
def __init__(self, name, *, reset_name=True):
497+
"""Prepare the context manager.
498+
499+
The reset_name argument specifies whether to unconditionally reset
500+
the __name__ attribute if the module is found to be a reload.
501+
"""
497502
self._name = name
503+
self._reset_name = reset_name
498504

499505
def __enter__(self):
500506
self._module = sys.modules.get(self._name)
@@ -508,6 +514,12 @@ def __enter__(self):
508514
# (otherwise an optimization shortcut in import.c becomes wrong)
509515
self._module.__initializing__ = True
510516
sys.modules[self._name] = self._module
517+
elif self._reset_name:
518+
try:
519+
self._module.__name__ = self._name
520+
except AttributeError:
521+
pass
522+
511523
return self._module
512524

513525
def __exit__(self, *args):

Lib/test/test_importlib/test_util.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ def test_reload_failed(self):
5555
else:
5656
self.fail('importlib.util.module_to_load swallowed an exception')
5757

58+
def test_reset_name(self):
59+
# If reset_name is true then module.__name__ = name, else leave it be.
60+
odd_name = 'not your typical name'
61+
created_module = imp.new_module(self.module_name)
62+
created_module.__name__ = odd_name
63+
sys.modules[self.module_name] = created_module
64+
with util.module_to_load(self.module_name) as module:
65+
self.assertEqual(module.__name__, self.module_name)
66+
created_module.__name__ = odd_name
67+
with util.module_to_load(self.module_name, reset_name=False) as module:
68+
self.assertEqual(module.__name__, odd_name)
69+
5870

5971
class ModuleForLoaderTests(unittest.TestCase):
6072

0 commit comments

Comments
 (0)