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.py373
1 files changed, 314 insertions, 59 deletions
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
index 0f8f1f584f..07464114dd 100644
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -1,7 +1,8 @@
+# We import importlib *ASAP* in order to test #15386
+import importlib
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
@@ -12,11 +13,13 @@ import sys
import unittest
import textwrap
import errno
+import shutil
+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
@@ -34,6 +37,7 @@ class ImportTests(unittest.TestCase):
def setUp(self):
remove_files(TESTFN)
+ importlib.invalidate_caches()
def tearDown(self):
unload(TESTFN)
@@ -71,6 +75,7 @@ class ImportTests(unittest.TestCase):
if TESTFN in sys.modules:
del sys.modules[TESTFN]
+ importlib.invalidate_caches()
try:
try:
mod = __import__(TESTFN)
@@ -98,48 +103,51 @@ class ImportTests(unittest.TestCase):
@unittest.skipUnless(os.name == 'posix',
"test meaningful only on posix systems")
- 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):
+ def test_creation_mode(self):
+ mask = 0o022
+ with temp_umask(mask):
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))
+ create_empty_file(fname)
fn = imp.cache_from_source(fname)
unlink(fn)
+ importlib.invalidate_caches()
__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)
+ # Check that the umask is respected, and the executable bits
+ # aren't set.
+ self.assertEqual(oct(stat.S_IMODE(s.st_mode)), oct(0o666 & ~mask))
finally:
del sys.path[0]
remove_files(TESTFN)
unload(TESTFN)
- 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)
+ @unittest.skipUnless(os.name == 'posix',
+ "test meaningful only on posix systems")
+ def test_cached_mode_issue_2051(self):
+ mode = 0o600
+ source = TESTFN + ".py"
+ with script_helper.temp_dir() as tempdir:
+ path = script_helper.make_script(tempdir, TESTFN,
+ "key='top secret'")
+ os.chmod(path, mode)
+ compiled = imp.cache_from_source(path)
+ sys.path.insert(0, tempdir)
+ try:
+ __import__(TESTFN)
+ finally:
+ sys.path.remove(tempdir)
+
+ if not os.path.exists(compiled):
+ self.fail("__import__ did not result in creation of "
+ "either a .pyc or .pyo file")
+ stat_info = os.stat(compiled)
+
+ self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode))
def test_bug7732(self):
source = TESTFN + '.py'
@@ -170,6 +178,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)
@@ -189,6 +198,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:
@@ -262,6 +272,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'))
@@ -282,12 +293,6 @@ class ImportTests(unittest.TestCase):
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()
@@ -297,8 +302,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
@@ -335,6 +338,12 @@ 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")
+
class PycRewritingTests(unittest.TestCase):
# Test that the `co_filename` attribute on code objects always points
@@ -362,6 +371,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
@@ -401,6 +411,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)
@@ -409,7 +420,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__
@@ -451,9 +462,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
@@ -468,13 +481,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):
@@ -515,7 +530,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
@@ -563,6 +578,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]'
@@ -610,6 +626,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)))
@@ -630,6 +647,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)))
@@ -638,6 +656,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
@@ -645,8 +665,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'))
@@ -660,18 +679,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'))
@@ -680,22 +701,256 @@ 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[:]
+
+ # 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)
-class RelativeImportFromImportlibTests(test_relative_imports.RelativeImports):
+ 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)
+
+
+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,
PycRewritingTests, PathsTests, RelativeImportTests,
OverridingImportBuiltinTests,
- RelativeImportFromImportlibTests)
+ ImportlibBootstrapTests,
+ TestSymbolicallyLinkedPackage,
+ ImportTracebackTests)
if __name__ == '__main__':