|
4 | 4 | frozen_util, source_util = util.import_importlib('importlib.util') |
5 | 5 | frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') |
6 | 6 |
|
| 7 | +from contextlib import contextmanager |
7 | 8 | import os.path |
8 | 9 | import sys |
9 | 10 | from test import support |
10 | 11 | import types |
11 | 12 | import unittest |
12 | 13 |
|
13 | 14 |
|
| 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 | + |
14 | 46 | class ImportModuleTests: |
15 | 47 |
|
16 | 48 | """Test importlib.import_module.""" |
@@ -246,6 +278,32 @@ def test_nothing(self): |
246 | 278 | # None is returned upon failure to find a loader. |
247 | 279 | self.assertIsNone(self.init.find_spec('nevergoingtofindthismodule')) |
248 | 280 |
|
| 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 | + |
249 | 307 | class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase): |
250 | 308 | init = frozen_init |
251 | 309 | machinery = frozen_machinery |
@@ -410,6 +468,16 @@ def test_reload_namespace_changed(self): |
410 | 468 | self.assertEqual(loader.path, init_path) |
411 | 469 | self.assertEqual(ns, expected) |
412 | 470 |
|
| 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 | + |
413 | 481 |
|
414 | 482 | class Frozen_ReloadTests(ReloadTests, unittest.TestCase): |
415 | 483 | init = frozen_init |
|
0 commit comments