• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# We import importlib *ASAP* in order to test #15386
2import importlib
3import importlib.util
4from importlib._bootstrap_external import _get_sourcefile
5import builtins
6import marshal
7import os
8import py_compile
9import random
10import shutil
11import subprocess
12import stat
13import sys
14import threading
15import time
16import unittest
17import unittest.mock as mock
18import textwrap
19import errno
20import contextlib
21import glob
22
23import test.support
24from test.support import (
25    TESTFN, forget, is_jython,
26    make_legacy_pyc, rmtree, swap_attr, swap_item, temp_umask,
27    unlink, unload, cpython_only, TESTFN_UNENCODABLE,
28    temp_dir, DirsOnSysPath)
29from test.support import script_helper
30from test.test_importlib.util import uncache
31
32
33skip_if_dont_write_bytecode = unittest.skipIf(
34        sys.dont_write_bytecode,
35        "test meaningful only when writing bytecode")
36
37def remove_files(name):
38    for f in (name + ".py",
39              name + ".pyc",
40              name + ".pyw",
41              name + "$py.class"):
42        unlink(f)
43    rmtree('__pycache__')
44
45
46@contextlib.contextmanager
47def _ready_to_import(name=None, source=""):
48    # sets up a temporary directory and removes it
49    # creates the module file
50    # temporarily clears the module from sys.modules (if any)
51    # reverts or removes the module when cleaning up
52    name = name or "spam"
53    with temp_dir() as tempdir:
54        path = script_helper.make_script(tempdir, name, source)
55        old_module = sys.modules.pop(name, None)
56        try:
57            sys.path.insert(0, tempdir)
58            yield name, path
59            sys.path.remove(tempdir)
60        finally:
61            if old_module is not None:
62                sys.modules[name] = old_module
63            elif name in sys.modules:
64                del sys.modules[name]
65
66
67class ImportTests(unittest.TestCase):
68
69    def setUp(self):
70        remove_files(TESTFN)
71        importlib.invalidate_caches()
72
73    def tearDown(self):
74        unload(TESTFN)
75
76    def test_import_raises_ModuleNotFoundError(self):
77        with self.assertRaises(ModuleNotFoundError):
78            import something_that_should_not_exist_anywhere
79
80    def test_from_import_missing_module_raises_ModuleNotFoundError(self):
81        with self.assertRaises(ModuleNotFoundError):
82            from something_that_should_not_exist_anywhere import blah
83
84    def test_from_import_missing_attr_raises_ImportError(self):
85        with self.assertRaises(ImportError):
86            from importlib import something_that_should_not_exist_anywhere
87
88    def test_from_import_missing_attr_has_name_and_path(self):
89        with self.assertRaises(ImportError) as cm:
90            from os import i_dont_exist
91        self.assertEqual(cm.exception.name, 'os')
92        self.assertEqual(cm.exception.path, os.__file__)
93        self.assertRegex(str(cm.exception), r"cannot import name 'i_dont_exist' from 'os' \(.*os.py\)")
94
95    @cpython_only
96    def test_from_import_missing_attr_has_name_and_so_path(self):
97        import _testcapi
98        with self.assertRaises(ImportError) as cm:
99            from _testcapi import i_dont_exist
100        self.assertEqual(cm.exception.name, '_testcapi')
101        self.assertEqual(cm.exception.path, _testcapi.__file__)
102        self.assertRegex(str(cm.exception), r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)")
103
104    def test_from_import_missing_attr_has_name(self):
105        with self.assertRaises(ImportError) as cm:
106            # _warning has no path as it's a built-in module.
107            from _warning import i_dont_exist
108        self.assertEqual(cm.exception.name, '_warning')
109        self.assertIsNone(cm.exception.path)
110
111    def test_from_import_missing_attr_path_is_canonical(self):
112        with self.assertRaises(ImportError) as cm:
113            from os.path import i_dont_exist
114        self.assertIn(cm.exception.name, {'posixpath', 'ntpath'})
115        self.assertIsNotNone(cm.exception)
116
117    def test_from_import_star_invalid_type(self):
118        import re
119        with _ready_to_import() as (name, path):
120            with open(path, 'w') as f:
121                f.write("__all__ = [b'invalid_type']")
122            globals = {}
123            with self.assertRaisesRegex(
124                TypeError, f"{re.escape(name)}\\.__all__ must be str"
125            ):
126                exec(f"from {name} import *", globals)
127            self.assertNotIn(b"invalid_type", globals)
128        with _ready_to_import() as (name, path):
129            with open(path, 'w') as f:
130                f.write("globals()[b'invalid_type'] = object()")
131            globals = {}
132            with self.assertRaisesRegex(
133                TypeError, f"{re.escape(name)}\\.__dict__ must be str"
134            ):
135                exec(f"from {name} import *", globals)
136            self.assertNotIn(b"invalid_type", globals)
137
138    def test_case_sensitivity(self):
139        # Brief digression to test that import is case-sensitive:  if we got
140        # this far, we know for sure that "random" exists.
141        with self.assertRaises(ImportError):
142            import RAnDoM
143
144    def test_double_const(self):
145        # Another brief digression to test the accuracy of manifest float
146        # constants.
147        from test import double_const  # don't blink -- that *was* the test
148
149    def test_import(self):
150        def test_with_extension(ext):
151            # The extension is normally ".py", perhaps ".pyw".
152            source = TESTFN + ext
153            if is_jython:
154                pyc = TESTFN + "$py.class"
155            else:
156                pyc = TESTFN + ".pyc"
157
158            with open(source, "w") as f:
159                print("# This tests Python's ability to import a",
160                      ext, "file.", file=f)
161                a = random.randrange(1000)
162                b = random.randrange(1000)
163                print("a =", a, file=f)
164                print("b =", b, file=f)
165
166            if TESTFN in sys.modules:
167                del sys.modules[TESTFN]
168            importlib.invalidate_caches()
169            try:
170                try:
171                    mod = __import__(TESTFN)
172                except ImportError as err:
173                    self.fail("import from %s failed: %s" % (ext, err))
174
175                self.assertEqual(mod.a, a,
176                    "module loaded (%s) but contents invalid" % mod)
177                self.assertEqual(mod.b, b,
178                    "module loaded (%s) but contents invalid" % mod)
179            finally:
180                forget(TESTFN)
181                unlink(source)
182                unlink(pyc)
183
184        sys.path.insert(0, os.curdir)
185        try:
186            test_with_extension(".py")
187            if sys.platform.startswith("win"):
188                for ext in [".PY", ".Py", ".pY", ".pyw", ".PYW", ".pYw"]:
189                    test_with_extension(ext)
190        finally:
191            del sys.path[0]
192
193    def test_module_with_large_stack(self, module='longlist'):
194        # Regression test for http://bugs.python.org/issue561858.
195        filename = module + '.py'
196
197        # Create a file with a list of 65000 elements.
198        with open(filename, 'w') as f:
199            f.write('d = [\n')
200            for i in range(65000):
201                f.write('"",\n')
202            f.write(']')
203
204        try:
205            # Compile & remove .py file; we only need .pyc.
206            # Bytecode must be relocated from the PEP 3147 bytecode-only location.
207            py_compile.compile(filename)
208        finally:
209            unlink(filename)
210
211        # Need to be able to load from current dir.
212        sys.path.append('')
213        importlib.invalidate_caches()
214
215        namespace = {}
216        try:
217            make_legacy_pyc(filename)
218            # This used to crash.
219            exec('import ' + module, None, namespace)
220        finally:
221            # Cleanup.
222            del sys.path[-1]
223            unlink(filename + 'c')
224            unlink(filename + 'o')
225
226            # Remove references to the module (unload the module)
227            namespace.clear()
228            try:
229                del sys.modules[module]
230            except KeyError:
231                pass
232
233    def test_failing_import_sticks(self):
234        source = TESTFN + ".py"
235        with open(source, "w") as f:
236            print("a = 1/0", file=f)
237
238        # New in 2.4, we shouldn't be able to import that no matter how often
239        # we try.
240        sys.path.insert(0, os.curdir)
241        importlib.invalidate_caches()
242        if TESTFN in sys.modules:
243            del sys.modules[TESTFN]
244        try:
245            for i in [1, 2, 3]:
246                self.assertRaises(ZeroDivisionError, __import__, TESTFN)
247                self.assertNotIn(TESTFN, sys.modules,
248                                 "damaged module in sys.modules on %i try" % i)
249        finally:
250            del sys.path[0]
251            remove_files(TESTFN)
252
253    def test_import_name_binding(self):
254        # import x.y.z binds x in the current namespace
255        import test as x
256        import test.support
257        self.assertIs(x, test, x.__name__)
258        self.assertTrue(hasattr(test.support, "__file__"))
259
260        # import x.y.z as w binds z as w
261        import test.support as y
262        self.assertIs(y, test.support, y.__name__)
263
264    def test_issue31286(self):
265        # import in a 'finally' block resulted in SystemError
266        try:
267            x = ...
268        finally:
269            import test.support.script_helper as x
270
271        # import in a 'while' loop resulted in stack overflow
272        i = 0
273        while i < 10:
274            import test.support.script_helper as x
275            i += 1
276
277        # import in a 'for' loop resulted in segmentation fault
278        for i in range(2):
279            import test.support.script_helper as x
280
281    def test_failing_reload(self):
282        # A failing reload should leave the module object in sys.modules.
283        source = TESTFN + os.extsep + "py"
284        with open(source, "w") as f:
285            f.write("a = 1\nb=2\n")
286
287        sys.path.insert(0, os.curdir)
288        try:
289            mod = __import__(TESTFN)
290            self.assertIn(TESTFN, sys.modules)
291            self.assertEqual(mod.a, 1, "module has wrong attribute values")
292            self.assertEqual(mod.b, 2, "module has wrong attribute values")
293
294            # On WinXP, just replacing the .py file wasn't enough to
295            # convince reload() to reparse it.  Maybe the timestamp didn't
296            # move enough.  We force it to get reparsed by removing the
297            # compiled file too.
298            remove_files(TESTFN)
299
300            # Now damage the module.
301            with open(source, "w") as f:
302                f.write("a = 10\nb=20//0\n")
303
304            self.assertRaises(ZeroDivisionError, importlib.reload, mod)
305            # But we still expect the module to be in sys.modules.
306            mod = sys.modules.get(TESTFN)
307            self.assertIsNotNone(mod, "expected module to be in sys.modules")
308
309            # We should have replaced a w/ 10, but the old b value should
310            # stick.
311            self.assertEqual(mod.a, 10, "module has wrong attribute values")
312            self.assertEqual(mod.b, 2, "module has wrong attribute values")
313
314        finally:
315            del sys.path[0]
316            remove_files(TESTFN)
317            unload(TESTFN)
318
319    @skip_if_dont_write_bytecode
320    def test_file_to_source(self):
321        # check if __file__ points to the source file where available
322        source = TESTFN + ".py"
323        with open(source, "w") as f:
324            f.write("test = None\n")
325
326        sys.path.insert(0, os.curdir)
327        try:
328            mod = __import__(TESTFN)
329            self.assertTrue(mod.__file__.endswith('.py'))
330            os.remove(source)
331            del sys.modules[TESTFN]
332            make_legacy_pyc(source)
333            importlib.invalidate_caches()
334            mod = __import__(TESTFN)
335            base, ext = os.path.splitext(mod.__file__)
336            self.assertEqual(ext, '.pyc')
337        finally:
338            del sys.path[0]
339            remove_files(TESTFN)
340            if TESTFN in sys.modules:
341                del sys.modules[TESTFN]
342
343    def test_import_by_filename(self):
344        path = os.path.abspath(TESTFN)
345        encoding = sys.getfilesystemencoding()
346        try:
347            path.encode(encoding)
348        except UnicodeEncodeError:
349            self.skipTest('path is not encodable to {}'.format(encoding))
350        with self.assertRaises(ImportError) as c:
351            __import__(path)
352
353    def test_import_in_del_does_not_crash(self):
354        # Issue 4236
355        testfn = script_helper.make_script('', TESTFN, textwrap.dedent("""\
356            import sys
357            class C:
358               def __del__(self):
359                  import importlib
360            sys.argv.insert(0, C())
361            """))
362        script_helper.assert_python_ok(testfn)
363
364    @skip_if_dont_write_bytecode
365    def test_timestamp_overflow(self):
366        # A modification timestamp larger than 2**32 should not be a problem
367        # when importing a module (issue #11235).
368        sys.path.insert(0, os.curdir)
369        try:
370            source = TESTFN + ".py"
371            compiled = importlib.util.cache_from_source(source)
372            with open(source, 'w') as f:
373                pass
374            try:
375                os.utime(source, (2 ** 33 - 5, 2 ** 33 - 5))
376            except OverflowError:
377                self.skipTest("cannot set modification time to large integer")
378            except OSError as e:
379                if e.errno not in (getattr(errno, 'EOVERFLOW', None),
380                                   getattr(errno, 'EINVAL', None)):
381                    raise
382                self.skipTest("cannot set modification time to large integer ({})".format(e))
383            __import__(TESTFN)
384            # The pyc file was created.
385            os.stat(compiled)
386        finally:
387            del sys.path[0]
388            remove_files(TESTFN)
389
390    def test_bogus_fromlist(self):
391        try:
392            __import__('http', fromlist=['blah'])
393        except ImportError:
394            self.fail("fromlist must allow bogus names")
395
396    @cpython_only
397    def test_delete_builtins_import(self):
398        args = ["-c", "del __builtins__.__import__; import os"]
399        popen = script_helper.spawn_python(*args)
400        stdout, stderr = popen.communicate()
401        self.assertIn(b"ImportError", stdout)
402
403    def test_from_import_message_for_nonexistent_module(self):
404        with self.assertRaisesRegex(ImportError, "^No module named 'bogus'"):
405            from bogus import foo
406
407    def test_from_import_message_for_existing_module(self):
408        with self.assertRaisesRegex(ImportError, "^cannot import name 'bogus'"):
409            from re import bogus
410
411    def test_from_import_AttributeError(self):
412        # Issue #24492: trying to import an attribute that raises an
413        # AttributeError should lead to an ImportError.
414        class AlwaysAttributeError:
415            def __getattr__(self, _):
416                raise AttributeError
417
418        module_name = 'test_from_import_AttributeError'
419        self.addCleanup(unload, module_name)
420        sys.modules[module_name] = AlwaysAttributeError()
421        with self.assertRaises(ImportError) as cm:
422            from test_from_import_AttributeError import does_not_exist
423
424        self.assertEqual(str(cm.exception),
425            "cannot import name 'does_not_exist' from '<unknown module name>' (unknown location)")
426
427    @cpython_only
428    def test_issue31492(self):
429        # There shouldn't be an assertion failure in case of failing to import
430        # from a module with a bad __name__ attribute, or in case of failing
431        # to access an attribute of such a module.
432        with swap_attr(os, '__name__', None):
433            with self.assertRaises(ImportError):
434                from os import does_not_exist
435
436            with self.assertRaises(AttributeError):
437                os.does_not_exist
438
439    def test_concurrency(self):
440        sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'data'))
441        try:
442            exc = None
443            def run():
444                event.wait()
445                try:
446                    import package
447                except BaseException as e:
448                    nonlocal exc
449                    exc = e
450
451            for i in range(10):
452                event = threading.Event()
453                threads = [threading.Thread(target=run) for x in range(2)]
454                try:
455                    with test.support.start_threads(threads, event.set):
456                        time.sleep(0)
457                finally:
458                    sys.modules.pop('package', None)
459                    sys.modules.pop('package.submodule', None)
460                if exc is not None:
461                    raise exc
462        finally:
463            del sys.path[0]
464
465    @unittest.skipUnless(sys.platform == "win32", "Windows-specific")
466    def test_dll_dependency_import(self):
467        from _winapi import GetModuleFileName
468        dllname = GetModuleFileName(sys.dllhandle)
469        pydname = importlib.util.find_spec("_sqlite3").origin
470        depname = os.path.join(
471            os.path.dirname(pydname),
472            "sqlite3{}.dll".format("_d" if "_d" in pydname else ""))
473
474        with test.support.temp_dir() as tmp:
475            tmp2 = os.path.join(tmp, "DLLs")
476            os.mkdir(tmp2)
477
478            pyexe = os.path.join(tmp, os.path.basename(sys.executable))
479            shutil.copy(sys.executable, pyexe)
480            shutil.copy(dllname, tmp)
481            for f in glob.glob(os.path.join(glob.escape(sys.prefix), "vcruntime*.dll")):
482                shutil.copy(f, tmp)
483
484            shutil.copy(pydname, tmp2)
485
486            env = None
487            env = {k.upper(): os.environ[k] for k in os.environ}
488            env["PYTHONPATH"] = tmp2 + ";" + os.path.dirname(os.__file__)
489
490            # Test 1: import with added DLL directory
491            subprocess.check_call([
492                pyexe, "-Sc", ";".join([
493                    "import os",
494                    "p = os.add_dll_directory({!r})".format(
495                        os.path.dirname(depname)),
496                    "import _sqlite3",
497                    "p.close"
498                ])],
499                stderr=subprocess.STDOUT,
500                env=env,
501                cwd=os.path.dirname(pyexe))
502
503            # Test 2: import with DLL adjacent to PYD
504            shutil.copy(depname, tmp2)
505            subprocess.check_call([pyexe, "-Sc", "import _sqlite3"],
506                                    stderr=subprocess.STDOUT,
507                                    env=env,
508                                    cwd=os.path.dirname(pyexe))
509
510
511@skip_if_dont_write_bytecode
512class FilePermissionTests(unittest.TestCase):
513    # tests for file mode on cached .pyc files
514
515    @unittest.skipUnless(os.name == 'posix',
516                         "test meaningful only on posix systems")
517    def test_creation_mode(self):
518        mask = 0o022
519        with temp_umask(mask), _ready_to_import() as (name, path):
520            cached_path = importlib.util.cache_from_source(path)
521            module = __import__(name)
522            if not os.path.exists(cached_path):
523                self.fail("__import__ did not result in creation of "
524                          "a .pyc file")
525            stat_info = os.stat(cached_path)
526
527        # Check that the umask is respected, and the executable bits
528        # aren't set.
529        self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)),
530                         oct(0o666 & ~mask))
531
532    @unittest.skipUnless(os.name == 'posix',
533                         "test meaningful only on posix systems")
534    def test_cached_mode_issue_2051(self):
535        # permissions of .pyc should match those of .py, regardless of mask
536        mode = 0o600
537        with temp_umask(0o022), _ready_to_import() as (name, path):
538            cached_path = importlib.util.cache_from_source(path)
539            os.chmod(path, mode)
540            __import__(name)
541            if not os.path.exists(cached_path):
542                self.fail("__import__ did not result in creation of "
543                          "a .pyc file")
544            stat_info = os.stat(cached_path)
545
546        self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode))
547
548    @unittest.skipUnless(os.name == 'posix',
549                         "test meaningful only on posix systems")
550    def test_cached_readonly(self):
551        mode = 0o400
552        with temp_umask(0o022), _ready_to_import() as (name, path):
553            cached_path = importlib.util.cache_from_source(path)
554            os.chmod(path, mode)
555            __import__(name)
556            if not os.path.exists(cached_path):
557                self.fail("__import__ did not result in creation of "
558                          "a .pyc file")
559            stat_info = os.stat(cached_path)
560
561        expected = mode | 0o200 # Account for fix for issue #6074
562        self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(expected))
563
564    def test_pyc_always_writable(self):
565        # Initially read-only .pyc files on Windows used to cause problems
566        # with later updates, see issue #6074 for details
567        with _ready_to_import() as (name, path):
568            # Write a Python file, make it read-only and import it
569            with open(path, 'w') as f:
570                f.write("x = 'original'\n")
571            # Tweak the mtime of the source to ensure pyc gets updated later
572            s = os.stat(path)
573            os.utime(path, (s.st_atime, s.st_mtime-100000000))
574            os.chmod(path, 0o400)
575            m = __import__(name)
576            self.assertEqual(m.x, 'original')
577            # Change the file and then reimport it
578            os.chmod(path, 0o600)
579            with open(path, 'w') as f:
580                f.write("x = 'rewritten'\n")
581            unload(name)
582            importlib.invalidate_caches()
583            m = __import__(name)
584            self.assertEqual(m.x, 'rewritten')
585            # Now delete the source file and check the pyc was rewritten
586            unlink(path)
587            unload(name)
588            importlib.invalidate_caches()
589            bytecode_only = path + "c"
590            os.rename(importlib.util.cache_from_source(path), bytecode_only)
591            m = __import__(name)
592            self.assertEqual(m.x, 'rewritten')
593
594
595class PycRewritingTests(unittest.TestCase):
596    # Test that the `co_filename` attribute on code objects always points
597    # to the right file, even when various things happen (e.g. both the .py
598    # and the .pyc file are renamed).
599
600    module_name = "unlikely_module_name"
601    module_source = """
602import sys
603code_filename = sys._getframe().f_code.co_filename
604module_filename = __file__
605constant = 1
606def func():
607    pass
608func_filename = func.__code__.co_filename
609"""
610    dir_name = os.path.abspath(TESTFN)
611    file_name = os.path.join(dir_name, module_name) + os.extsep + "py"
612    compiled_name = importlib.util.cache_from_source(file_name)
613
614    def setUp(self):
615        self.sys_path = sys.path[:]
616        self.orig_module = sys.modules.pop(self.module_name, None)
617        os.mkdir(self.dir_name)
618        with open(self.file_name, "w") as f:
619            f.write(self.module_source)
620        sys.path.insert(0, self.dir_name)
621        importlib.invalidate_caches()
622
623    def tearDown(self):
624        sys.path[:] = self.sys_path
625        if self.orig_module is not None:
626            sys.modules[self.module_name] = self.orig_module
627        else:
628            unload(self.module_name)
629        unlink(self.file_name)
630        unlink(self.compiled_name)
631        rmtree(self.dir_name)
632
633    def import_module(self):
634        ns = globals()
635        __import__(self.module_name, ns, ns)
636        return sys.modules[self.module_name]
637
638    def test_basics(self):
639        mod = self.import_module()
640        self.assertEqual(mod.module_filename, self.file_name)
641        self.assertEqual(mod.code_filename, self.file_name)
642        self.assertEqual(mod.func_filename, self.file_name)
643        del sys.modules[self.module_name]
644        mod = self.import_module()
645        self.assertEqual(mod.module_filename, self.file_name)
646        self.assertEqual(mod.code_filename, self.file_name)
647        self.assertEqual(mod.func_filename, self.file_name)
648
649    def test_incorrect_code_name(self):
650        py_compile.compile(self.file_name, dfile="another_module.py")
651        mod = self.import_module()
652        self.assertEqual(mod.module_filename, self.file_name)
653        self.assertEqual(mod.code_filename, self.file_name)
654        self.assertEqual(mod.func_filename, self.file_name)
655
656    def test_module_without_source(self):
657        target = "another_module.py"
658        py_compile.compile(self.file_name, dfile=target)
659        os.remove(self.file_name)
660        pyc_file = make_legacy_pyc(self.file_name)
661        importlib.invalidate_caches()
662        mod = self.import_module()
663        self.assertEqual(mod.module_filename, pyc_file)
664        self.assertEqual(mod.code_filename, target)
665        self.assertEqual(mod.func_filename, target)
666
667    def test_foreign_code(self):
668        py_compile.compile(self.file_name)
669        with open(self.compiled_name, "rb") as f:
670            header = f.read(16)
671            code = marshal.load(f)
672        constants = list(code.co_consts)
673        foreign_code = importlib.import_module.__code__
674        pos = constants.index(1)
675        constants[pos] = foreign_code
676        code = code.replace(co_consts=tuple(constants))
677        with open(self.compiled_name, "wb") as f:
678            f.write(header)
679            marshal.dump(code, f)
680        mod = self.import_module()
681        self.assertEqual(mod.constant.co_filename, foreign_code.co_filename)
682
683
684class PathsTests(unittest.TestCase):
685    SAMPLES = ('test', 'test\u00e4\u00f6\u00fc\u00df', 'test\u00e9\u00e8',
686               'test\u00b0\u00b3\u00b2')
687    path = TESTFN
688
689    def setUp(self):
690        os.mkdir(self.path)
691        self.syspath = sys.path[:]
692
693    def tearDown(self):
694        rmtree(self.path)
695        sys.path[:] = self.syspath
696
697    # Regression test for http://bugs.python.org/issue1293.
698    def test_trailing_slash(self):
699        with open(os.path.join(self.path, 'test_trailing_slash.py'), 'w') as f:
700            f.write("testdata = 'test_trailing_slash'")
701        sys.path.append(self.path+'/')
702        mod = __import__("test_trailing_slash")
703        self.assertEqual(mod.testdata, 'test_trailing_slash')
704        unload("test_trailing_slash")
705
706    # Regression test for http://bugs.python.org/issue3677.
707    @unittest.skipUnless(sys.platform == 'win32', 'Windows-specific')
708    def test_UNC_path(self):
709        with open(os.path.join(self.path, 'test_unc_path.py'), 'w') as f:
710            f.write("testdata = 'test_unc_path'")
711        importlib.invalidate_caches()
712        # Create the UNC path, like \\myhost\c$\foo\bar.
713        path = os.path.abspath(self.path)
714        import socket
715        hn = socket.gethostname()
716        drive = path[0]
717        unc = "\\\\%s\\%s$"%(hn, drive)
718        unc += path[2:]
719        try:
720            os.listdir(unc)
721        except OSError as e:
722            if e.errno in (errno.EPERM, errno.EACCES, errno.ENOENT):
723                # See issue #15338
724                self.skipTest("cannot access administrative share %r" % (unc,))
725            raise
726        sys.path.insert(0, unc)
727        try:
728            mod = __import__("test_unc_path")
729        except ImportError as e:
730            self.fail("could not import 'test_unc_path' from %r: %r"
731                      % (unc, e))
732        self.assertEqual(mod.testdata, 'test_unc_path')
733        self.assertTrue(mod.__file__.startswith(unc), mod.__file__)
734        unload("test_unc_path")
735
736
737class RelativeImportTests(unittest.TestCase):
738
739    def tearDown(self):
740        unload("test.relimport")
741    setUp = tearDown
742
743    def test_relimport_star(self):
744        # This will import * from .test_import.
745        from .. import relimport
746        self.assertTrue(hasattr(relimport, "RelativeImportTests"))
747
748    def test_issue3221(self):
749        # Note for mergers: the 'absolute' tests from the 2.x branch
750        # are missing in Py3k because implicit relative imports are
751        # a thing of the past
752        #
753        # Regression test for http://bugs.python.org/issue3221.
754        def check_relative():
755            exec("from . import relimport", ns)
756
757        # Check relative import OK with __package__ and __name__ correct
758        ns = dict(__package__='test', __name__='test.notarealmodule')
759        check_relative()
760
761        # Check relative import OK with only __name__ wrong
762        ns = dict(__package__='test', __name__='notarealpkg.notarealmodule')
763        check_relative()
764
765        # Check relative import fails with only __package__ wrong
766        ns = dict(__package__='foo', __name__='test.notarealmodule')
767        self.assertRaises(ModuleNotFoundError, check_relative)
768
769        # Check relative import fails with __package__ and __name__ wrong
770        ns = dict(__package__='foo', __name__='notarealpkg.notarealmodule')
771        self.assertRaises(ModuleNotFoundError, check_relative)
772
773        # Check relative import fails with package set to a non-string
774        ns = dict(__package__=object())
775        self.assertRaises(TypeError, check_relative)
776
777    def test_parentless_import_shadowed_by_global(self):
778        # Test as if this were done from the REPL where this error most commonly occurs (bpo-37409).
779        script_helper.assert_python_failure('-W', 'ignore', '-c',
780            "foo = 1; from . import foo")
781
782    def test_absolute_import_without_future(self):
783        # If explicit relative import syntax is used, then do not try
784        # to perform an absolute import in the face of failure.
785        # Issue #7902.
786        with self.assertRaises(ImportError):
787            from .os import sep
788            self.fail("explicit relative import triggered an "
789                      "implicit absolute import")
790
791    def test_import_from_non_package(self):
792        path = os.path.join(os.path.dirname(__file__), 'data', 'package2')
793        with uncache('submodule1', 'submodule2'), DirsOnSysPath(path):
794            with self.assertRaises(ImportError):
795                import submodule1
796            self.assertNotIn('submodule1', sys.modules)
797            self.assertNotIn('submodule2', sys.modules)
798
799    def test_import_from_unloaded_package(self):
800        with uncache('package2', 'package2.submodule1', 'package2.submodule2'), \
801             DirsOnSysPath(os.path.join(os.path.dirname(__file__), 'data')):
802            import package2.submodule1
803            package2.submodule1.submodule2
804
805
806class OverridingImportBuiltinTests(unittest.TestCase):
807    def test_override_builtin(self):
808        # Test that overriding builtins.__import__ can bypass sys.modules.
809        import os
810
811        def foo():
812            import os
813            return os
814        self.assertEqual(foo(), os)  # Quick sanity check.
815
816        with swap_attr(builtins, "__import__", lambda *x: 5):
817            self.assertEqual(foo(), 5)
818
819        # Test what happens when we shadow __import__ in globals(); this
820        # currently does not impact the import process, but if this changes,
821        # other code will need to change, so keep this test as a tripwire.
822        with swap_item(globals(), "__import__", lambda *x: 5):
823            self.assertEqual(foo(), os)
824
825
826class PycacheTests(unittest.TestCase):
827    # Test the various PEP 3147/488-related behaviors.
828
829    def _clean(self):
830        forget(TESTFN)
831        rmtree('__pycache__')
832        unlink(self.source)
833
834    def setUp(self):
835        self.source = TESTFN + '.py'
836        self._clean()
837        with open(self.source, 'w') as fp:
838            print('# This is a test file written by test_import.py', file=fp)
839        sys.path.insert(0, os.curdir)
840        importlib.invalidate_caches()
841
842    def tearDown(self):
843        assert sys.path[0] == os.curdir, 'Unexpected sys.path[0]'
844        del sys.path[0]
845        self._clean()
846
847    @skip_if_dont_write_bytecode
848    def test_import_pyc_path(self):
849        self.assertFalse(os.path.exists('__pycache__'))
850        __import__(TESTFN)
851        self.assertTrue(os.path.exists('__pycache__'))
852        pyc_path = importlib.util.cache_from_source(self.source)
853        self.assertTrue(os.path.exists(pyc_path),
854                        'bytecode file {!r} for {!r} does not '
855                        'exist'.format(pyc_path, TESTFN))
856
857    @unittest.skipUnless(os.name == 'posix',
858                         "test meaningful only on posix systems")
859    @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
860            "due to varying filesystem permission semantics (issue #11956)")
861    @skip_if_dont_write_bytecode
862    def test_unwritable_directory(self):
863        # When the umask causes the new __pycache__ directory to be
864        # unwritable, the import still succeeds but no .pyc file is written.
865        with temp_umask(0o222):
866            __import__(TESTFN)
867        self.assertTrue(os.path.exists('__pycache__'))
868        pyc_path = importlib.util.cache_from_source(self.source)
869        self.assertFalse(os.path.exists(pyc_path),
870                        'bytecode file {!r} for {!r} '
871                        'exists'.format(pyc_path, TESTFN))
872
873    @skip_if_dont_write_bytecode
874    def test_missing_source(self):
875        # With PEP 3147 cache layout, removing the source but leaving the pyc
876        # file does not satisfy the import.
877        __import__(TESTFN)
878        pyc_file = importlib.util.cache_from_source(self.source)
879        self.assertTrue(os.path.exists(pyc_file))
880        os.remove(self.source)
881        forget(TESTFN)
882        importlib.invalidate_caches()
883        self.assertRaises(ImportError, __import__, TESTFN)
884
885    @skip_if_dont_write_bytecode
886    def test_missing_source_legacy(self):
887        # Like test_missing_source() except that for backward compatibility,
888        # when the pyc file lives where the py file would have been (and named
889        # without the tag), it is importable.  The __file__ of the imported
890        # module is the pyc location.
891        __import__(TESTFN)
892        # pyc_file gets removed in _clean() via tearDown().
893        pyc_file = make_legacy_pyc(self.source)
894        os.remove(self.source)
895        unload(TESTFN)
896        importlib.invalidate_caches()
897        m = __import__(TESTFN)
898        try:
899            self.assertEqual(m.__file__,
900                             os.path.join(os.curdir, os.path.relpath(pyc_file)))
901        finally:
902            os.remove(pyc_file)
903
904    def test___cached__(self):
905        # Modules now also have an __cached__ that points to the pyc file.
906        m = __import__(TESTFN)
907        pyc_file = importlib.util.cache_from_source(TESTFN + '.py')
908        self.assertEqual(m.__cached__, os.path.join(os.curdir, pyc_file))
909
910    @skip_if_dont_write_bytecode
911    def test___cached___legacy_pyc(self):
912        # Like test___cached__() except that for backward compatibility,
913        # when the pyc file lives where the py file would have been (and named
914        # without the tag), it is importable.  The __cached__ of the imported
915        # module is the pyc location.
916        __import__(TESTFN)
917        # pyc_file gets removed in _clean() via tearDown().
918        pyc_file = make_legacy_pyc(self.source)
919        os.remove(self.source)
920        unload(TESTFN)
921        importlib.invalidate_caches()
922        m = __import__(TESTFN)
923        self.assertEqual(m.__cached__,
924                         os.path.join(os.curdir, os.path.relpath(pyc_file)))
925
926    @skip_if_dont_write_bytecode
927    def test_package___cached__(self):
928        # Like test___cached__ but for packages.
929        def cleanup():
930            rmtree('pep3147')
931            unload('pep3147.foo')
932            unload('pep3147')
933        os.mkdir('pep3147')
934        self.addCleanup(cleanup)
935        # Touch the __init__.py
936        with open(os.path.join('pep3147', '__init__.py'), 'w'):
937            pass
938        with open(os.path.join('pep3147', 'foo.py'), 'w'):
939            pass
940        importlib.invalidate_caches()
941        m = __import__('pep3147.foo')
942        init_pyc = importlib.util.cache_from_source(
943            os.path.join('pep3147', '__init__.py'))
944        self.assertEqual(m.__cached__, os.path.join(os.curdir, init_pyc))
945        foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
946        self.assertEqual(sys.modules['pep3147.foo'].__cached__,
947                         os.path.join(os.curdir, foo_pyc))
948
949    def test_package___cached___from_pyc(self):
950        # Like test___cached__ but ensuring __cached__ when imported from a
951        # PEP 3147 pyc file.
952        def cleanup():
953            rmtree('pep3147')
954            unload('pep3147.foo')
955            unload('pep3147')
956        os.mkdir('pep3147')
957        self.addCleanup(cleanup)
958        # Touch the __init__.py
959        with open(os.path.join('pep3147', '__init__.py'), 'w'):
960            pass
961        with open(os.path.join('pep3147', 'foo.py'), 'w'):
962            pass
963        importlib.invalidate_caches()
964        m = __import__('pep3147.foo')
965        unload('pep3147.foo')
966        unload('pep3147')
967        importlib.invalidate_caches()
968        m = __import__('pep3147.foo')
969        init_pyc = importlib.util.cache_from_source(
970            os.path.join('pep3147', '__init__.py'))
971        self.assertEqual(m.__cached__, os.path.join(os.curdir, init_pyc))
972        foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
973        self.assertEqual(sys.modules['pep3147.foo'].__cached__,
974                         os.path.join(os.curdir, foo_pyc))
975
976    def test_recompute_pyc_same_second(self):
977        # Even when the source file doesn't change timestamp, a change in
978        # source size is enough to trigger recomputation of the pyc file.
979        __import__(TESTFN)
980        unload(TESTFN)
981        with open(self.source, 'a') as fp:
982            print("x = 5", file=fp)
983        m = __import__(TESTFN)
984        self.assertEqual(m.x, 5)
985
986
987class TestSymbolicallyLinkedPackage(unittest.TestCase):
988    package_name = 'sample'
989    tagged = package_name + '-tagged'
990
991    def setUp(self):
992        test.support.rmtree(self.tagged)
993        test.support.rmtree(self.package_name)
994        self.orig_sys_path = sys.path[:]
995
996        # create a sample package; imagine you have a package with a tag and
997        #  you want to symbolically link it from its untagged name.
998        os.mkdir(self.tagged)
999        self.addCleanup(test.support.rmtree, self.tagged)
1000        init_file = os.path.join(self.tagged, '__init__.py')
1001        test.support.create_empty_file(init_file)
1002        assert os.path.exists(init_file)
1003
1004        # now create a symlink to the tagged package
1005        # sample -> sample-tagged
1006        os.symlink(self.tagged, self.package_name, target_is_directory=True)
1007        self.addCleanup(test.support.unlink, self.package_name)
1008        importlib.invalidate_caches()
1009
1010        self.assertEqual(os.path.isdir(self.package_name), True)
1011
1012        assert os.path.isfile(os.path.join(self.package_name, '__init__.py'))
1013
1014    def tearDown(self):
1015        sys.path[:] = self.orig_sys_path
1016
1017    # regression test for issue6727
1018    @unittest.skipUnless(
1019        not hasattr(sys, 'getwindowsversion')
1020        or sys.getwindowsversion() >= (6, 0),
1021        "Windows Vista or later required")
1022    @test.support.skip_unless_symlink
1023    def test_symlinked_dir_importable(self):
1024        # make sure sample can only be imported from the current directory.
1025        sys.path[:] = ['.']
1026        assert os.path.exists(self.package_name)
1027        assert os.path.exists(os.path.join(self.package_name, '__init__.py'))
1028
1029        # Try to import the package
1030        importlib.import_module(self.package_name)
1031
1032
1033@cpython_only
1034class ImportlibBootstrapTests(unittest.TestCase):
1035    # These tests check that importlib is bootstrapped.
1036
1037    def test_frozen_importlib(self):
1038        mod = sys.modules['_frozen_importlib']
1039        self.assertTrue(mod)
1040
1041    def test_frozen_importlib_is_bootstrap(self):
1042        from importlib import _bootstrap
1043        mod = sys.modules['_frozen_importlib']
1044        self.assertIs(mod, _bootstrap)
1045        self.assertEqual(mod.__name__, 'importlib._bootstrap')
1046        self.assertEqual(mod.__package__, 'importlib')
1047        self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__)
1048
1049    def test_frozen_importlib_external_is_bootstrap_external(self):
1050        from importlib import _bootstrap_external
1051        mod = sys.modules['_frozen_importlib_external']
1052        self.assertIs(mod, _bootstrap_external)
1053        self.assertEqual(mod.__name__, 'importlib._bootstrap_external')
1054        self.assertEqual(mod.__package__, 'importlib')
1055        self.assertTrue(mod.__file__.endswith('_bootstrap_external.py'), mod.__file__)
1056
1057    def test_there_can_be_only_one(self):
1058        # Issue #15386 revealed a tricky loophole in the bootstrapping
1059        # This test is technically redundant, since the bug caused importing
1060        # this test module to crash completely, but it helps prove the point
1061        from importlib import machinery
1062        mod = sys.modules['_frozen_importlib']
1063        self.assertIs(machinery.ModuleSpec, mod.ModuleSpec)
1064
1065
1066@cpython_only
1067class GetSourcefileTests(unittest.TestCase):
1068
1069    """Test importlib._bootstrap_external._get_sourcefile() as used by the C API.
1070
1071    Because of the peculiarities of the need of this function, the tests are
1072    knowingly whitebox tests.
1073
1074    """
1075
1076    def test_get_sourcefile(self):
1077        # Given a valid bytecode path, return the path to the corresponding
1078        # source file if it exists.
1079        with mock.patch('importlib._bootstrap_external._path_isfile') as _path_isfile:
1080            _path_isfile.return_value = True;
1081            path = TESTFN + '.pyc'
1082            expect = TESTFN + '.py'
1083            self.assertEqual(_get_sourcefile(path), expect)
1084
1085    def test_get_sourcefile_no_source(self):
1086        # Given a valid bytecode path without a corresponding source path,
1087        # return the original bytecode path.
1088        with mock.patch('importlib._bootstrap_external._path_isfile') as _path_isfile:
1089            _path_isfile.return_value = False;
1090            path = TESTFN + '.pyc'
1091            self.assertEqual(_get_sourcefile(path), path)
1092
1093    def test_get_sourcefile_bad_ext(self):
1094        # Given a path with an invalid bytecode extension, return the
1095        # bytecode path passed as the argument.
1096        path = TESTFN + '.bad_ext'
1097        self.assertEqual(_get_sourcefile(path), path)
1098
1099
1100class ImportTracebackTests(unittest.TestCase):
1101
1102    def setUp(self):
1103        os.mkdir(TESTFN)
1104        self.old_path = sys.path[:]
1105        sys.path.insert(0, TESTFN)
1106
1107    def tearDown(self):
1108        sys.path[:] = self.old_path
1109        rmtree(TESTFN)
1110
1111    def create_module(self, mod, contents, ext=".py"):
1112        fname = os.path.join(TESTFN, mod + ext)
1113        with open(fname, "w") as f:
1114            f.write(contents)
1115        self.addCleanup(unload, mod)
1116        importlib.invalidate_caches()
1117        return fname
1118
1119    def assert_traceback(self, tb, files):
1120        deduped_files = []
1121        while tb:
1122            code = tb.tb_frame.f_code
1123            fn = code.co_filename
1124            if not deduped_files or fn != deduped_files[-1]:
1125                deduped_files.append(fn)
1126            tb = tb.tb_next
1127        self.assertEqual(len(deduped_files), len(files), deduped_files)
1128        for fn, pat in zip(deduped_files, files):
1129            self.assertIn(pat, fn)
1130
1131    def test_nonexistent_module(self):
1132        try:
1133            # assertRaises() clears __traceback__
1134            import nonexistent_xyzzy
1135        except ImportError as e:
1136            tb = e.__traceback__
1137        else:
1138            self.fail("ImportError should have been raised")
1139        self.assert_traceback(tb, [__file__])
1140
1141    def test_nonexistent_module_nested(self):
1142        self.create_module("foo", "import nonexistent_xyzzy")
1143        try:
1144            import foo
1145        except ImportError as e:
1146            tb = e.__traceback__
1147        else:
1148            self.fail("ImportError should have been raised")
1149        self.assert_traceback(tb, [__file__, 'foo.py'])
1150
1151    def test_exec_failure(self):
1152        self.create_module("foo", "1/0")
1153        try:
1154            import foo
1155        except ZeroDivisionError as e:
1156            tb = e.__traceback__
1157        else:
1158            self.fail("ZeroDivisionError should have been raised")
1159        self.assert_traceback(tb, [__file__, 'foo.py'])
1160
1161    def test_exec_failure_nested(self):
1162        self.create_module("foo", "import bar")
1163        self.create_module("bar", "1/0")
1164        try:
1165            import foo
1166        except ZeroDivisionError as e:
1167            tb = e.__traceback__
1168        else:
1169            self.fail("ZeroDivisionError should have been raised")
1170        self.assert_traceback(tb, [__file__, 'foo.py', 'bar.py'])
1171
1172    # A few more examples from issue #15425
1173    def test_syntax_error(self):
1174        self.create_module("foo", "invalid syntax is invalid")
1175        try:
1176            import foo
1177        except SyntaxError as e:
1178            tb = e.__traceback__
1179        else:
1180            self.fail("SyntaxError should have been raised")
1181        self.assert_traceback(tb, [__file__])
1182
1183    def _setup_broken_package(self, parent, child):
1184        pkg_name = "_parent_foo"
1185        self.addCleanup(unload, pkg_name)
1186        pkg_path = os.path.join(TESTFN, pkg_name)
1187        os.mkdir(pkg_path)
1188        # Touch the __init__.py
1189        init_path = os.path.join(pkg_path, '__init__.py')
1190        with open(init_path, 'w') as f:
1191            f.write(parent)
1192        bar_path = os.path.join(pkg_path, 'bar.py')
1193        with open(bar_path, 'w') as f:
1194            f.write(child)
1195        importlib.invalidate_caches()
1196        return init_path, bar_path
1197
1198    def test_broken_submodule(self):
1199        init_path, bar_path = self._setup_broken_package("", "1/0")
1200        try:
1201            import _parent_foo.bar
1202        except ZeroDivisionError as e:
1203            tb = e.__traceback__
1204        else:
1205            self.fail("ZeroDivisionError should have been raised")
1206        self.assert_traceback(tb, [__file__, bar_path])
1207
1208    def test_broken_from(self):
1209        init_path, bar_path = self._setup_broken_package("", "1/0")
1210        try:
1211            from _parent_foo import bar
1212        except ZeroDivisionError as e:
1213            tb = e.__traceback__
1214        else:
1215            self.fail("ImportError should have been raised")
1216        self.assert_traceback(tb, [__file__, bar_path])
1217
1218    def test_broken_parent(self):
1219        init_path, bar_path = self._setup_broken_package("1/0", "")
1220        try:
1221            import _parent_foo.bar
1222        except ZeroDivisionError as e:
1223            tb = e.__traceback__
1224        else:
1225            self.fail("ZeroDivisionError should have been raised")
1226        self.assert_traceback(tb, [__file__, init_path])
1227
1228    def test_broken_parent_from(self):
1229        init_path, bar_path = self._setup_broken_package("1/0", "")
1230        try:
1231            from _parent_foo import bar
1232        except ZeroDivisionError as e:
1233            tb = e.__traceback__
1234        else:
1235            self.fail("ZeroDivisionError should have been raised")
1236        self.assert_traceback(tb, [__file__, init_path])
1237
1238    @cpython_only
1239    def test_import_bug(self):
1240        # We simulate a bug in importlib and check that it's not stripped
1241        # away from the traceback.
1242        self.create_module("foo", "")
1243        importlib = sys.modules['_frozen_importlib_external']
1244        if 'load_module' in vars(importlib.SourceLoader):
1245            old_exec_module = importlib.SourceLoader.exec_module
1246        else:
1247            old_exec_module = None
1248        try:
1249            def exec_module(*args):
1250                1/0
1251            importlib.SourceLoader.exec_module = exec_module
1252            try:
1253                import foo
1254            except ZeroDivisionError as e:
1255                tb = e.__traceback__
1256            else:
1257                self.fail("ZeroDivisionError should have been raised")
1258            self.assert_traceback(tb, [__file__, '<frozen importlib', __file__])
1259        finally:
1260            if old_exec_module is None:
1261                del importlib.SourceLoader.exec_module
1262            else:
1263                importlib.SourceLoader.exec_module = old_exec_module
1264
1265    @unittest.skipUnless(TESTFN_UNENCODABLE, 'need TESTFN_UNENCODABLE')
1266    def test_unencodable_filename(self):
1267        # Issue #11619: The Python parser and the import machinery must not
1268        # encode filenames, especially on Windows
1269        pyname = script_helper.make_script('', TESTFN_UNENCODABLE, 'pass')
1270        self.addCleanup(unlink, pyname)
1271        name = pyname[:-3]
1272        script_helper.assert_python_ok("-c", "mod = __import__(%a)" % name,
1273                                       __isolated=False)
1274
1275
1276class CircularImportTests(unittest.TestCase):
1277
1278    """See the docstrings of the modules being imported for the purpose of the
1279    test."""
1280
1281    def tearDown(self):
1282        """Make sure no modules pre-exist in sys.modules which are being used to
1283        test."""
1284        for key in list(sys.modules.keys()):
1285            if key.startswith('test.test_import.data.circular_imports'):
1286                del sys.modules[key]
1287
1288    def test_direct(self):
1289        try:
1290            import test.test_import.data.circular_imports.basic
1291        except ImportError:
1292            self.fail('circular import through relative imports failed')
1293
1294    def test_indirect(self):
1295        try:
1296            import test.test_import.data.circular_imports.indirect
1297        except ImportError:
1298            self.fail('relative import in module contributing to circular '
1299                      'import failed')
1300
1301    def test_subpackage(self):
1302        try:
1303            import test.test_import.data.circular_imports.subpackage
1304        except ImportError:
1305            self.fail('circular import involving a subpackage failed')
1306
1307    def test_rebinding(self):
1308        try:
1309            import test.test_import.data.circular_imports.rebinding as rebinding
1310        except ImportError:
1311            self.fail('circular import with rebinding of module attribute failed')
1312        from test.test_import.data.circular_imports.subpkg import util
1313        self.assertIs(util.util, rebinding.util)
1314
1315    def test_binding(self):
1316        try:
1317            import test.test_import.data.circular_imports.binding
1318        except ImportError:
1319            self.fail('circular import with binding a submodule to a name failed')
1320
1321    def test_crossreference1(self):
1322        import test.test_import.data.circular_imports.use
1323        import test.test_import.data.circular_imports.source
1324
1325    def test_crossreference2(self):
1326        with self.assertRaises(AttributeError) as cm:
1327            import test.test_import.data.circular_imports.source
1328        errmsg = str(cm.exception)
1329        self.assertIn('test.test_import.data.circular_imports.source', errmsg)
1330        self.assertIn('spam', errmsg)
1331        self.assertIn('partially initialized module', errmsg)
1332        self.assertIn('circular import', errmsg)
1333
1334    def test_circular_from_import(self):
1335        with self.assertRaises(ImportError) as cm:
1336            import test.test_import.data.circular_imports.from_cycle1
1337        self.assertIn(
1338            "cannot import name 'b' from partially initialized module "
1339            "'test.test_import.data.circular_imports.from_cycle1' "
1340            "(most likely due to a circular import)",
1341            str(cm.exception),
1342        )
1343
1344
1345if __name__ == '__main__':
1346    # Test needs to be a package, so we can do relative imports.
1347    unittest.main()
1348