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