summaryrefslogtreecommitdiff
path: root/Lib/test/test_import.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_import.py')
-rw-r--r--Lib/test/test_import.py587
1 files changed, 442 insertions, 145 deletions
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
index 1aa665a1b2..df08e6a86f 100644
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -1,7 +1,9 @@
+# We import importlib *ASAP* in order to test #15386
+import importlib
+from importlib._bootstrap import _get_sourcefile
import builtins
import imp
-from importlib.test.import_ import test_relative_imports
-from importlib.test.import_ import util as importlib_util
+from test.test_importlib.import_ import util as importlib_util
import marshal
import os
import platform
@@ -10,13 +12,17 @@ import random
import stat
import sys
import unittest
+import unittest.mock as mock
import textwrap
import errno
+import shutil
+import contextlib
+import test.support
from test.support import (
EnvironmentVarGuard, TESTFN, check_warnings, forget, is_jython,
make_legacy_pyc, rmtree, run_unittest, swap_attr, swap_item, temp_umask,
- unlink, unload)
+ unlink, unload, create_empty_file, cpython_only)
from test import script_helper
@@ -24,31 +30,42 @@ skip_if_dont_write_bytecode = unittest.skipIf(
sys.dont_write_bytecode,
"test meaningful only when writing bytecode")
-def _files(name):
- return (name + os.extsep + "py",
- name + os.extsep + "pyc",
- name + os.extsep + "pyo",
- name + os.extsep + "pyw",
- name + "$py.class")
-
-def chmod_files(name):
- for f in _files(name):
- try:
- os.chmod(f, 0o600)
- except OSError as exc:
- if exc.errno != errno.ENOENT:
- raise
-
def remove_files(name):
- for f in _files(name):
+ for f in (name + ".py",
+ name + ".pyc",
+ name + ".pyo",
+ name + ".pyw",
+ name + "$py.class"):
unlink(f)
rmtree('__pycache__')
+@contextlib.contextmanager
+def _ready_to_import(name=None, source=""):
+ # sets up a temporary directory and removes it
+ # creates the module file
+ # temporarily clears the module from sys.modules (if any)
+ # reverts or removes the module when cleaning up
+ name = name or "spam"
+ with script_helper.temp_dir() as tempdir:
+ path = script_helper.make_script(tempdir, name, source)
+ old_module = sys.modules.pop(name, None)
+ try:
+ sys.path.insert(0, tempdir)
+ yield name, path
+ sys.path.remove(tempdir)
+ finally:
+ if old_module is not None:
+ sys.modules[name] = old_module
+ elif name in sys.modules:
+ del sys.modules[name]
+
+
class ImportTests(unittest.TestCase):
def setUp(self):
remove_files(TESTFN)
+ importlib.invalidate_caches()
def tearDown(self):
unload(TESTFN)
@@ -86,6 +103,7 @@ class ImportTests(unittest.TestCase):
if TESTFN in sys.modules:
del sys.modules[TESTFN]
+ importlib.invalidate_caches()
try:
try:
mod = __import__(TESTFN)
@@ -111,92 +129,7 @@ class ImportTests(unittest.TestCase):
finally:
del sys.path[0]
- @unittest.skipUnless(os.name == 'posix',
- "test meaningful only on posix systems")
@skip_if_dont_write_bytecode
- def test_execute_bit_not_copied(self):
- # Issue 6070: under posix .pyc files got their execute bit set if
- # the .py file had the execute bit set, but they aren't executable.
- with temp_umask(0o022):
- sys.path.insert(0, os.curdir)
- try:
- fname = TESTFN + os.extsep + "py"
- open(fname, 'w').close()
- os.chmod(fname, (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH |
- stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))
- fn = imp.cache_from_source(fname)
- unlink(fn)
- __import__(TESTFN)
- if not os.path.exists(fn):
- self.fail("__import__ did not result in creation of "
- "either a .pyc or .pyo file")
- s = os.stat(fn)
- self.assertEqual(stat.S_IMODE(s.st_mode),
- stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
- finally:
- del sys.path[0]
- remove_files(TESTFN)
- unload(TESTFN)
-
- @skip_if_dont_write_bytecode
- def test_rewrite_pyc_with_read_only_source(self):
- # Issue 6074: a long time ago on posix, and more recently on Windows,
- # a read only source file resulted in a read only pyc file, which
- # led to problems with updating it later
- sys.path.insert(0, os.curdir)
- fname = TESTFN + os.extsep + "py"
- try:
- # Write a Python file, make it read-only and import it
- with open(fname, 'w') as f:
- f.write("x = 'original'\n")
- # Tweak the mtime of the source to ensure pyc gets updated later
- s = os.stat(fname)
- os.utime(fname, (s.st_atime, s.st_mtime-100000000))
- os.chmod(fname, 0o400)
- m1 = __import__(TESTFN)
- self.assertEqual(m1.x, 'original')
- # Change the file and then reimport it
- os.chmod(fname, 0o600)
- with open(fname, 'w') as f:
- f.write("x = 'rewritten'\n")
- unload(TESTFN)
- m2 = __import__(TESTFN)
- self.assertEqual(m2.x, 'rewritten')
- # Now delete the source file and check the pyc was rewritten
- unlink(fname)
- unload(TESTFN)
- if __debug__:
- bytecode_name = fname + "c"
- else:
- bytecode_name = fname + "o"
- os.rename(imp.cache_from_source(fname), bytecode_name)
- m3 = __import__(TESTFN)
- self.assertEqual(m3.x, 'rewritten')
- finally:
- chmod_files(TESTFN)
- remove_files(TESTFN)
- unload(TESTFN)
- del sys.path[0]
-
- def test_imp_module(self):
- # Verify that the imp module can correctly load and find .py files
- # XXX (ncoghlan): It would be nice to use support.CleanImport
- # here, but that breaks because the os module registers some
- # handlers in copy_reg on import. Since CleanImport doesn't
- # revert that registration, the module is left in a broken
- # state after reversion. Reinitialising the module contents
- # and just reverting os.environ to its previous state is an OK
- # workaround
- orig_path = os.path
- orig_getenv = os.getenv
- with EnvironmentVarGuard():
- x = imp.find_module("os")
- self.addCleanup(x[0].close)
- new_os = imp.load_module("os", *x)
- self.assertIs(os, new_os)
- self.assertIs(orig_path, new_os.path)
- self.assertIsNot(orig_getenv, new_os.getenv)
-
def test_bug7732(self):
source = TESTFN + '.py'
os.mkdir(source)
@@ -226,6 +159,7 @@ class ImportTests(unittest.TestCase):
# Need to be able to load from current dir.
sys.path.append('')
+ importlib.invalidate_caches()
try:
make_legacy_pyc(filename)
@@ -245,6 +179,7 @@ class ImportTests(unittest.TestCase):
# New in 2.4, we shouldn't be able to import that no matter how often
# we try.
sys.path.insert(0, os.curdir)
+ importlib.invalidate_caches()
if TESTFN in sys.modules:
del sys.modules[TESTFN]
try:
@@ -319,6 +254,7 @@ class ImportTests(unittest.TestCase):
os.remove(source)
del sys.modules[TESTFN]
make_legacy_pyc(source)
+ importlib.invalidate_caches()
mod = __import__(TESTFN)
base, ext = os.path.splitext(mod.__file__)
self.assertIn(ext, ('.pyc', '.pyo'))
@@ -328,23 +264,6 @@ class ImportTests(unittest.TestCase):
if TESTFN in sys.modules:
del sys.modules[TESTFN]
- def test_import_name_binding(self):
- # import x.y.z binds x in the current namespace.
- import test as x
- import test.support
- self.assertIs(x, test, x.__name__)
- self.assertTrue(hasattr(test.support, "__file__"))
-
- # import x.y.z as w binds z as w.
- import test.support as y
- self.assertIs(y, test.support, y.__name__)
-
- def test_import_initless_directory_warning(self):
- with check_warnings(('', ImportWarning)):
- # Just a random non-package directory we always expect to be
- # somewhere in sys.path...
- self.assertRaises(ImportError, __import__, "site-packages")
-
def test_import_by_filename(self):
path = os.path.abspath(TESTFN)
encoding = sys.getfilesystemencoding()
@@ -354,8 +273,6 @@ class ImportTests(unittest.TestCase):
self.skipTest('path is not encodable to {}'.format(encoding))
with self.assertRaises(ImportError) as c:
__import__(path)
- self.assertEqual("Import by filename is not supported.",
- c.exception.args[0])
def test_import_in_del_does_not_crash(self):
# Issue 4236
@@ -392,6 +309,106 @@ class ImportTests(unittest.TestCase):
del sys.path[0]
remove_files(TESTFN)
+ def test_bogus_fromlist(self):
+ try:
+ __import__('http', fromlist=['blah'])
+ except ImportError:
+ self.fail("fromlist must allow bogus names")
+
+ @cpython_only
+ def test_delete_builtins_import(self):
+ args = ["-c", "del __builtins__.__import__; import os"]
+ popen = script_helper.spawn_python(*args)
+ stdout, stderr = popen.communicate()
+ self.assertIn(b"ImportError", stdout)
+
+
+@skip_if_dont_write_bytecode
+class FilePermissionTests(unittest.TestCase):
+ # tests for file mode on cached .pyc/.pyo files
+
+ @unittest.skipUnless(os.name == 'posix',
+ "test meaningful only on posix systems")
+ def test_creation_mode(self):
+ mask = 0o022
+ with temp_umask(mask), _ready_to_import() as (name, path):
+ cached_path = imp.cache_from_source(path)
+ module = __import__(name)
+ if not os.path.exists(cached_path):
+ self.fail("__import__ did not result in creation of "
+ "either a .pyc or .pyo file")
+ stat_info = os.stat(cached_path)
+
+ # Check that the umask is respected, and the executable bits
+ # aren't set.
+ self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)),
+ oct(0o666 & ~mask))
+
+ @unittest.skipUnless(os.name == 'posix',
+ "test meaningful only on posix systems")
+ def test_cached_mode_issue_2051(self):
+ # permissions of .pyc should match those of .py, regardless of mask
+ mode = 0o600
+ with temp_umask(0o022), _ready_to_import() as (name, path):
+ cached_path = imp.cache_from_source(path)
+ os.chmod(path, mode)
+ __import__(name)
+ if not os.path.exists(cached_path):
+ self.fail("__import__ did not result in creation of "
+ "either a .pyc or .pyo file")
+ stat_info = os.stat(cached_path)
+
+ self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode))
+
+ @unittest.skipUnless(os.name == 'posix',
+ "test meaningful only on posix systems")
+ def test_cached_readonly(self):
+ mode = 0o400
+ with temp_umask(0o022), _ready_to_import() as (name, path):
+ cached_path = imp.cache_from_source(path)
+ os.chmod(path, mode)
+ __import__(name)
+ if not os.path.exists(cached_path):
+ self.fail("__import__ did not result in creation of "
+ "either a .pyc or .pyo file")
+ stat_info = os.stat(cached_path)
+
+ expected = mode | 0o200 # Account for fix for issue #6074
+ self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(expected))
+
+ def test_pyc_always_writable(self):
+ # Initially read-only .pyc files on Windows used to cause problems
+ # with later updates, see issue #6074 for details
+ with _ready_to_import() as (name, path):
+ # Write a Python file, make it read-only and import it
+ with open(path, 'w') as f:
+ f.write("x = 'original'\n")
+ # Tweak the mtime of the source to ensure pyc gets updated later
+ s = os.stat(path)
+ os.utime(path, (s.st_atime, s.st_mtime-100000000))
+ os.chmod(path, 0o400)
+ m = __import__(name)
+ self.assertEqual(m.x, 'original')
+ # Change the file and then reimport it
+ os.chmod(path, 0o600)
+ with open(path, 'w') as f:
+ f.write("x = 'rewritten'\n")
+ unload(name)
+ importlib.invalidate_caches()
+ m = __import__(name)
+ self.assertEqual(m.x, 'rewritten')
+ # Now delete the source file and check the pyc was rewritten
+ unlink(path)
+ unload(name)
+ importlib.invalidate_caches()
+ if __debug__:
+ bytecode_only = path + "c"
+ else:
+ bytecode_only = path + "o"
+ os.rename(imp.cache_from_source(path), bytecode_only)
+ m = __import__(name)
+ self.assertEqual(m.x, 'rewritten')
+
class PycRewritingTests(unittest.TestCase):
# Test that the `co_filename` attribute on code objects always points
@@ -419,6 +436,7 @@ func_filename = func.__code__.co_filename
with open(self.file_name, "w") as f:
f.write(self.module_source)
sys.path.insert(0, self.dir_name)
+ importlib.invalidate_caches()
def tearDown(self):
sys.path[:] = self.sys_path
@@ -458,6 +476,7 @@ func_filename = func.__code__.co_filename
py_compile.compile(self.file_name, dfile=target)
os.remove(self.file_name)
pyc_file = make_legacy_pyc(self.file_name)
+ importlib.invalidate_caches()
mod = self.import_module()
self.assertEqual(mod.module_filename, pyc_file)
self.assertEqual(mod.code_filename, target)
@@ -466,7 +485,7 @@ func_filename = func.__code__.co_filename
def test_foreign_code(self):
py_compile.compile(self.file_name)
with open(self.compiled_name, "rb") as f:
- header = f.read(8)
+ header = f.read(12)
code = marshal.load(f)
constants = list(code.co_consts)
foreign_code = test_main.__code__
@@ -508,9 +527,11 @@ class PathsTests(unittest.TestCase):
unload("test_trailing_slash")
# Regression test for http://bugs.python.org/issue3677.
- def _test_UNC_path(self):
- with open(os.path.join(self.path, 'test_trailing_slash.py'), 'w') as f:
- f.write("testdata = 'test_trailing_slash'")
+ @unittest.skipUnless(sys.platform == 'win32', 'Windows-specific')
+ def test_UNC_path(self):
+ with open(os.path.join(self.path, 'test_unc_path.py'), 'w') as f:
+ f.write("testdata = 'test_unc_path'")
+ importlib.invalidate_caches()
# Create the UNC path, like \\myhost\c$\foo\bar.
path = os.path.abspath(self.path)
import socket
@@ -525,13 +546,15 @@ class PathsTests(unittest.TestCase):
# See issue #15338
self.skipTest("cannot access administrative share %r" % (unc,))
raise
- sys.path.append(path)
- mod = __import__("test_trailing_slash")
- self.assertEqual(mod.testdata, 'test_trailing_slash')
- unload("test_trailing_slash")
-
- if sys.platform == "win32":
- test_UNC_path = _test_UNC_path
+ sys.path.insert(0, unc)
+ try:
+ mod = __import__("test_unc_path")
+ except ImportError as e:
+ self.fail("could not import 'test_unc_path' from %r: %r"
+ % (unc, e))
+ self.assertEqual(mod.testdata, 'test_unc_path')
+ self.assertTrue(mod.__file__.startswith(unc), mod.__file__)
+ unload("test_unc_path")
class RelativeImportTests(unittest.TestCase):
@@ -572,7 +595,7 @@ class RelativeImportTests(unittest.TestCase):
# Check relative import fails with package set to a non-string
ns = dict(__package__=object())
- self.assertRaises(ValueError, check_relative)
+ self.assertRaises(TypeError, check_relative)
def test_absolute_import_without_future(self):
# If explicit relative import syntax is used, then do not try
@@ -620,6 +643,7 @@ class PycacheTests(unittest.TestCase):
with open(self.source, 'w') as fp:
print('# This is a test file written by test_import.py', file=fp)
sys.path.insert(0, os.curdir)
+ importlib.invalidate_caches()
def tearDown(self):
assert sys.path[0] == os.curdir, 'Unexpected sys.path[0]'
@@ -671,6 +695,7 @@ class PycacheTests(unittest.TestCase):
pyc_file = make_legacy_pyc(self.source)
os.remove(self.source)
unload(TESTFN)
+ importlib.invalidate_caches()
m = __import__(TESTFN)
self.assertEqual(m.__file__,
os.path.join(os.curdir, os.path.relpath(pyc_file)))
@@ -692,6 +717,7 @@ class PycacheTests(unittest.TestCase):
pyc_file = make_legacy_pyc(self.source)
os.remove(self.source)
unload(TESTFN)
+ importlib.invalidate_caches()
m = __import__(TESTFN)
self.assertEqual(m.__cached__,
os.path.join(os.curdir, os.path.relpath(pyc_file)))
@@ -701,6 +727,8 @@ class PycacheTests(unittest.TestCase):
# Like test___cached__ but for packages.
def cleanup():
rmtree('pep3147')
+ unload('pep3147.foo')
+ unload('pep3147')
os.mkdir('pep3147')
self.addCleanup(cleanup)
# Touch the __init__.py
@@ -708,8 +736,7 @@ class PycacheTests(unittest.TestCase):
pass
with open(os.path.join('pep3147', 'foo.py'), 'w'):
pass
- unload('pep3147.foo')
- unload('pep3147')
+ importlib.invalidate_caches()
m = __import__('pep3147.foo')
init_pyc = imp.cache_from_source(
os.path.join('pep3147', '__init__.py'))
@@ -723,18 +750,20 @@ class PycacheTests(unittest.TestCase):
# PEP 3147 pyc file.
def cleanup():
rmtree('pep3147')
+ unload('pep3147.foo')
+ unload('pep3147')
os.mkdir('pep3147')
self.addCleanup(cleanup)
- unload('pep3147.foo')
- unload('pep3147')
# Touch the __init__.py
with open(os.path.join('pep3147', '__init__.py'), 'w'):
pass
with open(os.path.join('pep3147', 'foo.py'), 'w'):
pass
+ importlib.invalidate_caches()
m = __import__('pep3147.foo')
unload('pep3147.foo')
unload('pep3147')
+ importlib.invalidate_caches()
m = __import__('pep3147.foo')
init_pyc = imp.cache_from_source(
os.path.join('pep3147', '__init__.py'))
@@ -743,22 +772,290 @@ class PycacheTests(unittest.TestCase):
self.assertEqual(sys.modules['pep3147.foo'].__cached__,
os.path.join(os.curdir, foo_pyc))
+ def test_recompute_pyc_same_second(self):
+ # Even when the source file doesn't change timestamp, a change in
+ # source size is enough to trigger recomputation of the pyc file.
+ __import__(TESTFN)
+ unload(TESTFN)
+ with open(self.source, 'a') as fp:
+ print("x = 5", file=fp)
+ m = __import__(TESTFN)
+ self.assertEqual(m.x, 5)
+
+
+class TestSymbolicallyLinkedPackage(unittest.TestCase):
+ package_name = 'sample'
+ tagged = package_name + '-tagged'
+
+ def setUp(self):
+ test.support.rmtree(self.tagged)
+ test.support.rmtree(self.package_name)
+ self.orig_sys_path = sys.path[:]
-class RelativeImportFromImportlibTests(test_relative_imports.RelativeImports):
+ # create a sample package; imagine you have a package with a tag and
+ # you want to symbolically link it from its untagged name.
+ os.mkdir(self.tagged)
+ self.addCleanup(test.support.rmtree, self.tagged)
+ init_file = os.path.join(self.tagged, '__init__.py')
+ test.support.create_empty_file(init_file)
+ assert os.path.exists(init_file)
+
+ # now create a symlink to the tagged package
+ # sample -> sample-tagged
+ os.symlink(self.tagged, self.package_name, target_is_directory=True)
+ self.addCleanup(test.support.unlink, self.package_name)
+ importlib.invalidate_caches()
+
+ self.assertEqual(os.path.isdir(self.package_name), True)
+
+ assert os.path.isfile(os.path.join(self.package_name, '__init__.py'))
+
+ def tearDown(self):
+ sys.path[:] = self.orig_sys_path
+
+ # regression test for issue6727
+ @unittest.skipUnless(
+ not hasattr(sys, 'getwindowsversion')
+ or sys.getwindowsversion() >= (6, 0),
+ "Windows Vista or later required")
+ @test.support.skip_unless_symlink
+ def test_symlinked_dir_importable(self):
+ # make sure sample can only be imported from the current directory.
+ sys.path[:] = ['.']
+ assert os.path.exists(self.package_name)
+ assert os.path.exists(os.path.join(self.package_name, '__init__.py'))
+
+ # Try to import the package
+ importlib.import_module(self.package_name)
+
+
+@cpython_only
+class ImportlibBootstrapTests(unittest.TestCase):
+ # These tests check that importlib is bootstrapped.
+
+ def test_frozen_importlib(self):
+ mod = sys.modules['_frozen_importlib']
+ self.assertTrue(mod)
+
+ def test_frozen_importlib_is_bootstrap(self):
+ from importlib import _bootstrap
+ mod = sys.modules['_frozen_importlib']
+ self.assertIs(mod, _bootstrap)
+ self.assertEqual(mod.__name__, 'importlib._bootstrap')
+ self.assertEqual(mod.__package__, 'importlib')
+ self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__)
+
+ def test_there_can_be_only_one(self):
+ # Issue #15386 revealed a tricky loophole in the bootstrapping
+ # This test is technically redundant, since the bug caused importing
+ # this test module to crash completely, but it helps prove the point
+ from importlib import machinery
+ mod = sys.modules['_frozen_importlib']
+ self.assertIs(machinery.FileFinder, mod.FileFinder)
+ self.assertIs(imp.new_module, mod.new_module)
+
+
+@cpython_only
+class GetSourcefileTests(unittest.TestCase):
+
+ """Test importlib._bootstrap._get_sourcefile() as used by the C API.
+
+ Because of the peculiarities of the need of this function, the tests are
+ knowingly whitebox tests.
+
+ """
+
+ def test_get_sourcefile(self):
+ # Given a valid bytecode path, return the path to the corresponding
+ # source file if it exists.
+ with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile:
+ _path_isfile.return_value = True;
+ path = TESTFN + '.pyc'
+ expect = TESTFN + '.py'
+ self.assertEqual(_get_sourcefile(path), expect)
+
+ def test_get_sourcefile_no_source(self):
+ # Given a valid bytecode path without a corresponding source path,
+ # return the original bytecode path.
+ with mock.patch('importlib._bootstrap._path_isfile') as _path_isfile:
+ _path_isfile.return_value = False;
+ path = TESTFN + '.pyc'
+ self.assertEqual(_get_sourcefile(path), path)
+
+ def test_get_sourcefile_bad_ext(self):
+ # Given a path with an invalid bytecode extension, return the
+ # bytecode path passed as the argument.
+ path = TESTFN + '.bad_ext'
+ self.assertEqual(_get_sourcefile(path), path)
+
+
+class ImportTracebackTests(unittest.TestCase):
def setUp(self):
- self._importlib_util_flag = importlib_util.using___import__
- importlib_util.using___import__ = True
+ os.mkdir(TESTFN)
+ self.old_path = sys.path[:]
+ sys.path.insert(0, TESTFN)
def tearDown(self):
- importlib_util.using___import__ = self._importlib_util_flag
+ sys.path[:] = self.old_path
+ rmtree(TESTFN)
+
+ def create_module(self, mod, contents, ext=".py"):
+ fname = os.path.join(TESTFN, mod + ext)
+ with open(fname, "w") as f:
+ f.write(contents)
+ self.addCleanup(unload, mod)
+ importlib.invalidate_caches()
+ return fname
+
+ def assert_traceback(self, tb, files):
+ deduped_files = []
+ while tb:
+ code = tb.tb_frame.f_code
+ fn = code.co_filename
+ if not deduped_files or fn != deduped_files[-1]:
+ deduped_files.append(fn)
+ tb = tb.tb_next
+ self.assertEqual(len(deduped_files), len(files), deduped_files)
+ for fn, pat in zip(deduped_files, files):
+ self.assertIn(pat, fn)
+
+ def test_nonexistent_module(self):
+ try:
+ # assertRaises() clears __traceback__
+ import nonexistent_xyzzy
+ except ImportError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ImportError should have been raised")
+ self.assert_traceback(tb, [__file__])
+
+ def test_nonexistent_module_nested(self):
+ self.create_module("foo", "import nonexistent_xyzzy")
+ try:
+ import foo
+ except ImportError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ImportError should have been raised")
+ self.assert_traceback(tb, [__file__, 'foo.py'])
+
+ def test_exec_failure(self):
+ self.create_module("foo", "1/0")
+ try:
+ import foo
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, 'foo.py'])
+
+ def test_exec_failure_nested(self):
+ self.create_module("foo", "import bar")
+ self.create_module("bar", "1/0")
+ try:
+ import foo
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, 'foo.py', 'bar.py'])
+
+ # A few more examples from issue #15425
+ def test_syntax_error(self):
+ self.create_module("foo", "invalid syntax is invalid")
+ try:
+ import foo
+ except SyntaxError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("SyntaxError should have been raised")
+ self.assert_traceback(tb, [__file__])
+
+ def _setup_broken_package(self, parent, child):
+ pkg_name = "_parent_foo"
+ self.addCleanup(unload, pkg_name)
+ pkg_path = os.path.join(TESTFN, pkg_name)
+ os.mkdir(pkg_path)
+ # Touch the __init__.py
+ init_path = os.path.join(pkg_path, '__init__.py')
+ with open(init_path, 'w') as f:
+ f.write(parent)
+ bar_path = os.path.join(pkg_path, 'bar.py')
+ with open(bar_path, 'w') as f:
+ f.write(child)
+ importlib.invalidate_caches()
+ return init_path, bar_path
+
+ def test_broken_submodule(self):
+ init_path, bar_path = self._setup_broken_package("", "1/0")
+ try:
+ import _parent_foo.bar
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, bar_path])
+
+ def test_broken_from(self):
+ init_path, bar_path = self._setup_broken_package("", "1/0")
+ try:
+ from _parent_foo import bar
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ImportError should have been raised")
+ self.assert_traceback(tb, [__file__, bar_path])
+
+ def test_broken_parent(self):
+ init_path, bar_path = self._setup_broken_package("1/0", "")
+ try:
+ import _parent_foo.bar
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, init_path])
+
+ def test_broken_parent_from(self):
+ init_path, bar_path = self._setup_broken_package("1/0", "")
+ try:
+ from _parent_foo import bar
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, init_path])
+
+ @cpython_only
+ def test_import_bug(self):
+ # We simulate a bug in importlib and check that it's not stripped
+ # away from the traceback.
+ self.create_module("foo", "")
+ importlib = sys.modules['_frozen_importlib']
+ old_load_module = importlib.SourceLoader.load_module
+ try:
+ def load_module(*args):
+ 1/0
+ importlib.SourceLoader.load_module = load_module
+ try:
+ import foo
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ else:
+ self.fail("ZeroDivisionError should have been raised")
+ self.assert_traceback(tb, [__file__, '<frozen importlib', __file__])
+ finally:
+ importlib.SourceLoader.load_module = old_load_module
def test_main(verbose=None):
- run_unittest(ImportTests, PycacheTests,
+ run_unittest(ImportTests, PycacheTests, FilePermissionTests,
PycRewritingTests, PathsTests, RelativeImportTests,
OverridingImportBuiltinTests,
- RelativeImportFromImportlibTests)
+ ImportlibBootstrapTests, GetSourcefileTests,
+ TestSymbolicallyLinkedPackage,
+ ImportTracebackTests)
if __name__ == '__main__':