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