blob: 8b443f6b856d9a62db24fba94531b7ddf62a88e9 [file] [log] [blame]
Thomas Woutersa9773292006-04-21 09:43:23 +00001# Test the runpy module
2import unittest
3import os
4import os.path
5import sys
Nick Coghlan16eb0fb2009-11-18 11:35:25 +00006import re
Thomas Woutersa9773292006-04-21 09:43:23 +00007import tempfile
Brett Cannonfd074152012-04-14 14:10:13 -04008import importlib
Barry Warsaw28a691b2010-04-17 00:19:56 +00009import py_compile
Brett Cannon31f59292011-02-21 19:29:56 +000010from test.support import (
Victor Stinnerbf816222011-06-30 23:25:47 +020011 forget, make_legacy_pyc, run_unittest, unload, verbose, no_tracing,
12 create_empty_file)
Barry Warsaw28a691b2010-04-17 00:19:56 +000013from test.script_helper import (
14 make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000015
Nick Coghlan8ecf5042012-07-15 21:19:18 +100016
Nick Coghlan761bb112012-07-14 23:59:22 +100017import runpy
Nick Coghlan260bd3e2009-11-16 06:49:25 +000018from runpy import _run_code, _run_module_code, run_module, run_path
Christian Heimescbf3b5c2007-12-03 21:02:03 +000019# Note: This module can't safely test _run_module_as_main as it
20# runs its tests in the current process, which would mess with the
21# real __main__ module (usually test.regrtest)
22# See test_cmd_line_script for a test that executes that code path
Thomas Woutersa9773292006-04-21 09:43:23 +000023
Thomas Woutersa9773292006-04-21 09:43:23 +000024
Nick Coghlan761bb112012-07-14 23:59:22 +100025# Set up the test code and expected results
26example_source = """\
27# Check basic code execution
28result = ['Top level assignment']
29def f():
30 result.append('Lower level reference')
31f()
32del f
33# Check the sys module
34import sys
35run_argv0 = sys.argv[0]
36run_name_in_sys_modules = __name__ in sys.modules
37module_in_sys_modules = (run_name_in_sys_modules and
38 globals() is sys.modules[__name__].__dict__)
39# Check nested operation
40import runpy
41nested = runpy._run_module_code('x=1\\n', mod_name='<run>')
42"""
43
44implicit_namespace = {
45 "__name__": None,
46 "__file__": None,
47 "__cached__": None,
48 "__package__": None,
49 "__doc__": None,
50}
51example_namespace = {
52 "sys": sys,
53 "runpy": runpy,
54 "result": ["Top level assignment", "Lower level reference"],
55 "run_argv0": sys.argv[0],
56 "run_name_in_sys_modules": False,
57 "module_in_sys_modules": False,
58 "nested": dict(implicit_namespace,
59 x=1, __name__="<run>", __loader__=None),
60}
61example_namespace.update(implicit_namespace)
62
63class CodeExecutionMixin:
64 # Issue #15230 (run_path not handling run_name correctly) highlighted a
65 # problem with the way arguments were being passed from higher level APIs
66 # down to lower level code. This mixin makes it easier to ensure full
67 # testing occurs at those upper layers as well, not just at the utility
68 # layer
69
70 def assertNamespaceMatches(self, result_ns, expected_ns):
71 """Check two namespaces match.
72
73 Ignores any unspecified interpreter created names
74 """
75 # Impls are permitted to add extra names, so filter them out
76 for k in list(result_ns):
77 if k.startswith("__") and k.endswith("__"):
78 if k not in expected_ns:
79 result_ns.pop(k)
80 if k not in expected_ns["nested"]:
81 result_ns["nested"].pop(k)
82 # Don't use direct dict comparison - the diffs are too hard to debug
83 self.assertEqual(set(result_ns), set(expected_ns))
84 for k in result_ns:
85 actual = (k, result_ns[k])
86 expected = (k, expected_ns[k])
87 self.assertEqual(actual, expected)
88
89 def check_code_execution(self, create_namespace, expected_namespace):
90 """Check that an interface runs the example code correctly
91
92 First argument is a callable accepting the initial globals and
93 using them to create the actual namespace
94 Second argument is the expected result
95 """
96 sentinel = object()
97 expected_ns = expected_namespace.copy()
98 run_name = expected_ns["__name__"]
99 saved_argv0 = sys.argv[0]
100 saved_mod = sys.modules.get(run_name, sentinel)
101 # Check without initial globals
102 result_ns = create_namespace(None)
103 self.assertNamespaceMatches(result_ns, expected_ns)
104 self.assertIs(sys.argv[0], saved_argv0)
105 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod)
106 # And then with initial globals
107 initial_ns = {"sentinel": sentinel}
108 expected_ns["sentinel"] = sentinel
109 result_ns = create_namespace(initial_ns)
110 self.assertIsNot(result_ns, initial_ns)
111 self.assertNamespaceMatches(result_ns, expected_ns)
112 self.assertIs(sys.argv[0], saved_argv0)
113 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod)
114
115
116class ExecutionLayerTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000117 """Unit tests for runpy._run_code and runpy._run_module_code"""
Thomas Woutersa9773292006-04-21 09:43:23 +0000118
Thomas Woutersed03b412007-08-28 21:37:11 +0000119 def test_run_code(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000120 expected_ns = example_namespace.copy()
121 expected_ns.update({
122 "__loader__": None,
123 })
124 def create_ns(init_globals):
125 return _run_code(example_source, {}, init_globals)
126 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersa9773292006-04-21 09:43:23 +0000127
128 def test_run_module_code(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000129 mod_name = "<Nonsense>"
130 mod_fname = "Some other nonsense"
131 mod_loader = "Now you're just being silly"
132 mod_package = '' # Treat as a top level module
133 expected_ns = example_namespace.copy()
134 expected_ns.update({
135 "__name__": mod_name,
136 "__file__": mod_fname,
137 "__loader__": mod_loader,
138 "__package__": mod_package,
139 "run_argv0": mod_fname,
140 "run_name_in_sys_modules": True,
141 "module_in_sys_modules": True,
142 })
143 def create_ns(init_globals):
144 return _run_module_code(example_source,
145 init_globals,
146 mod_name,
147 mod_fname,
148 mod_loader,
149 mod_package)
150 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersed03b412007-08-28 21:37:11 +0000151
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000152# TODO: Use self.addCleanup to get rid of a lot of try-finally blocks
Nick Coghlan761bb112012-07-14 23:59:22 +1000153class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000154 """Unit tests for runpy.run_module"""
Thomas Woutersa9773292006-04-21 09:43:23 +0000155
156 def expect_import_error(self, mod_name):
157 try:
158 run_module(mod_name)
159 except ImportError:
160 pass
161 else:
162 self.fail("Expected import error for " + mod_name)
163
164 def test_invalid_names(self):
Guido van Rossum806c2462007-08-06 23:33:07 +0000165 # Builtin module
Thomas Woutersa9773292006-04-21 09:43:23 +0000166 self.expect_import_error("sys")
Guido van Rossum806c2462007-08-06 23:33:07 +0000167 # Non-existent modules
Thomas Woutersa9773292006-04-21 09:43:23 +0000168 self.expect_import_error("sys.imp.eric")
169 self.expect_import_error("os.path.half")
170 self.expect_import_error("a.bee")
171 self.expect_import_error(".howard")
172 self.expect_import_error("..eaten")
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000173 # Package without __main__.py
174 self.expect_import_error("multiprocessing")
Thomas Woutersa9773292006-04-21 09:43:23 +0000175
176 def test_library_module(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000177 self.assertEqual(run_module("runpy")["__name__"], "runpy")
Thomas Woutersa9773292006-04-21 09:43:23 +0000178
Guido van Rossum806c2462007-08-06 23:33:07 +0000179 def _add_pkg_dir(self, pkg_dir):
180 os.mkdir(pkg_dir)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000181 pkg_fname = os.path.join(pkg_dir, "__init__.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200182 create_empty_file(pkg_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000183 return pkg_fname
184
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000185 def _make_pkg(self, source, depth, mod_base="runpy_test"):
Thomas Woutersa9773292006-04-21 09:43:23 +0000186 pkg_name = "__runpy_pkg__"
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000187 test_fname = mod_base+os.extsep+"py"
Nick Coghlaneb3e62f2012-07-17 20:42:39 +1000188 pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp())
Nick Coghlan761bb112012-07-14 23:59:22 +1000189 if verbose > 1: print(" Package tree in:", sub_dir)
Thomas Woutersa9773292006-04-21 09:43:23 +0000190 sys.path.insert(0, pkg_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000191 if verbose > 1: print(" Updated sys.path:", sys.path[0])
Thomas Woutersa9773292006-04-21 09:43:23 +0000192 for i in range(depth):
193 sub_dir = os.path.join(sub_dir, pkg_name)
Guido van Rossum806c2462007-08-06 23:33:07 +0000194 pkg_fname = self._add_pkg_dir(sub_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000195 if verbose > 1: print(" Next level in:", sub_dir)
196 if verbose > 1: print(" Created:", pkg_fname)
Thomas Woutersa9773292006-04-21 09:43:23 +0000197 mod_fname = os.path.join(sub_dir, test_fname)
198 mod_file = open(mod_fname, "w")
199 mod_file.write(source)
200 mod_file.close()
Nick Coghlan761bb112012-07-14 23:59:22 +1000201 if verbose > 1: print(" Created:", mod_fname)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000202 mod_name = (pkg_name+".")*depth + mod_base
Thomas Woutersa9773292006-04-21 09:43:23 +0000203 return pkg_dir, mod_fname, mod_name
204
205 def _del_pkg(self, top, depth, mod_name):
Guido van Rossum806c2462007-08-06 23:33:07 +0000206 for entry in list(sys.modules):
207 if entry.startswith("__runpy_pkg__"):
Thomas Woutersa9773292006-04-21 09:43:23 +0000208 del sys.modules[entry]
Nick Coghlan761bb112012-07-14 23:59:22 +1000209 if verbose > 1: print(" Removed sys.modules entries")
Thomas Woutersa9773292006-04-21 09:43:23 +0000210 del sys.path[0]
Nick Coghlan761bb112012-07-14 23:59:22 +1000211 if verbose > 1: print(" Removed sys.path entry")
Thomas Woutersa9773292006-04-21 09:43:23 +0000212 for root, dirs, files in os.walk(top, topdown=False):
213 for name in files:
214 try:
215 os.remove(os.path.join(root, name))
Guido van Rossumb940e112007-01-10 16:19:56 +0000216 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000217 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000218 for name in dirs:
219 fullname = os.path.join(root, name)
220 try:
221 os.rmdir(fullname)
Guido van Rossumb940e112007-01-10 16:19:56 +0000222 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000223 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000224 try:
225 os.rmdir(top)
Nick Coghlan761bb112012-07-14 23:59:22 +1000226 if verbose > 1: print(" Removed package tree")
Guido van Rossumb940e112007-01-10 16:19:56 +0000227 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000228 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000229
Nick Coghlan761bb112012-07-14 23:59:22 +1000230 def _fix_ns_for_legacy_pyc(self, ns, alter_sys):
231 char_to_add = "c" if __debug__ else "o"
232 ns["__file__"] += char_to_add
233 if alter_sys:
234 ns["run_argv0"] += char_to_add
235
236
237 def _check_module(self, depth, alter_sys=False):
Thomas Woutersa9773292006-04-21 09:43:23 +0000238 pkg_dir, mod_fname, mod_name = (
Nick Coghlan761bb112012-07-14 23:59:22 +1000239 self._make_pkg(example_source, depth))
Guido van Rossum04110fb2007-08-24 16:32:05 +0000240 forget(mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000241 expected_ns = example_namespace.copy()
242 expected_ns.update({
243 "__name__": mod_name,
244 "__file__": mod_fname,
245 "__package__": mod_name.rpartition(".")[0],
246 })
247 if alter_sys:
248 expected_ns.update({
249 "run_argv0": mod_fname,
250 "run_name_in_sys_modules": True,
251 "module_in_sys_modules": True,
252 })
253 def create_ns(init_globals):
254 return run_module(mod_name, init_globals, alter_sys=alter_sys)
Thomas Woutersa9773292006-04-21 09:43:23 +0000255 try:
Nick Coghlan761bb112012-07-14 23:59:22 +1000256 if verbose > 1: print("Running from source:", mod_name)
257 self.check_code_execution(create_ns, expected_ns)
Brett Cannonfd074152012-04-14 14:10:13 -0400258 importlib.invalidate_caches()
Thomas Woutersa9773292006-04-21 09:43:23 +0000259 __import__(mod_name)
260 os.remove(mod_fname)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000261 make_legacy_pyc(mod_fname)
Brett Cannon61b14252010-07-03 21:48:25 +0000262 unload(mod_name) # In case loader caches paths
Brett Cannonfd074152012-04-14 14:10:13 -0400263 importlib.invalidate_caches()
Nick Coghlan761bb112012-07-14 23:59:22 +1000264 if verbose > 1: print("Running from compiled:", mod_name)
265 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
266 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersa9773292006-04-21 09:43:23 +0000267 finally:
268 self._del_pkg(pkg_dir, depth, mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000269 if verbose > 1: print("Module executed successfully")
Thomas Woutersa9773292006-04-21 09:43:23 +0000270
Nick Coghlan761bb112012-07-14 23:59:22 +1000271 def _check_package(self, depth, alter_sys=False):
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000272 pkg_dir, mod_fname, mod_name = (
Nick Coghlan761bb112012-07-14 23:59:22 +1000273 self._make_pkg(example_source, depth, "__main__"))
274 pkg_name = mod_name.rpartition(".")[0]
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000275 forget(mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000276 expected_ns = example_namespace.copy()
277 expected_ns.update({
278 "__name__": mod_name,
279 "__file__": mod_fname,
280 "__package__": pkg_name,
281 })
282 if alter_sys:
283 expected_ns.update({
284 "run_argv0": mod_fname,
285 "run_name_in_sys_modules": True,
286 "module_in_sys_modules": True,
287 })
288 def create_ns(init_globals):
289 return run_module(pkg_name, init_globals, alter_sys=alter_sys)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000290 try:
Nick Coghlan761bb112012-07-14 23:59:22 +1000291 if verbose > 1: print("Running from source:", pkg_name)
292 self.check_code_execution(create_ns, expected_ns)
Brett Cannonfd074152012-04-14 14:10:13 -0400293 importlib.invalidate_caches()
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000294 __import__(mod_name)
295 os.remove(mod_fname)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000296 make_legacy_pyc(mod_fname)
Brett Cannon61b14252010-07-03 21:48:25 +0000297 unload(mod_name) # In case loader caches paths
Nick Coghlan761bb112012-07-14 23:59:22 +1000298 if verbose > 1: print("Running from compiled:", pkg_name)
Brett Cannonfd074152012-04-14 14:10:13 -0400299 importlib.invalidate_caches()
Nick Coghlan761bb112012-07-14 23:59:22 +1000300 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
301 self.check_code_execution(create_ns, expected_ns)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000302 finally:
303 self._del_pkg(pkg_dir, depth, pkg_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000304 if verbose > 1: print("Package executed successfully")
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000305
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000306 def _add_relative_modules(self, base_dir, source, depth):
Guido van Rossum806c2462007-08-06 23:33:07 +0000307 if depth <= 1:
308 raise ValueError("Relative module test needs depth > 1")
309 pkg_name = "__runpy_pkg__"
310 module_dir = base_dir
311 for i in range(depth):
312 parent_dir = module_dir
313 module_dir = os.path.join(module_dir, pkg_name)
314 # Add sibling module
Skip Montanaro7a98be22007-08-16 14:35:24 +0000315 sibling_fname = os.path.join(module_dir, "sibling.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200316 create_empty_file(sibling_fname)
Nick Coghlan761bb112012-07-14 23:59:22 +1000317 if verbose > 1: print(" Added sibling module:", sibling_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000318 # Add nephew module
319 uncle_dir = os.path.join(parent_dir, "uncle")
320 self._add_pkg_dir(uncle_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000321 if verbose > 1: print(" Added uncle package:", uncle_dir)
Guido van Rossum806c2462007-08-06 23:33:07 +0000322 cousin_dir = os.path.join(uncle_dir, "cousin")
323 self._add_pkg_dir(cousin_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000324 if verbose > 1: print(" Added cousin package:", cousin_dir)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000325 nephew_fname = os.path.join(cousin_dir, "nephew.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200326 create_empty_file(nephew_fname)
Nick Coghlan761bb112012-07-14 23:59:22 +1000327 if verbose > 1: print(" Added nephew module:", nephew_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000328
329 def _check_relative_imports(self, depth, run_name=None):
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000330 contents = r"""\
Guido van Rossum806c2462007-08-06 23:33:07 +0000331from __future__ import absolute_import
332from . import sibling
333from ..uncle.cousin import nephew
334"""
335 pkg_dir, mod_fname, mod_name = (
336 self._make_pkg(contents, depth))
Nick Coghlan761bb112012-07-14 23:59:22 +1000337 if run_name is None:
338 expected_name = mod_name
339 else:
340 expected_name = run_name
Guido van Rossum806c2462007-08-06 23:33:07 +0000341 try:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000342 self._add_relative_modules(pkg_dir, contents, depth)
343 pkg_name = mod_name.rpartition('.')[0]
Nick Coghlan761bb112012-07-14 23:59:22 +1000344 if verbose > 1: print("Running from source:", mod_name)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000345 d1 = run_module(mod_name, run_name=run_name) # Read from source
Nick Coghlan761bb112012-07-14 23:59:22 +1000346 self.assertEqual(d1["__name__"], expected_name)
347 self.assertEqual(d1["__package__"], pkg_name)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000348 self.assertIn("sibling", d1)
349 self.assertIn("nephew", d1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000350 del d1 # Ensure __loader__ entry doesn't keep file open
Brett Cannonfd074152012-04-14 14:10:13 -0400351 importlib.invalidate_caches()
Guido van Rossum806c2462007-08-06 23:33:07 +0000352 __import__(mod_name)
353 os.remove(mod_fname)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000354 make_legacy_pyc(mod_fname)
Brett Cannon61b14252010-07-03 21:48:25 +0000355 unload(mod_name) # In case the loader caches paths
Nick Coghlan761bb112012-07-14 23:59:22 +1000356 if verbose > 1: print("Running from compiled:", mod_name)
Brett Cannonfd074152012-04-14 14:10:13 -0400357 importlib.invalidate_caches()
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000358 d2 = run_module(mod_name, run_name=run_name) # Read from bytecode
Nick Coghlan761bb112012-07-14 23:59:22 +1000359 self.assertEqual(d2["__name__"], expected_name)
360 self.assertEqual(d2["__package__"], pkg_name)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000361 self.assertIn("sibling", d2)
362 self.assertIn("nephew", d2)
Guido van Rossum806c2462007-08-06 23:33:07 +0000363 del d2 # Ensure __loader__ entry doesn't keep file open
364 finally:
365 self._del_pkg(pkg_dir, depth, mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000366 if verbose > 1: print("Module executed successfully")
Guido van Rossum806c2462007-08-06 23:33:07 +0000367
Thomas Woutersa9773292006-04-21 09:43:23 +0000368 def test_run_module(self):
369 for depth in range(4):
Nick Coghlan761bb112012-07-14 23:59:22 +1000370 if verbose > 1: print("Testing package depth:", depth)
Thomas Woutersa9773292006-04-21 09:43:23 +0000371 self._check_module(depth)
372
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000373 def test_run_package(self):
374 for depth in range(1, 4):
Nick Coghlan761bb112012-07-14 23:59:22 +1000375 if verbose > 1: print("Testing package depth:", depth)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000376 self._check_package(depth)
377
Nick Coghlan761bb112012-07-14 23:59:22 +1000378 def test_run_module_alter_sys(self):
379 for depth in range(4):
380 if verbose > 1: print("Testing package depth:", depth)
381 self._check_module(depth, alter_sys=True)
382
383 def test_run_package_alter_sys(self):
384 for depth in range(1, 4):
385 if verbose > 1: print("Testing package depth:", depth)
386 self._check_package(depth, alter_sys=True)
387
Guido van Rossum806c2462007-08-06 23:33:07 +0000388 def test_explicit_relative_import(self):
389 for depth in range(2, 5):
Nick Coghlan761bb112012-07-14 23:59:22 +1000390 if verbose > 1: print("Testing relative imports at depth:", depth)
Guido van Rossum806c2462007-08-06 23:33:07 +0000391 self._check_relative_imports(depth)
392
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000393 def test_main_relative_import(self):
394 for depth in range(2, 5):
Nick Coghlan761bb112012-07-14 23:59:22 +1000395 if verbose > 1: print("Testing main relative imports at depth:", depth)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000396 self._check_relative_imports(depth, "__main__")
397
Nick Coghlan761bb112012-07-14 23:59:22 +1000398 def test_run_name(self):
399 depth = 1
400 run_name = "And now for something completely different"
401 pkg_dir, mod_fname, mod_name = (
402 self._make_pkg(example_source, depth))
403 forget(mod_name)
404 expected_ns = example_namespace.copy()
405 expected_ns.update({
406 "__name__": run_name,
407 "__file__": mod_fname,
408 "__package__": mod_name.rpartition(".")[0],
409 })
410 def create_ns(init_globals):
411 return run_module(mod_name, init_globals, run_name)
412 try:
413 self.check_code_execution(create_ns, expected_ns)
414 finally:
415 self._del_pkg(pkg_dir, depth, mod_name)
Thomas Woutersa9773292006-04-21 09:43:23 +0000416
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000417 def test_pkgutil_walk_packages(self):
418 # This is a dodgy hack to use the test_runpy infrastructure to test
419 # issue #15343. Issue #15348 declares this is indeed a dodgy hack ;)
420 import pkgutil
421 max_depth = 4
422 base_name = "__runpy_pkg__"
423 package_suffixes = ["uncle", "uncle.cousin"]
424 module_suffixes = ["uncle.cousin.nephew", base_name + ".sibling"]
425 expected_packages = set()
426 expected_modules = set()
427 for depth in range(1, max_depth):
428 pkg_name = ".".join([base_name] * depth)
429 expected_packages.add(pkg_name)
430 for name in package_suffixes:
431 expected_packages.add(pkg_name + "." + name)
432 for name in module_suffixes:
433 expected_modules.add(pkg_name + "." + name)
434 pkg_name = ".".join([base_name] * max_depth)
435 expected_packages.add(pkg_name)
436 expected_modules.add(pkg_name + ".runpy_test")
437 pkg_dir, mod_fname, mod_name = (
438 self._make_pkg("", max_depth))
439 self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name)
440 for depth in range(2, max_depth+1):
441 self._add_relative_modules(pkg_dir, "", depth)
442 for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]):
443 self.assertIsInstance(finder,
444 importlib.machinery.FileFinder)
445 if ispkg:
446 expected_packages.remove(mod_name)
447 else:
448 expected_modules.remove(mod_name)
449 self.assertEqual(len(expected_packages), 0, expected_packages)
450 self.assertEqual(len(expected_modules), 0, expected_modules)
Nick Coghlan761bb112012-07-14 23:59:22 +1000451
452class RunPathTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000453 """Unit tests for runpy.run_path"""
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000454
455 def _make_test_script(self, script_dir, script_basename, source=None):
456 if source is None:
Nick Coghlan761bb112012-07-14 23:59:22 +1000457 source = example_source
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000458 return make_script(script_dir, script_basename, source)
459
460 def _check_script(self, script_name, expected_name, expected_file,
Nick Coghlan761bb112012-07-14 23:59:22 +1000461 expected_argv0):
462 # First check is without run_name
463 def create_ns(init_globals):
464 return run_path(script_name, init_globals)
465 expected_ns = example_namespace.copy()
466 expected_ns.update({
467 "__name__": expected_name,
468 "__file__": expected_file,
469 "__package__": "",
470 "run_argv0": expected_argv0,
471 "run_name_in_sys_modules": True,
472 "module_in_sys_modules": True,
473 })
474 self.check_code_execution(create_ns, expected_ns)
475 # Second check makes sure run_name works in all cases
476 run_name = "prove.issue15230.is.fixed"
477 def create_ns(init_globals):
478 return run_path(script_name, init_globals, run_name)
479 expected_ns["__name__"] = run_name
480 expected_ns["__package__"] = run_name.rpartition(".")[0]
481 self.check_code_execution(create_ns, expected_ns)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000482
483 def _check_import_error(self, script_name, msg):
Nick Coghlan16eb0fb2009-11-18 11:35:25 +0000484 msg = re.escape(msg)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000485 self.assertRaisesRegex(ImportError, msg, run_path, script_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000486
487 def test_basic_script(self):
488 with temp_dir() as script_dir:
489 mod_name = 'script'
490 script_name = self._make_test_script(script_dir, mod_name)
491 self._check_script(script_name, "<run_path>", script_name,
Nick Coghlan761bb112012-07-14 23:59:22 +1000492 script_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000493
494 def test_script_compiled(self):
495 with temp_dir() as script_dir:
496 mod_name = 'script'
497 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000498 compiled_name = py_compile.compile(script_name, doraise=True)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000499 os.remove(script_name)
500 self._check_script(compiled_name, "<run_path>", compiled_name,
Nick Coghlan761bb112012-07-14 23:59:22 +1000501 compiled_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000502
503 def test_directory(self):
504 with temp_dir() as script_dir:
505 mod_name = '__main__'
506 script_name = self._make_test_script(script_dir, mod_name)
507 self._check_script(script_dir, "<run_path>", script_name,
Nick Coghlan761bb112012-07-14 23:59:22 +1000508 script_dir)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000509
510 def test_directory_compiled(self):
511 with temp_dir() as script_dir:
512 mod_name = '__main__'
513 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000514 compiled_name = py_compile.compile(script_name, doraise=True)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000515 os.remove(script_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000516 legacy_pyc = make_legacy_pyc(script_name)
517 self._check_script(script_dir, "<run_path>", legacy_pyc,
Nick Coghlan761bb112012-07-14 23:59:22 +1000518 script_dir)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000519
520 def test_directory_error(self):
521 with temp_dir() as script_dir:
522 mod_name = 'not_main'
523 script_name = self._make_test_script(script_dir, mod_name)
524 msg = "can't find '__main__' module in %r" % script_dir
525 self._check_import_error(script_dir, msg)
526
527 def test_zipfile(self):
528 with temp_dir() as script_dir:
529 mod_name = '__main__'
530 script_name = self._make_test_script(script_dir, mod_name)
531 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000532 self._check_script(zip_name, "<run_path>", fname, zip_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000533
534 def test_zipfile_compiled(self):
535 with temp_dir() as script_dir:
536 mod_name = '__main__'
537 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000538 compiled_name = py_compile.compile(script_name, doraise=True)
539 zip_name, fname = make_zip_script(script_dir, 'test_zip',
540 compiled_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000541 self._check_script(zip_name, "<run_path>", fname, zip_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000542
543 def test_zipfile_error(self):
544 with temp_dir() as script_dir:
545 mod_name = 'not_main'
546 script_name = self._make_test_script(script_dir, mod_name)
547 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
548 msg = "can't find '__main__' module in %r" % zip_name
549 self._check_import_error(zip_name, msg)
550
Brett Cannon31f59292011-02-21 19:29:56 +0000551 @no_tracing
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000552 def test_main_recursion_error(self):
553 with temp_dir() as script_dir, temp_dir() as dummy_dir:
554 mod_name = '__main__'
555 source = ("import runpy\n"
556 "runpy.run_path(%r)\n") % dummy_dir
557 script_name = self._make_test_script(script_dir, mod_name, source)
558 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
559 msg = "recursion depth exceeded"
Ezio Melottied3a7d22010-12-01 02:32:32 +0000560 self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000561
Victor Stinner6c471022011-07-04 01:45:39 +0200562 def test_encoding(self):
563 with temp_dir() as script_dir:
564 filename = os.path.join(script_dir, 'script.py')
565 with open(filename, 'w', encoding='latin1') as f:
566 f.write("""
567#coding:latin1
568"non-ASCII: h\xe9"
569""")
570 result = run_path(filename)
571 self.assertEqual(result['__doc__'], "non-ASCII: h\xe9")
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000572
573
Thomas Woutersa9773292006-04-21 09:43:23 +0000574def test_main():
Brett Cannon61b14252010-07-03 21:48:25 +0000575 run_unittest(
Nick Coghlan761bb112012-07-14 23:59:22 +1000576 ExecutionLayerTestCase,
577 RunModuleTestCase,
578 RunPathTestCase
Brett Cannon61b14252010-07-03 21:48:25 +0000579 )
Thomas Woutersa9773292006-04-21 09:43:23 +0000580
581if __name__ == "__main__":
582 test_main()