1# Test the runpy module 2import unittest 3import os 4import os.path 5import sys 6import re 7import tempfile 8import importlib, importlib.machinery, importlib.util 9import py_compile 10import warnings 11from test.support import ( 12 forget, make_legacy_pyc, unload, verbose, no_tracing, 13 create_empty_file, temp_dir) 14from test.support.script_helper import ( 15 make_pkg, make_script, make_zip_pkg, make_zip_script) 16 17 18import runpy 19from runpy import _run_code, _run_module_code, run_module, run_path 20# Note: This module can't safely test _run_module_as_main as it 21# runs its tests in the current process, which would mess with the 22# real __main__ module (usually test.regrtest) 23# See test_cmd_line_script for a test that executes that code path 24 25 26# Set up the test code and expected results 27example_source = """\ 28# Check basic code execution 29result = ['Top level assignment'] 30def f(): 31 result.append('Lower level reference') 32f() 33del f 34# Check the sys module 35import sys 36run_argv0 = sys.argv[0] 37run_name_in_sys_modules = __name__ in sys.modules 38module_in_sys_modules = (run_name_in_sys_modules and 39 globals() is sys.modules[__name__].__dict__) 40# Check nested operation 41import runpy 42nested = runpy._run_module_code('x=1\\n', mod_name='<run>') 43""" 44 45implicit_namespace = { 46 "__name__": None, 47 "__file__": None, 48 "__cached__": None, 49 "__package__": None, 50 "__doc__": None, 51 "__spec__": None 52} 53example_namespace = { 54 "sys": sys, 55 "runpy": runpy, 56 "result": ["Top level assignment", "Lower level reference"], 57 "run_argv0": sys.argv[0], 58 "run_name_in_sys_modules": False, 59 "module_in_sys_modules": False, 60 "nested": dict(implicit_namespace, 61 x=1, __name__="<run>", __loader__=None), 62} 63example_namespace.update(implicit_namespace) 64 65class CodeExecutionMixin: 66 # Issue #15230 (run_path not handling run_name correctly) highlighted a 67 # problem with the way arguments were being passed from higher level APIs 68 # down to lower level code. This mixin makes it easier to ensure full 69 # testing occurs at those upper layers as well, not just at the utility 70 # layer 71 72 # Figuring out the loader details in advance is hard to do, so we skip 73 # checking the full details of loader and loader_state 74 CHECKED_SPEC_ATTRIBUTES = ["name", "parent", "origin", "cached", 75 "has_location", "submodule_search_locations"] 76 77 def assertNamespaceMatches(self, result_ns, expected_ns): 78 """Check two namespaces match. 79 80 Ignores any unspecified interpreter created names 81 """ 82 # Avoid side effects 83 result_ns = result_ns.copy() 84 expected_ns = expected_ns.copy() 85 # Impls are permitted to add extra names, so filter them out 86 for k in list(result_ns): 87 if k.startswith("__") and k.endswith("__"): 88 if k not in expected_ns: 89 result_ns.pop(k) 90 if k not in expected_ns["nested"]: 91 result_ns["nested"].pop(k) 92 # Spec equality includes the loader, so we take the spec out of the 93 # result namespace and check that separately 94 result_spec = result_ns.pop("__spec__") 95 expected_spec = expected_ns.pop("__spec__") 96 if expected_spec is None: 97 self.assertIsNone(result_spec) 98 else: 99 # If an expected loader is set, we just check we got the right 100 # type, rather than checking for full equality 101 if expected_spec.loader is not None: 102 self.assertEqual(type(result_spec.loader), 103 type(expected_spec.loader)) 104 for attr in self.CHECKED_SPEC_ATTRIBUTES: 105 k = "__spec__." + attr 106 actual = (k, getattr(result_spec, attr)) 107 expected = (k, getattr(expected_spec, attr)) 108 self.assertEqual(actual, expected) 109 # For the rest, we still don't use direct dict comparison on the 110 # namespace, as the diffs are too hard to debug if anything breaks 111 self.assertEqual(set(result_ns), set(expected_ns)) 112 for k in result_ns: 113 actual = (k, result_ns[k]) 114 expected = (k, expected_ns[k]) 115 self.assertEqual(actual, expected) 116 117 def check_code_execution(self, create_namespace, expected_namespace): 118 """Check that an interface runs the example code correctly 119 120 First argument is a callable accepting the initial globals and 121 using them to create the actual namespace 122 Second argument is the expected result 123 """ 124 sentinel = object() 125 expected_ns = expected_namespace.copy() 126 run_name = expected_ns["__name__"] 127 saved_argv0 = sys.argv[0] 128 saved_mod = sys.modules.get(run_name, sentinel) 129 # Check without initial globals 130 result_ns = create_namespace(None) 131 self.assertNamespaceMatches(result_ns, expected_ns) 132 self.assertIs(sys.argv[0], saved_argv0) 133 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) 134 # And then with initial globals 135 initial_ns = {"sentinel": sentinel} 136 expected_ns["sentinel"] = sentinel 137 result_ns = create_namespace(initial_ns) 138 self.assertIsNot(result_ns, initial_ns) 139 self.assertNamespaceMatches(result_ns, expected_ns) 140 self.assertIs(sys.argv[0], saved_argv0) 141 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) 142 143 144class ExecutionLayerTestCase(unittest.TestCase, CodeExecutionMixin): 145 """Unit tests for runpy._run_code and runpy._run_module_code""" 146 147 def test_run_code(self): 148 expected_ns = example_namespace.copy() 149 expected_ns.update({ 150 "__loader__": None, 151 }) 152 def create_ns(init_globals): 153 return _run_code(example_source, {}, init_globals) 154 self.check_code_execution(create_ns, expected_ns) 155 156 def test_run_module_code(self): 157 mod_name = "<Nonsense>" 158 mod_fname = "Some other nonsense" 159 mod_loader = "Now you're just being silly" 160 mod_package = '' # Treat as a top level module 161 mod_spec = importlib.machinery.ModuleSpec(mod_name, 162 origin=mod_fname, 163 loader=mod_loader) 164 expected_ns = example_namespace.copy() 165 expected_ns.update({ 166 "__name__": mod_name, 167 "__file__": mod_fname, 168 "__loader__": mod_loader, 169 "__package__": mod_package, 170 "__spec__": mod_spec, 171 "run_argv0": mod_fname, 172 "run_name_in_sys_modules": True, 173 "module_in_sys_modules": True, 174 }) 175 def create_ns(init_globals): 176 return _run_module_code(example_source, 177 init_globals, 178 mod_name, 179 mod_spec) 180 self.check_code_execution(create_ns, expected_ns) 181 182# TODO: Use self.addCleanup to get rid of a lot of try-finally blocks 183class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): 184 """Unit tests for runpy.run_module""" 185 186 def expect_import_error(self, mod_name): 187 try: 188 run_module(mod_name) 189 except ImportError: 190 pass 191 else: 192 self.fail("Expected import error for " + mod_name) 193 194 def test_invalid_names(self): 195 # Builtin module 196 self.expect_import_error("sys") 197 # Non-existent modules 198 self.expect_import_error("sys.imp.eric") 199 self.expect_import_error("os.path.half") 200 self.expect_import_error("a.bee") 201 # Relative names not allowed 202 self.expect_import_error(".howard") 203 self.expect_import_error("..eaten") 204 self.expect_import_error(".test_runpy") 205 self.expect_import_error(".unittest") 206 # Package without __main__.py 207 self.expect_import_error("multiprocessing") 208 209 def test_library_module(self): 210 self.assertEqual(run_module("runpy")["__name__"], "runpy") 211 212 def _add_pkg_dir(self, pkg_dir, namespace=False): 213 os.mkdir(pkg_dir) 214 if namespace: 215 return None 216 pkg_fname = os.path.join(pkg_dir, "__init__.py") 217 create_empty_file(pkg_fname) 218 return pkg_fname 219 220 def _make_pkg(self, source, depth, mod_base="runpy_test", 221 *, namespace=False, parent_namespaces=False): 222 # Enforce a couple of internal sanity checks on test cases 223 if (namespace or parent_namespaces) and not depth: 224 raise RuntimeError("Can't mark top level module as a " 225 "namespace package") 226 pkg_name = "__runpy_pkg__" 227 test_fname = mod_base+os.extsep+"py" 228 pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) 229 if verbose > 1: print(" Package tree in:", sub_dir) 230 sys.path.insert(0, pkg_dir) 231 if verbose > 1: print(" Updated sys.path:", sys.path[0]) 232 if depth: 233 namespace_flags = [parent_namespaces] * depth 234 namespace_flags[-1] = namespace 235 for namespace_flag in namespace_flags: 236 sub_dir = os.path.join(sub_dir, pkg_name) 237 pkg_fname = self._add_pkg_dir(sub_dir, namespace_flag) 238 if verbose > 1: print(" Next level in:", sub_dir) 239 if verbose > 1: print(" Created:", pkg_fname) 240 mod_fname = os.path.join(sub_dir, test_fname) 241 mod_file = open(mod_fname, "w") 242 mod_file.write(source) 243 mod_file.close() 244 if verbose > 1: print(" Created:", mod_fname) 245 mod_name = (pkg_name+".")*depth + mod_base 246 mod_spec = importlib.util.spec_from_file_location(mod_name, 247 mod_fname) 248 return pkg_dir, mod_fname, mod_name, mod_spec 249 250 def _del_pkg(self, top): 251 for entry in list(sys.modules): 252 if entry.startswith("__runpy_pkg__"): 253 del sys.modules[entry] 254 if verbose > 1: print(" Removed sys.modules entries") 255 del sys.path[0] 256 if verbose > 1: print(" Removed sys.path entry") 257 for root, dirs, files in os.walk(top, topdown=False): 258 for name in files: 259 try: 260 os.remove(os.path.join(root, name)) 261 except OSError as ex: 262 if verbose > 1: print(ex) # Persist with cleaning up 263 for name in dirs: 264 fullname = os.path.join(root, name) 265 try: 266 os.rmdir(fullname) 267 except OSError as ex: 268 if verbose > 1: print(ex) # Persist with cleaning up 269 try: 270 os.rmdir(top) 271 if verbose > 1: print(" Removed package tree") 272 except OSError as ex: 273 if verbose > 1: print(ex) # Persist with cleaning up 274 275 def _fix_ns_for_legacy_pyc(self, ns, alter_sys): 276 char_to_add = "c" 277 ns["__file__"] += char_to_add 278 ns["__cached__"] = ns["__file__"] 279 spec = ns["__spec__"] 280 new_spec = importlib.util.spec_from_file_location(spec.name, 281 ns["__file__"]) 282 ns["__spec__"] = new_spec 283 if alter_sys: 284 ns["run_argv0"] += char_to_add 285 286 287 def _check_module(self, depth, alter_sys=False, 288 *, namespace=False, parent_namespaces=False): 289 pkg_dir, mod_fname, mod_name, mod_spec = ( 290 self._make_pkg(example_source, depth, 291 namespace=namespace, 292 parent_namespaces=parent_namespaces)) 293 forget(mod_name) 294 expected_ns = example_namespace.copy() 295 expected_ns.update({ 296 "__name__": mod_name, 297 "__file__": mod_fname, 298 "__cached__": mod_spec.cached, 299 "__package__": mod_name.rpartition(".")[0], 300 "__spec__": mod_spec, 301 }) 302 if alter_sys: 303 expected_ns.update({ 304 "run_argv0": mod_fname, 305 "run_name_in_sys_modules": True, 306 "module_in_sys_modules": True, 307 }) 308 def create_ns(init_globals): 309 return run_module(mod_name, init_globals, alter_sys=alter_sys) 310 try: 311 if verbose > 1: print("Running from source:", mod_name) 312 self.check_code_execution(create_ns, expected_ns) 313 importlib.invalidate_caches() 314 __import__(mod_name) 315 os.remove(mod_fname) 316 if not sys.dont_write_bytecode: 317 make_legacy_pyc(mod_fname) 318 unload(mod_name) # In case loader caches paths 319 importlib.invalidate_caches() 320 if verbose > 1: print("Running from compiled:", mod_name) 321 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) 322 self.check_code_execution(create_ns, expected_ns) 323 finally: 324 self._del_pkg(pkg_dir) 325 if verbose > 1: print("Module executed successfully") 326 327 def _check_package(self, depth, alter_sys=False, 328 *, namespace=False, parent_namespaces=False): 329 pkg_dir, mod_fname, mod_name, mod_spec = ( 330 self._make_pkg(example_source, depth, "__main__", 331 namespace=namespace, 332 parent_namespaces=parent_namespaces)) 333 pkg_name = mod_name.rpartition(".")[0] 334 forget(mod_name) 335 expected_ns = example_namespace.copy() 336 expected_ns.update({ 337 "__name__": mod_name, 338 "__file__": mod_fname, 339 "__cached__": importlib.util.cache_from_source(mod_fname), 340 "__package__": pkg_name, 341 "__spec__": mod_spec, 342 }) 343 if alter_sys: 344 expected_ns.update({ 345 "run_argv0": mod_fname, 346 "run_name_in_sys_modules": True, 347 "module_in_sys_modules": True, 348 }) 349 def create_ns(init_globals): 350 return run_module(pkg_name, init_globals, alter_sys=alter_sys) 351 try: 352 if verbose > 1: print("Running from source:", pkg_name) 353 self.check_code_execution(create_ns, expected_ns) 354 importlib.invalidate_caches() 355 __import__(mod_name) 356 os.remove(mod_fname) 357 if not sys.dont_write_bytecode: 358 make_legacy_pyc(mod_fname) 359 unload(mod_name) # In case loader caches paths 360 if verbose > 1: print("Running from compiled:", pkg_name) 361 importlib.invalidate_caches() 362 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) 363 self.check_code_execution(create_ns, expected_ns) 364 finally: 365 self._del_pkg(pkg_dir) 366 if verbose > 1: print("Package executed successfully") 367 368 def _add_relative_modules(self, base_dir, source, depth): 369 if depth <= 1: 370 raise ValueError("Relative module test needs depth > 1") 371 pkg_name = "__runpy_pkg__" 372 module_dir = base_dir 373 for i in range(depth): 374 parent_dir = module_dir 375 module_dir = os.path.join(module_dir, pkg_name) 376 # Add sibling module 377 sibling_fname = os.path.join(module_dir, "sibling.py") 378 create_empty_file(sibling_fname) 379 if verbose > 1: print(" Added sibling module:", sibling_fname) 380 # Add nephew module 381 uncle_dir = os.path.join(parent_dir, "uncle") 382 self._add_pkg_dir(uncle_dir) 383 if verbose > 1: print(" Added uncle package:", uncle_dir) 384 cousin_dir = os.path.join(uncle_dir, "cousin") 385 self._add_pkg_dir(cousin_dir) 386 if verbose > 1: print(" Added cousin package:", cousin_dir) 387 nephew_fname = os.path.join(cousin_dir, "nephew.py") 388 create_empty_file(nephew_fname) 389 if verbose > 1: print(" Added nephew module:", nephew_fname) 390 391 def _check_relative_imports(self, depth, run_name=None): 392 contents = r"""\ 393from __future__ import absolute_import 394from . import sibling 395from ..uncle.cousin import nephew 396""" 397 pkg_dir, mod_fname, mod_name, mod_spec = ( 398 self._make_pkg(contents, depth)) 399 if run_name is None: 400 expected_name = mod_name 401 else: 402 expected_name = run_name 403 try: 404 self._add_relative_modules(pkg_dir, contents, depth) 405 pkg_name = mod_name.rpartition('.')[0] 406 if verbose > 1: print("Running from source:", mod_name) 407 d1 = run_module(mod_name, run_name=run_name) # Read from source 408 self.assertEqual(d1["__name__"], expected_name) 409 self.assertEqual(d1["__package__"], pkg_name) 410 self.assertIn("sibling", d1) 411 self.assertIn("nephew", d1) 412 del d1 # Ensure __loader__ entry doesn't keep file open 413 importlib.invalidate_caches() 414 __import__(mod_name) 415 os.remove(mod_fname) 416 if not sys.dont_write_bytecode: 417 make_legacy_pyc(mod_fname) 418 unload(mod_name) # In case the loader caches paths 419 if verbose > 1: print("Running from compiled:", mod_name) 420 importlib.invalidate_caches() 421 d2 = run_module(mod_name, run_name=run_name) # Read from bytecode 422 self.assertEqual(d2["__name__"], expected_name) 423 self.assertEqual(d2["__package__"], pkg_name) 424 self.assertIn("sibling", d2) 425 self.assertIn("nephew", d2) 426 del d2 # Ensure __loader__ entry doesn't keep file open 427 finally: 428 self._del_pkg(pkg_dir) 429 if verbose > 1: print("Module executed successfully") 430 431 def test_run_module(self): 432 for depth in range(4): 433 if verbose > 1: print("Testing package depth:", depth) 434 self._check_module(depth) 435 436 def test_run_module_in_namespace_package(self): 437 for depth in range(1, 4): 438 if verbose > 1: print("Testing package depth:", depth) 439 self._check_module(depth, namespace=True, parent_namespaces=True) 440 441 def test_run_package(self): 442 for depth in range(1, 4): 443 if verbose > 1: print("Testing package depth:", depth) 444 self._check_package(depth) 445 446 def test_run_package_init_exceptions(self): 447 # These were previously wrapped in an ImportError; see Issue 14285 448 result = self._make_pkg("", 1, "__main__") 449 pkg_dir, _, mod_name, _ = result 450 mod_name = mod_name.replace(".__main__", "") 451 self.addCleanup(self._del_pkg, pkg_dir) 452 init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py") 453 454 exceptions = (ImportError, AttributeError, TypeError, ValueError) 455 for exception in exceptions: 456 name = exception.__name__ 457 with self.subTest(name): 458 source = "raise {0}('{0} in __init__.py.')".format(name) 459 with open(init, "wt", encoding="ascii") as mod_file: 460 mod_file.write(source) 461 try: 462 run_module(mod_name) 463 except exception as err: 464 self.assertNotIn("finding spec", format(err)) 465 else: 466 self.fail("Nothing raised; expected {}".format(name)) 467 try: 468 run_module(mod_name + ".submodule") 469 except exception as err: 470 self.assertNotIn("finding spec", format(err)) 471 else: 472 self.fail("Nothing raised; expected {}".format(name)) 473 474 def test_submodule_imported_warning(self): 475 pkg_dir, _, mod_name, _ = self._make_pkg("", 1) 476 try: 477 __import__(mod_name) 478 with self.assertWarnsRegex(RuntimeWarning, 479 r"found in sys\.modules"): 480 run_module(mod_name) 481 finally: 482 self._del_pkg(pkg_dir) 483 484 def test_package_imported_no_warning(self): 485 pkg_dir, _, mod_name, _ = self._make_pkg("", 1, "__main__") 486 self.addCleanup(self._del_pkg, pkg_dir) 487 package = mod_name.replace(".__main__", "") 488 # No warning should occur if we only imported the parent package 489 __import__(package) 490 self.assertIn(package, sys.modules) 491 with warnings.catch_warnings(): 492 warnings.simplefilter("error", RuntimeWarning) 493 run_module(package) 494 # But the warning should occur if we imported the __main__ submodule 495 __import__(mod_name) 496 with self.assertWarnsRegex(RuntimeWarning, r"found in sys\.modules"): 497 run_module(package) 498 499 def test_run_package_in_namespace_package(self): 500 for depth in range(1, 4): 501 if verbose > 1: print("Testing package depth:", depth) 502 self._check_package(depth, parent_namespaces=True) 503 504 def test_run_namespace_package(self): 505 for depth in range(1, 4): 506 if verbose > 1: print("Testing package depth:", depth) 507 self._check_package(depth, namespace=True) 508 509 def test_run_namespace_package_in_namespace_package(self): 510 for depth in range(1, 4): 511 if verbose > 1: print("Testing package depth:", depth) 512 self._check_package(depth, namespace=True, parent_namespaces=True) 513 514 def test_run_module_alter_sys(self): 515 for depth in range(4): 516 if verbose > 1: print("Testing package depth:", depth) 517 self._check_module(depth, alter_sys=True) 518 519 def test_run_package_alter_sys(self): 520 for depth in range(1, 4): 521 if verbose > 1: print("Testing package depth:", depth) 522 self._check_package(depth, alter_sys=True) 523 524 def test_explicit_relative_import(self): 525 for depth in range(2, 5): 526 if verbose > 1: print("Testing relative imports at depth:", depth) 527 self._check_relative_imports(depth) 528 529 def test_main_relative_import(self): 530 for depth in range(2, 5): 531 if verbose > 1: print("Testing main relative imports at depth:", depth) 532 self._check_relative_imports(depth, "__main__") 533 534 def test_run_name(self): 535 depth = 1 536 run_name = "And now for something completely different" 537 pkg_dir, mod_fname, mod_name, mod_spec = ( 538 self._make_pkg(example_source, depth)) 539 forget(mod_name) 540 expected_ns = example_namespace.copy() 541 expected_ns.update({ 542 "__name__": run_name, 543 "__file__": mod_fname, 544 "__cached__": importlib.util.cache_from_source(mod_fname), 545 "__package__": mod_name.rpartition(".")[0], 546 "__spec__": mod_spec, 547 }) 548 def create_ns(init_globals): 549 return run_module(mod_name, init_globals, run_name) 550 try: 551 self.check_code_execution(create_ns, expected_ns) 552 finally: 553 self._del_pkg(pkg_dir) 554 555 def test_pkgutil_walk_packages(self): 556 # This is a dodgy hack to use the test_runpy infrastructure to test 557 # issue #15343. Issue #15348 declares this is indeed a dodgy hack ;) 558 import pkgutil 559 max_depth = 4 560 base_name = "__runpy_pkg__" 561 package_suffixes = ["uncle", "uncle.cousin"] 562 module_suffixes = ["uncle.cousin.nephew", base_name + ".sibling"] 563 expected_packages = set() 564 expected_modules = set() 565 for depth in range(1, max_depth): 566 pkg_name = ".".join([base_name] * depth) 567 expected_packages.add(pkg_name) 568 for name in package_suffixes: 569 expected_packages.add(pkg_name + "." + name) 570 for name in module_suffixes: 571 expected_modules.add(pkg_name + "." + name) 572 pkg_name = ".".join([base_name] * max_depth) 573 expected_packages.add(pkg_name) 574 expected_modules.add(pkg_name + ".runpy_test") 575 pkg_dir, mod_fname, mod_name, mod_spec = ( 576 self._make_pkg("", max_depth)) 577 self.addCleanup(self._del_pkg, pkg_dir) 578 for depth in range(2, max_depth+1): 579 self._add_relative_modules(pkg_dir, "", depth) 580 for moduleinfo in pkgutil.walk_packages([pkg_dir]): 581 self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo) 582 self.assertIsInstance(moduleinfo.module_finder, 583 importlib.machinery.FileFinder) 584 if moduleinfo.ispkg: 585 expected_packages.remove(moduleinfo.name) 586 else: 587 expected_modules.remove(moduleinfo.name) 588 self.assertEqual(len(expected_packages), 0, expected_packages) 589 self.assertEqual(len(expected_modules), 0, expected_modules) 590 591class RunPathTestCase(unittest.TestCase, CodeExecutionMixin): 592 """Unit tests for runpy.run_path""" 593 594 def _make_test_script(self, script_dir, script_basename, 595 source=None, omit_suffix=False): 596 if source is None: 597 source = example_source 598 return make_script(script_dir, script_basename, 599 source, omit_suffix) 600 601 def _check_script(self, script_name, expected_name, expected_file, 602 expected_argv0, mod_name=None, 603 expect_spec=True, check_loader=True): 604 # First check is without run_name 605 def create_ns(init_globals): 606 return run_path(script_name, init_globals) 607 expected_ns = example_namespace.copy() 608 if mod_name is None: 609 spec_name = expected_name 610 else: 611 spec_name = mod_name 612 if expect_spec: 613 mod_spec = importlib.util.spec_from_file_location(spec_name, 614 expected_file) 615 mod_cached = mod_spec.cached 616 if not check_loader: 617 mod_spec.loader = None 618 else: 619 mod_spec = mod_cached = None 620 621 expected_ns.update({ 622 "__name__": expected_name, 623 "__file__": expected_file, 624 "__cached__": mod_cached, 625 "__package__": "", 626 "__spec__": mod_spec, 627 "run_argv0": expected_argv0, 628 "run_name_in_sys_modules": True, 629 "module_in_sys_modules": True, 630 }) 631 self.check_code_execution(create_ns, expected_ns) 632 # Second check makes sure run_name works in all cases 633 run_name = "prove.issue15230.is.fixed" 634 def create_ns(init_globals): 635 return run_path(script_name, init_globals, run_name) 636 if expect_spec and mod_name is None: 637 mod_spec = importlib.util.spec_from_file_location(run_name, 638 expected_file) 639 if not check_loader: 640 mod_spec.loader = None 641 expected_ns["__spec__"] = mod_spec 642 expected_ns["__name__"] = run_name 643 expected_ns["__package__"] = run_name.rpartition(".")[0] 644 self.check_code_execution(create_ns, expected_ns) 645 646 def _check_import_error(self, script_name, msg): 647 msg = re.escape(msg) 648 self.assertRaisesRegex(ImportError, msg, run_path, script_name) 649 650 def test_basic_script(self): 651 with temp_dir() as script_dir: 652 mod_name = 'script' 653 script_name = self._make_test_script(script_dir, mod_name) 654 self._check_script(script_name, "<run_path>", script_name, 655 script_name, expect_spec=False) 656 657 def test_basic_script_no_suffix(self): 658 with temp_dir() as script_dir: 659 mod_name = 'script' 660 script_name = self._make_test_script(script_dir, mod_name, 661 omit_suffix=True) 662 self._check_script(script_name, "<run_path>", script_name, 663 script_name, expect_spec=False) 664 665 def test_script_compiled(self): 666 with temp_dir() as script_dir: 667 mod_name = 'script' 668 script_name = self._make_test_script(script_dir, mod_name) 669 compiled_name = py_compile.compile(script_name, doraise=True) 670 os.remove(script_name) 671 self._check_script(compiled_name, "<run_path>", compiled_name, 672 compiled_name, expect_spec=False) 673 674 def test_directory(self): 675 with temp_dir() as script_dir: 676 mod_name = '__main__' 677 script_name = self._make_test_script(script_dir, mod_name) 678 self._check_script(script_dir, "<run_path>", script_name, 679 script_dir, mod_name=mod_name) 680 681 def test_directory_compiled(self): 682 with temp_dir() as script_dir: 683 mod_name = '__main__' 684 script_name = self._make_test_script(script_dir, mod_name) 685 compiled_name = py_compile.compile(script_name, doraise=True) 686 os.remove(script_name) 687 if not sys.dont_write_bytecode: 688 legacy_pyc = make_legacy_pyc(script_name) 689 self._check_script(script_dir, "<run_path>", legacy_pyc, 690 script_dir, mod_name=mod_name) 691 692 def test_directory_error(self): 693 with temp_dir() as script_dir: 694 mod_name = 'not_main' 695 script_name = self._make_test_script(script_dir, mod_name) 696 msg = "can't find '__main__' module in %r" % script_dir 697 self._check_import_error(script_dir, msg) 698 699 def test_zipfile(self): 700 with temp_dir() as script_dir: 701 mod_name = '__main__' 702 script_name = self._make_test_script(script_dir, mod_name) 703 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 704 self._check_script(zip_name, "<run_path>", fname, zip_name, 705 mod_name=mod_name, check_loader=False) 706 707 def test_zipfile_compiled(self): 708 with temp_dir() as script_dir: 709 mod_name = '__main__' 710 script_name = self._make_test_script(script_dir, mod_name) 711 compiled_name = py_compile.compile(script_name, doraise=True) 712 zip_name, fname = make_zip_script(script_dir, 'test_zip', 713 compiled_name) 714 self._check_script(zip_name, "<run_path>", fname, zip_name, 715 mod_name=mod_name, check_loader=False) 716 717 def test_zipfile_error(self): 718 with temp_dir() as script_dir: 719 mod_name = 'not_main' 720 script_name = self._make_test_script(script_dir, mod_name) 721 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 722 msg = "can't find '__main__' module in %r" % zip_name 723 self._check_import_error(zip_name, msg) 724 725 @no_tracing 726 def test_main_recursion_error(self): 727 with temp_dir() as script_dir, temp_dir() as dummy_dir: 728 mod_name = '__main__' 729 source = ("import runpy\n" 730 "runpy.run_path(%r)\n") % dummy_dir 731 script_name = self._make_test_script(script_dir, mod_name, source) 732 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 733 msg = "recursion depth exceeded" 734 self.assertRaisesRegex(RecursionError, msg, run_path, zip_name) 735 736 def test_encoding(self): 737 with temp_dir() as script_dir: 738 filename = os.path.join(script_dir, 'script.py') 739 with open(filename, 'w', encoding='latin1') as f: 740 f.write(""" 741#coding:latin1 742s = "non-ASCII: h\xe9" 743""") 744 result = run_path(filename) 745 self.assertEqual(result['s'], "non-ASCII: h\xe9") 746 747 748if __name__ == "__main__": 749 unittest.main() 750