1# Test the runpy module 2import unittest 3import os 4import os.path 5import sys 6import re 7import tempfile 8from test.test_support import verbose, run_unittest, forget 9from test.script_helper import (temp_dir, make_script, compile_script, 10 make_pkg, make_zip_script, make_zip_pkg) 11 12 13from runpy import _run_code, _run_module_code, run_module, run_path 14# Note: This module can't safely test _run_module_as_main as it 15# runs its tests in the current process, which would mess with the 16# real __main__ module (usually test.regrtest) 17# See test_cmd_line_script for a test that executes that code path 18 19# Set up the test code and expected results 20 21class RunModuleCodeTest(unittest.TestCase): 22 """Unit tests for runpy._run_code and runpy._run_module_code""" 23 24 expected_result = ["Top level assignment", "Lower level reference"] 25 test_source = ( 26 "# Check basic code execution\n" 27 "result = ['Top level assignment']\n" 28 "def f():\n" 29 " result.append('Lower level reference')\n" 30 "f()\n" 31 "# Check the sys module\n" 32 "import sys\n" 33 "run_argv0 = sys.argv[0]\n" 34 "run_name_in_sys_modules = __name__ in sys.modules\n" 35 "if run_name_in_sys_modules:\n" 36 " module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n" 37 "# Check nested operation\n" 38 "import runpy\n" 39 "nested = runpy._run_module_code('x=1\\n', mod_name='<run>')\n" 40 ) 41 42 def test_run_code(self): 43 saved_argv0 = sys.argv[0] 44 d = _run_code(self.test_source, {}) 45 self.assertEqual(d["result"], self.expected_result) 46 self.assertIs(d["__name__"], None) 47 self.assertIs(d["__file__"], None) 48 self.assertIs(d["__loader__"], None) 49 self.assertIs(d["__package__"], None) 50 self.assertIs(d["run_argv0"], saved_argv0) 51 self.assertNotIn("run_name", d) 52 self.assertIs(sys.argv[0], saved_argv0) 53 54 def test_run_module_code(self): 55 initial = object() 56 name = "<Nonsense>" 57 file = "Some other nonsense" 58 loader = "Now you're just being silly" 59 package = '' # Treat as a top level module 60 d1 = dict(initial=initial) 61 saved_argv0 = sys.argv[0] 62 d2 = _run_module_code(self.test_source, 63 d1, 64 name, 65 file, 66 loader, 67 package) 68 self.assertNotIn("result", d1) 69 self.assertIs(d2["initial"], initial) 70 self.assertEqual(d2["result"], self.expected_result) 71 self.assertEqual(d2["nested"]["x"], 1) 72 self.assertIs(d2["__name__"], name) 73 self.assertTrue(d2["run_name_in_sys_modules"]) 74 self.assertTrue(d2["module_in_sys_modules"]) 75 self.assertIs(d2["__file__"], file) 76 self.assertIs(d2["run_argv0"], file) 77 self.assertIs(d2["__loader__"], loader) 78 self.assertIs(d2["__package__"], package) 79 self.assertIs(sys.argv[0], saved_argv0) 80 self.assertNotIn(name, sys.modules) 81 82 83class RunModuleTest(unittest.TestCase): 84 """Unit tests for runpy.run_module""" 85 86 def expect_import_error(self, mod_name): 87 try: 88 run_module(mod_name) 89 except ImportError: 90 pass 91 else: 92 self.fail("Expected import error for " + mod_name) 93 94 def test_invalid_names(self): 95 # Builtin module 96 self.expect_import_error("sys") 97 # Non-existent modules 98 self.expect_import_error("sys.imp.eric") 99 self.expect_import_error("os.path.half") 100 self.expect_import_error("a.bee") 101 self.expect_import_error(".howard") 102 self.expect_import_error("..eaten") 103 # Package without __main__.py 104 self.expect_import_error("multiprocessing") 105 106 def test_library_module(self): 107 run_module("runpy") 108 109 def _add_pkg_dir(self, pkg_dir): 110 os.mkdir(pkg_dir) 111 pkg_fname = os.path.join(pkg_dir, "__init__"+os.extsep+"py") 112 pkg_file = open(pkg_fname, "w") 113 pkg_file.close() 114 return pkg_fname 115 116 def _make_pkg(self, source, depth, mod_base="runpy_test"): 117 pkg_name = "__runpy_pkg__" 118 test_fname = mod_base+os.extsep+"py" 119 pkg_dir = sub_dir = tempfile.mkdtemp() 120 if verbose: print " Package tree in:", sub_dir 121 sys.path.insert(0, pkg_dir) 122 if verbose: print " Updated sys.path:", sys.path[0] 123 for i in range(depth): 124 sub_dir = os.path.join(sub_dir, pkg_name) 125 pkg_fname = self._add_pkg_dir(sub_dir) 126 if verbose: print " Next level in:", sub_dir 127 if verbose: print " Created:", pkg_fname 128 mod_fname = os.path.join(sub_dir, test_fname) 129 mod_file = open(mod_fname, "w") 130 mod_file.write(source) 131 mod_file.close() 132 if verbose: print " Created:", mod_fname 133 mod_name = (pkg_name+".")*depth + mod_base 134 return pkg_dir, mod_fname, mod_name 135 136 def _del_pkg(self, top, depth, mod_name): 137 for entry in list(sys.modules): 138 if entry.startswith("__runpy_pkg__"): 139 del sys.modules[entry] 140 if verbose: print " Removed sys.modules entries" 141 del sys.path[0] 142 if verbose: print " Removed sys.path entry" 143 for root, dirs, files in os.walk(top, topdown=False): 144 for name in files: 145 try: 146 os.remove(os.path.join(root, name)) 147 except OSError, ex: 148 if verbose: print ex # Persist with cleaning up 149 for name in dirs: 150 fullname = os.path.join(root, name) 151 try: 152 os.rmdir(fullname) 153 except OSError, ex: 154 if verbose: print ex # Persist with cleaning up 155 try: 156 os.rmdir(top) 157 if verbose: print " Removed package tree" 158 except OSError, ex: 159 if verbose: print ex # Persist with cleaning up 160 161 def _check_module(self, depth): 162 pkg_dir, mod_fname, mod_name = ( 163 self._make_pkg("x=1\n", depth)) 164 forget(mod_name) 165 try: 166 if verbose: print "Running from source:", mod_name 167 d1 = run_module(mod_name) # Read from source 168 self.assertIn("x", d1) 169 self.assertTrue(d1["x"] == 1) 170 del d1 # Ensure __loader__ entry doesn't keep file open 171 __import__(mod_name) 172 os.remove(mod_fname) 173 if not sys.dont_write_bytecode: 174 if verbose: print "Running from compiled:", mod_name 175 d2 = run_module(mod_name) # Read from bytecode 176 self.assertIn("x", d2) 177 self.assertTrue(d2["x"] == 1) 178 del d2 # Ensure __loader__ entry doesn't keep file open 179 finally: 180 self._del_pkg(pkg_dir, depth, mod_name) 181 if verbose: print "Module executed successfully" 182 183 def _check_package(self, depth): 184 pkg_dir, mod_fname, mod_name = ( 185 self._make_pkg("x=1\n", depth, "__main__")) 186 pkg_name, _, _ = mod_name.rpartition(".") 187 forget(mod_name) 188 try: 189 if verbose: print "Running from source:", pkg_name 190 d1 = run_module(pkg_name) # Read from source 191 self.assertIn("x", d1) 192 self.assertTrue(d1["x"] == 1) 193 del d1 # Ensure __loader__ entry doesn't keep file open 194 __import__(mod_name) 195 os.remove(mod_fname) 196 if not sys.dont_write_bytecode: 197 if verbose: print "Running from compiled:", pkg_name 198 d2 = run_module(pkg_name) # Read from bytecode 199 self.assertIn("x", d2) 200 self.assertTrue(d2["x"] == 1) 201 del d2 # Ensure __loader__ entry doesn't keep file open 202 finally: 203 self._del_pkg(pkg_dir, depth, pkg_name) 204 if verbose: print "Package executed successfully" 205 206 def _add_relative_modules(self, base_dir, source, depth): 207 if depth <= 1: 208 raise ValueError("Relative module test needs depth > 1") 209 pkg_name = "__runpy_pkg__" 210 module_dir = base_dir 211 for i in range(depth): 212 parent_dir = module_dir 213 module_dir = os.path.join(module_dir, pkg_name) 214 # Add sibling module 215 sibling_fname = os.path.join(module_dir, "sibling"+os.extsep+"py") 216 sibling_file = open(sibling_fname, "w") 217 sibling_file.close() 218 if verbose: print " Added sibling module:", sibling_fname 219 # Add nephew module 220 uncle_dir = os.path.join(parent_dir, "uncle") 221 self._add_pkg_dir(uncle_dir) 222 if verbose: print " Added uncle package:", uncle_dir 223 cousin_dir = os.path.join(uncle_dir, "cousin") 224 self._add_pkg_dir(cousin_dir) 225 if verbose: print " Added cousin package:", cousin_dir 226 nephew_fname = os.path.join(cousin_dir, "nephew"+os.extsep+"py") 227 nephew_file = open(nephew_fname, "w") 228 nephew_file.close() 229 if verbose: print " Added nephew module:", nephew_fname 230 231 def _check_relative_imports(self, depth, run_name=None): 232 contents = r"""\ 233from __future__ import absolute_import 234from . import sibling 235from ..uncle.cousin import nephew 236""" 237 pkg_dir, mod_fname, mod_name = ( 238 self._make_pkg(contents, depth)) 239 try: 240 self._add_relative_modules(pkg_dir, contents, depth) 241 pkg_name = mod_name.rpartition('.')[0] 242 if verbose: print "Running from source:", mod_name 243 d1 = run_module(mod_name, run_name=run_name) # Read from source 244 self.assertIn("__package__", d1) 245 self.assertTrue(d1["__package__"] == pkg_name) 246 self.assertIn("sibling", d1) 247 self.assertIn("nephew", d1) 248 del d1 # Ensure __loader__ entry doesn't keep file open 249 __import__(mod_name) 250 os.remove(mod_fname) 251 if not sys.dont_write_bytecode: 252 if verbose: print "Running from compiled:", mod_name 253 d2 = run_module(mod_name, run_name=run_name) # Read from bytecode 254 self.assertIn("__package__", d2) 255 self.assertTrue(d2["__package__"] == pkg_name) 256 self.assertIn("sibling", d2) 257 self.assertIn("nephew", d2) 258 del d2 # Ensure __loader__ entry doesn't keep file open 259 finally: 260 self._del_pkg(pkg_dir, depth, mod_name) 261 if verbose: print "Module executed successfully" 262 263 def test_run_module(self): 264 for depth in range(4): 265 if verbose: print "Testing package depth:", depth 266 self._check_module(depth) 267 268 def test_run_package(self): 269 for depth in range(1, 4): 270 if verbose: print "Testing package depth:", depth 271 self._check_package(depth) 272 273 def test_run_package_init_exceptions(self): 274 # These were previously wrapped in an ImportError; see Issue 14285 275 exceptions = (ImportError, AttributeError, TypeError, ValueError) 276 for exception in exceptions: 277 name = exception.__name__ 278 source = "raise {0}('{0} in __init__.py.')".format(name) 279 280 result = self._make_pkg("", 1, "__main__") 281 pkg_dir, _, mod_name = result 282 mod_name = mod_name.replace(".__main__", "") 283 try: 284 init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py") 285 with open(init, "wt") as mod_file: 286 mod_file.write(source) 287 try: 288 run_module(mod_name) 289 except exception as err: 290 msg = "cannot be directly executed" 291 self.assertNotIn(msg, format(err)) 292 else: 293 self.fail("Nothing raised; expected {}".format(name)) 294 finally: 295 self._del_pkg(pkg_dir, 1, mod_name) 296 297 def test_explicit_relative_import(self): 298 for depth in range(2, 5): 299 if verbose: print "Testing relative imports at depth:", depth 300 self._check_relative_imports(depth) 301 302 def test_main_relative_import(self): 303 for depth in range(2, 5): 304 if verbose: print "Testing main relative imports at depth:", depth 305 self._check_relative_imports(depth, "__main__") 306 307 308class RunPathTest(unittest.TestCase): 309 """Unit tests for runpy.run_path""" 310 # Based on corresponding tests in test_cmd_line_script 311 312 test_source = """\ 313# Script may be run with optimisation enabled, so don't rely on assert 314# statements being executed 315def assertEqual(lhs, rhs): 316 if lhs != rhs: 317 raise AssertionError('%r != %r' % (lhs, rhs)) 318def assertIs(lhs, rhs): 319 if lhs is not rhs: 320 raise AssertionError('%r is not %r' % (lhs, rhs)) 321# Check basic code execution 322result = ['Top level assignment'] 323def f(): 324 result.append('Lower level reference') 325f() 326assertEqual(result, ['Top level assignment', 'Lower level reference']) 327# Check the sys module 328import sys 329assertIs(globals(), sys.modules[__name__].__dict__) 330argv0 = sys.argv[0] 331""" 332 333 def _make_test_script(self, script_dir, script_basename, source=None): 334 if source is None: 335 source = self.test_source 336 return make_script(script_dir, script_basename, source) 337 338 def _check_script(self, script_name, expected_name, expected_file, 339 expected_argv0, expected_package): 340 result = run_path(script_name) 341 self.assertEqual(result["__name__"], expected_name) 342 self.assertEqual(result["__file__"], expected_file) 343 self.assertIn("argv0", result) 344 self.assertEqual(result["argv0"], expected_argv0) 345 self.assertEqual(result["__package__"], expected_package) 346 347 def _check_import_error(self, script_name, msg): 348 msg = re.escape(msg) 349 self.assertRaisesRegexp(ImportError, msg, run_path, script_name) 350 351 def test_basic_script(self): 352 with temp_dir() as script_dir: 353 mod_name = 'script' 354 script_name = self._make_test_script(script_dir, mod_name) 355 self._check_script(script_name, "<run_path>", script_name, 356 script_name, None) 357 358 def test_script_compiled(self): 359 with temp_dir() as script_dir: 360 mod_name = 'script' 361 script_name = self._make_test_script(script_dir, mod_name) 362 compiled_name = compile_script(script_name) 363 os.remove(script_name) 364 self._check_script(compiled_name, "<run_path>", compiled_name, 365 compiled_name, None) 366 367 def test_directory(self): 368 with temp_dir() as script_dir: 369 mod_name = '__main__' 370 script_name = self._make_test_script(script_dir, mod_name) 371 self._check_script(script_dir, "<run_path>", script_name, 372 script_dir, '') 373 374 def test_directory_compiled(self): 375 with temp_dir() as script_dir: 376 mod_name = '__main__' 377 script_name = self._make_test_script(script_dir, mod_name) 378 compiled_name = compile_script(script_name) 379 os.remove(script_name) 380 self._check_script(script_dir, "<run_path>", compiled_name, 381 script_dir, '') 382 383 def test_directory_error(self): 384 with temp_dir() as script_dir: 385 mod_name = 'not_main' 386 script_name = self._make_test_script(script_dir, mod_name) 387 msg = "can't find '__main__' module in %r" % script_dir 388 self._check_import_error(script_dir, msg) 389 390 def test_zipfile(self): 391 with temp_dir() as script_dir: 392 mod_name = '__main__' 393 script_name = self._make_test_script(script_dir, mod_name) 394 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 395 self._check_script(zip_name, "<run_path>", fname, zip_name, '') 396 397 def test_zipfile_compiled(self): 398 with temp_dir() as script_dir: 399 mod_name = '__main__' 400 script_name = self._make_test_script(script_dir, mod_name) 401 compiled_name = compile_script(script_name) 402 zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name) 403 self._check_script(zip_name, "<run_path>", fname, zip_name, '') 404 405 def test_zipfile_error(self): 406 with temp_dir() as script_dir: 407 mod_name = 'not_main' 408 script_name = self._make_test_script(script_dir, mod_name) 409 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 410 msg = "can't find '__main__' module in %r" % zip_name 411 self._check_import_error(zip_name, msg) 412 413 def test_main_recursion_error(self): 414 with temp_dir() as script_dir, temp_dir() as dummy_dir: 415 mod_name = '__main__' 416 source = ("import runpy\n" 417 "runpy.run_path(%r)\n") % dummy_dir 418 script_name = self._make_test_script(script_dir, mod_name, source) 419 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) 420 msg = "recursion depth exceeded" 421 self.assertRaisesRegexp(RuntimeError, msg, run_path, zip_name) 422 423 424 425def test_main(): 426 run_unittest(RunModuleCodeTest, RunModuleTest, RunPathTest) 427 428if __name__ == "__main__": 429 test_main() 430