pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/c1e7c747f92a27f1f2bb392dbbfbd2817591f44f

b48faa60c69660fa.css" /> Issue 19851: Fix a regression in reloading submodules. · python/cpython@c1e7c74 · GitHub
Skip to content

Commit c1e7c74

Browse files
Issue 19851: Fix a regression in reloading submodules.
1 parent fc25d62 commit c1e7c74

3 files changed

Lines changed: 81 additions & 4 deletions

File tree

Lib/importlib/__init__.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,17 @@ def reload(module):
153153
_RELOADING[name] = module
154154
try:
155155
parent_name = name.rpartition('.')[0]
156-
if parent_name and parent_name not in sys.modules:
157-
msg = "parent {!r} not in sys.modules"
158-
raise ImportError(msg.format(parent_name), name=parent_name)
159-
spec = module.__spec__ = _bootstrap._find_spec(name, None, module)
156+
if parent_name:
157+
try:
158+
parent = sys.modules[parent_name]
159+
except KeyError:
160+
msg = "parent {!r} not in sys.modules"
161+
raise ImportError(msg.format(parent_name), name=parent_name)
162+
else:
163+
pkgpath = parent.__path__
164+
else:
165+
pkgpath = None
166+
spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, module)
160167
methods = _bootstrap._SpecMethods(spec)
161168
methods.exec(module)
162169
# The module may have replaced itself in sys.modules!

Lib/test/test_importlib/test_api.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,45 @@
44
frozen_util, source_util = util.import_importlib('importlib.util')
55
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
66

7+
from contextlib import contextmanager
78
import os.path
89
import sys
910
from test import support
1011
import types
1112
import unittest
1213

1314

15+
@contextmanager
16+
def temp_module(name, content='', *, pkg=False):
17+
conflicts = [n for n in sys.modules if n.partition('.')[0] == name]
18+
with support.temp_cwd(None) as cwd:
19+
with util.uncache(name, *conflicts):
20+
with support.DirsOnSysPath(cwd):
21+
frozen_init.invalidate_caches()
22+
23+
location = os.path.join(cwd, name)
24+
if pkg:
25+
modpath = os.path.join(location, '__init__.py')
26+
os.mkdir(name)
27+
else:
28+
modpath = location + '.py'
29+
if content is None:
30+
# Make sure the module file gets created.
31+
content = ''
32+
if content is not None:
33+
# not a namespace package
34+
with open(modpath, 'w') as modfile:
35+
modfile.write(content)
36+
yield location
37+
38+
39+
def submodule(parent, name, pkg_dir, content=''):
40+
path = os.path.join(pkg_dir, name + '.py')
41+
with open(path, 'w') as subfile:
42+
subfile.write(content)
43+
return '{}.{}'.format(parent, name), path
44+
45+
1446
class ImportModuleTests:
1547

1648
"""Test importlib.import_module."""
@@ -246,6 +278,32 @@ def test_nothing(self):
246278
# None is returned upon failure to find a loader.
247279
self.assertIsNone(self.init.find_spec('nevergoingtofindthismodule'))
248280

281+
def test_find_submodule(self):
282+
name = 'spam'
283+
subname = 'ham'
284+
with temp_module(name, pkg=True) as pkg_dir:
285+
fullname, _ = submodule(name, subname, pkg_dir)
286+
spec = self.init.find_spec(fullname, [pkg_dir])
287+
self.assertIsNot(spec, None)
288+
self.assertNotIn(name, sorted(sys.modules))
289+
# Ensure successive calls behave the same.
290+
spec_again = self.init.find_spec(fullname, [pkg_dir])
291+
# XXX Once #19927 is resolved, uncomment this line.
292+
#self.assertEqual(spec_again, spec)
293+
294+
def test_find_submodule_missing_path(self):
295+
name = 'spam'
296+
subname = 'ham'
297+
with temp_module(name, pkg=True) as pkg_dir:
298+
fullname, _ = submodule(name, subname, pkg_dir)
299+
spec = self.init.find_spec(fullname)
300+
self.assertIs(spec, None)
301+
self.assertNotIn(name, sorted(sys.modules))
302+
# Ensure successive calls behave the same.
303+
spec = self.init.find_spec(fullname)
304+
self.assertIs(spec, None)
305+
306+
249307
class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase):
250308
init = frozen_init
251309
machinery = frozen_machinery
@@ -410,6 +468,16 @@ def test_reload_namespace_changed(self):
410468
self.assertEqual(loader.path, init_path)
411469
self.assertEqual(ns, expected)
412470

471+
def test_reload_submodule(self):
472+
# See #19851.
473+
name = 'spam'
474+
subname = 'ham'
475+
with temp_module(name, pkg=True) as pkg_dir:
476+
fullname, _ = submodule(name, subname, pkg_dir)
477+
ham = self.init.import_module(fullname)
478+
reloaded = self.init.reload(ham)
479+
self.assertIs(reloaded, ham)
480+
413481

414482
class Frozen_ReloadTests(ReloadTests, unittest.TestCase):
415483
init = frozen_init

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ Library
114114
- Issue #6477: Added support for pickling the types of built-in singletons
115115
(i.e., Ellipsis, NotImplemented, None).
116116

117+
- Issue #19851: Fixed a regression in reloading sub-modules.
118+
117119
- ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME.
118120

119121
- Issue #19802: Add socket.SO_PRIORITY.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy