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