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