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