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