blob: f00308611163972598f27fd09535cdfef76d02de [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
Nick Coghlan720c7e22013-12-15 20:33:02 +10008import importlib, importlib.machinery, importlib.util
Barry Warsaw28a691b2010-04-17 00:19:56 +00009import py_compile
Martin Panter9c8aa9b2016-08-21 04:07:58 +000010import warnings
Brett Cannon31f59292011-02-21 19:29:56 +000011from test.support import (
Zachary Ware38c707e2015-04-13 15:00:43 -050012 forget, make_legacy_pyc, unload, verbose, no_tracing,
Berker Peksagce643912015-05-06 06:33:17 +030013 create_empty_file, temp_dir)
Victor Stinner466e18e2019-07-01 19:01:52 +020014from test.support.script_helper import make_script, make_zip_script
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,
Nick Coghlan720c7e22013-12-15 20:33:02 +100050 "__spec__": None
Nick Coghlan761bb112012-07-14 23:59:22 +100051}
52example_namespace = {
53 "sys": sys,
54 "runpy": runpy,
55 "result": ["Top level assignment", "Lower level reference"],
56 "run_argv0": sys.argv[0],
57 "run_name_in_sys_modules": False,
58 "module_in_sys_modules": False,
59 "nested": dict(implicit_namespace,
Nick Coghlan720c7e22013-12-15 20:33:02 +100060 x=1, __name__="<run>", __loader__=None),
Nick Coghlan761bb112012-07-14 23:59:22 +100061}
62example_namespace.update(implicit_namespace)
63
64class CodeExecutionMixin:
65 # Issue #15230 (run_path not handling run_name correctly) highlighted a
66 # problem with the way arguments were being passed from higher level APIs
67 # down to lower level code. This mixin makes it easier to ensure full
68 # testing occurs at those upper layers as well, not just at the utility
69 # layer
70
Nick Coghlan720c7e22013-12-15 20:33:02 +100071 # Figuring out the loader details in advance is hard to do, so we skip
72 # checking the full details of loader and loader_state
73 CHECKED_SPEC_ATTRIBUTES = ["name", "parent", "origin", "cached",
74 "has_location", "submodule_search_locations"]
75
Nick Coghlan761bb112012-07-14 23:59:22 +100076 def assertNamespaceMatches(self, result_ns, expected_ns):
77 """Check two namespaces match.
78
79 Ignores any unspecified interpreter created names
80 """
Nick Coghlan720c7e22013-12-15 20:33:02 +100081 # Avoid side effects
82 result_ns = result_ns.copy()
83 expected_ns = expected_ns.copy()
Nick Coghlan761bb112012-07-14 23:59:22 +100084 # Impls are permitted to add extra names, so filter them out
85 for k in list(result_ns):
86 if k.startswith("__") and k.endswith("__"):
87 if k not in expected_ns:
88 result_ns.pop(k)
89 if k not in expected_ns["nested"]:
90 result_ns["nested"].pop(k)
Nick Coghlan720c7e22013-12-15 20:33:02 +100091 # Spec equality includes the loader, so we take the spec out of the
92 # result namespace and check that separately
93 result_spec = result_ns.pop("__spec__")
94 expected_spec = expected_ns.pop("__spec__")
95 if expected_spec is None:
96 self.assertIsNone(result_spec)
97 else:
98 # If an expected loader is set, we just check we got the right
99 # type, rather than checking for full equality
100 if expected_spec.loader is not None:
101 self.assertEqual(type(result_spec.loader),
102 type(expected_spec.loader))
103 for attr in self.CHECKED_SPEC_ATTRIBUTES:
104 k = "__spec__." + attr
105 actual = (k, getattr(result_spec, attr))
106 expected = (k, getattr(expected_spec, attr))
107 self.assertEqual(actual, expected)
108 # For the rest, we still don't use direct dict comparison on the
109 # namespace, as the diffs are too hard to debug if anything breaks
Nick Coghlan761bb112012-07-14 23:59:22 +1000110 self.assertEqual(set(result_ns), set(expected_ns))
111 for k in result_ns:
112 actual = (k, result_ns[k])
113 expected = (k, expected_ns[k])
114 self.assertEqual(actual, expected)
115
116 def check_code_execution(self, create_namespace, expected_namespace):
117 """Check that an interface runs the example code correctly
118
119 First argument is a callable accepting the initial globals and
120 using them to create the actual namespace
121 Second argument is the expected result
122 """
123 sentinel = object()
124 expected_ns = expected_namespace.copy()
125 run_name = expected_ns["__name__"]
126 saved_argv0 = sys.argv[0]
127 saved_mod = sys.modules.get(run_name, sentinel)
128 # Check without initial globals
129 result_ns = create_namespace(None)
130 self.assertNamespaceMatches(result_ns, expected_ns)
131 self.assertIs(sys.argv[0], saved_argv0)
132 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod)
133 # And then with initial globals
134 initial_ns = {"sentinel": sentinel}
135 expected_ns["sentinel"] = sentinel
136 result_ns = create_namespace(initial_ns)
137 self.assertIsNot(result_ns, initial_ns)
138 self.assertNamespaceMatches(result_ns, expected_ns)
139 self.assertIs(sys.argv[0], saved_argv0)
140 self.assertIs(sys.modules.get(run_name, sentinel), saved_mod)
141
142
143class ExecutionLayerTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000144 """Unit tests for runpy._run_code and runpy._run_module_code"""
Thomas Woutersa9773292006-04-21 09:43:23 +0000145
Thomas Woutersed03b412007-08-28 21:37:11 +0000146 def test_run_code(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000147 expected_ns = example_namespace.copy()
148 expected_ns.update({
149 "__loader__": None,
150 })
151 def create_ns(init_globals):
152 return _run_code(example_source, {}, init_globals)
153 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersa9773292006-04-21 09:43:23 +0000154
155 def test_run_module_code(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000156 mod_name = "<Nonsense>"
157 mod_fname = "Some other nonsense"
158 mod_loader = "Now you're just being silly"
159 mod_package = '' # Treat as a top level module
Nick Coghlan720c7e22013-12-15 20:33:02 +1000160 mod_spec = importlib.machinery.ModuleSpec(mod_name,
161 origin=mod_fname,
162 loader=mod_loader)
Nick Coghlan761bb112012-07-14 23:59:22 +1000163 expected_ns = example_namespace.copy()
164 expected_ns.update({
165 "__name__": mod_name,
166 "__file__": mod_fname,
167 "__loader__": mod_loader,
168 "__package__": mod_package,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000169 "__spec__": mod_spec,
Nick Coghlan761bb112012-07-14 23:59:22 +1000170 "run_argv0": mod_fname,
171 "run_name_in_sys_modules": True,
172 "module_in_sys_modules": True,
173 })
174 def create_ns(init_globals):
175 return _run_module_code(example_source,
176 init_globals,
177 mod_name,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000178 mod_spec)
Nick Coghlan761bb112012-07-14 23:59:22 +1000179 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersed03b412007-08-28 21:37:11 +0000180
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000181# TODO: Use self.addCleanup to get rid of a lot of try-finally blocks
Nick Coghlan761bb112012-07-14 23:59:22 +1000182class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000183 """Unit tests for runpy.run_module"""
Thomas Woutersa9773292006-04-21 09:43:23 +0000184
185 def expect_import_error(self, mod_name):
186 try:
187 run_module(mod_name)
188 except ImportError:
189 pass
190 else:
191 self.fail("Expected import error for " + mod_name)
192
193 def test_invalid_names(self):
Guido van Rossum806c2462007-08-06 23:33:07 +0000194 # Builtin module
Thomas Woutersa9773292006-04-21 09:43:23 +0000195 self.expect_import_error("sys")
Guido van Rossum806c2462007-08-06 23:33:07 +0000196 # Non-existent modules
Thomas Woutersa9773292006-04-21 09:43:23 +0000197 self.expect_import_error("sys.imp.eric")
198 self.expect_import_error("os.path.half")
199 self.expect_import_error("a.bee")
Martin Panter7dda4212015-12-10 06:47:06 +0000200 # Relative names not allowed
Thomas Woutersa9773292006-04-21 09:43:23 +0000201 self.expect_import_error(".howard")
202 self.expect_import_error("..eaten")
Martin Panter7dda4212015-12-10 06:47:06 +0000203 self.expect_import_error(".test_runpy")
204 self.expect_import_error(".unittest")
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000205 # Package without __main__.py
206 self.expect_import_error("multiprocessing")
Thomas Woutersa9773292006-04-21 09:43:23 +0000207
208 def test_library_module(self):
Nick Coghlan761bb112012-07-14 23:59:22 +1000209 self.assertEqual(run_module("runpy")["__name__"], "runpy")
Thomas Woutersa9773292006-04-21 09:43:23 +0000210
Nick Coghlan720c7e22013-12-15 20:33:02 +1000211 def _add_pkg_dir(self, pkg_dir, namespace=False):
Guido van Rossum806c2462007-08-06 23:33:07 +0000212 os.mkdir(pkg_dir)
Nick Coghlan720c7e22013-12-15 20:33:02 +1000213 if namespace:
214 return None
Skip Montanaro7a98be22007-08-16 14:35:24 +0000215 pkg_fname = os.path.join(pkg_dir, "__init__.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200216 create_empty_file(pkg_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000217 return pkg_fname
218
Nick Coghlan720c7e22013-12-15 20:33:02 +1000219 def _make_pkg(self, source, depth, mod_base="runpy_test",
220 *, namespace=False, parent_namespaces=False):
221 # Enforce a couple of internal sanity checks on test cases
222 if (namespace or parent_namespaces) and not depth:
223 raise RuntimeError("Can't mark top level module as a "
224 "namespace package")
Thomas Woutersa9773292006-04-21 09:43:23 +0000225 pkg_name = "__runpy_pkg__"
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000226 test_fname = mod_base+os.extsep+"py"
Nick Coghlaneb3e62f2012-07-17 20:42:39 +1000227 pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp())
Nick Coghlan761bb112012-07-14 23:59:22 +1000228 if verbose > 1: print(" Package tree in:", sub_dir)
Thomas Woutersa9773292006-04-21 09:43:23 +0000229 sys.path.insert(0, pkg_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000230 if verbose > 1: print(" Updated sys.path:", sys.path[0])
Nick Coghlan720c7e22013-12-15 20:33:02 +1000231 if depth:
232 namespace_flags = [parent_namespaces] * depth
233 namespace_flags[-1] = namespace
234 for namespace_flag in namespace_flags:
235 sub_dir = os.path.join(sub_dir, pkg_name)
236 pkg_fname = self._add_pkg_dir(sub_dir, namespace_flag)
237 if verbose > 1: print(" Next level in:", sub_dir)
238 if verbose > 1: print(" Created:", pkg_fname)
Thomas Woutersa9773292006-04-21 09:43:23 +0000239 mod_fname = os.path.join(sub_dir, test_fname)
Serhiy Storchaka5b10b982019-03-05 10:06:26 +0200240 with open(mod_fname, "w") as mod_file:
241 mod_file.write(source)
Nick Coghlan761bb112012-07-14 23:59:22 +1000242 if verbose > 1: print(" Created:", mod_fname)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000243 mod_name = (pkg_name+".")*depth + mod_base
Nick Coghlan720c7e22013-12-15 20:33:02 +1000244 mod_spec = importlib.util.spec_from_file_location(mod_name,
245 mod_fname)
246 return pkg_dir, mod_fname, mod_name, mod_spec
Thomas Woutersa9773292006-04-21 09:43:23 +0000247
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000248 def _del_pkg(self, top):
Guido van Rossum806c2462007-08-06 23:33:07 +0000249 for entry in list(sys.modules):
250 if entry.startswith("__runpy_pkg__"):
Thomas Woutersa9773292006-04-21 09:43:23 +0000251 del sys.modules[entry]
Nick Coghlan761bb112012-07-14 23:59:22 +1000252 if verbose > 1: print(" Removed sys.modules entries")
Thomas Woutersa9773292006-04-21 09:43:23 +0000253 del sys.path[0]
Nick Coghlan761bb112012-07-14 23:59:22 +1000254 if verbose > 1: print(" Removed sys.path entry")
Thomas Woutersa9773292006-04-21 09:43:23 +0000255 for root, dirs, files in os.walk(top, topdown=False):
256 for name in files:
257 try:
258 os.remove(os.path.join(root, name))
Guido van Rossumb940e112007-01-10 16:19:56 +0000259 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000260 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000261 for name in dirs:
262 fullname = os.path.join(root, name)
263 try:
264 os.rmdir(fullname)
Guido van Rossumb940e112007-01-10 16:19:56 +0000265 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000266 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000267 try:
268 os.rmdir(top)
Nick Coghlan761bb112012-07-14 23:59:22 +1000269 if verbose > 1: print(" Removed package tree")
Guido van Rossumb940e112007-01-10 16:19:56 +0000270 except OSError as ex:
Nick Coghlan761bb112012-07-14 23:59:22 +1000271 if verbose > 1: print(ex) # Persist with cleaning up
Thomas Woutersa9773292006-04-21 09:43:23 +0000272
Nick Coghlan761bb112012-07-14 23:59:22 +1000273 def _fix_ns_for_legacy_pyc(self, ns, alter_sys):
Brett Cannonf299abd2015-04-13 14:21:02 -0400274 char_to_add = "c"
Nick Coghlan761bb112012-07-14 23:59:22 +1000275 ns["__file__"] += char_to_add
Nick Coghlan720c7e22013-12-15 20:33:02 +1000276 ns["__cached__"] = ns["__file__"]
277 spec = ns["__spec__"]
278 new_spec = importlib.util.spec_from_file_location(spec.name,
279 ns["__file__"])
280 ns["__spec__"] = new_spec
Nick Coghlan761bb112012-07-14 23:59:22 +1000281 if alter_sys:
282 ns["run_argv0"] += char_to_add
283
284
Nick Coghlan720c7e22013-12-15 20:33:02 +1000285 def _check_module(self, depth, alter_sys=False,
286 *, namespace=False, parent_namespaces=False):
287 pkg_dir, mod_fname, mod_name, mod_spec = (
288 self._make_pkg(example_source, depth,
289 namespace=namespace,
290 parent_namespaces=parent_namespaces))
Guido van Rossum04110fb2007-08-24 16:32:05 +0000291 forget(mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000292 expected_ns = example_namespace.copy()
293 expected_ns.update({
294 "__name__": mod_name,
295 "__file__": mod_fname,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000296 "__cached__": mod_spec.cached,
Nick Coghlan761bb112012-07-14 23:59:22 +1000297 "__package__": mod_name.rpartition(".")[0],
Nick Coghlan720c7e22013-12-15 20:33:02 +1000298 "__spec__": mod_spec,
Nick Coghlan761bb112012-07-14 23:59:22 +1000299 })
300 if alter_sys:
301 expected_ns.update({
302 "run_argv0": mod_fname,
303 "run_name_in_sys_modules": True,
304 "module_in_sys_modules": True,
305 })
306 def create_ns(init_globals):
307 return run_module(mod_name, init_globals, alter_sys=alter_sys)
Thomas Woutersa9773292006-04-21 09:43:23 +0000308 try:
Nick Coghlan761bb112012-07-14 23:59:22 +1000309 if verbose > 1: print("Running from source:", mod_name)
310 self.check_code_execution(create_ns, expected_ns)
Brett Cannonfd074152012-04-14 14:10:13 -0400311 importlib.invalidate_caches()
Thomas Woutersa9773292006-04-21 09:43:23 +0000312 __import__(mod_name)
313 os.remove(mod_fname)
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200314 if not sys.dont_write_bytecode:
315 make_legacy_pyc(mod_fname)
316 unload(mod_name) # In case loader caches paths
Ezio Melottie5e7a7c2013-03-16 21:49:20 +0200317 importlib.invalidate_caches()
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200318 if verbose > 1: print("Running from compiled:", mod_name)
319 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
320 self.check_code_execution(create_ns, expected_ns)
Thomas Woutersa9773292006-04-21 09:43:23 +0000321 finally:
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000322 self._del_pkg(pkg_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000323 if verbose > 1: print("Module executed successfully")
Thomas Woutersa9773292006-04-21 09:43:23 +0000324
Nick Coghlan720c7e22013-12-15 20:33:02 +1000325 def _check_package(self, depth, alter_sys=False,
326 *, namespace=False, parent_namespaces=False):
327 pkg_dir, mod_fname, mod_name, mod_spec = (
328 self._make_pkg(example_source, depth, "__main__",
329 namespace=namespace,
330 parent_namespaces=parent_namespaces))
Nick Coghlan761bb112012-07-14 23:59:22 +1000331 pkg_name = mod_name.rpartition(".")[0]
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000332 forget(mod_name)
Nick Coghlan761bb112012-07-14 23:59:22 +1000333 expected_ns = example_namespace.copy()
334 expected_ns.update({
335 "__name__": mod_name,
336 "__file__": mod_fname,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000337 "__cached__": importlib.util.cache_from_source(mod_fname),
Nick Coghlan761bb112012-07-14 23:59:22 +1000338 "__package__": pkg_name,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000339 "__spec__": mod_spec,
Nick Coghlan761bb112012-07-14 23:59:22 +1000340 })
341 if alter_sys:
342 expected_ns.update({
343 "run_argv0": mod_fname,
344 "run_name_in_sys_modules": True,
345 "module_in_sys_modules": True,
346 })
347 def create_ns(init_globals):
348 return run_module(pkg_name, init_globals, alter_sys=alter_sys)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000349 try:
Nick Coghlan761bb112012-07-14 23:59:22 +1000350 if verbose > 1: print("Running from source:", pkg_name)
351 self.check_code_execution(create_ns, expected_ns)
Brett Cannonfd074152012-04-14 14:10:13 -0400352 importlib.invalidate_caches()
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000353 __import__(mod_name)
354 os.remove(mod_fname)
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200355 if not sys.dont_write_bytecode:
356 make_legacy_pyc(mod_fname)
357 unload(mod_name) # In case loader caches paths
358 if verbose > 1: print("Running from compiled:", pkg_name)
Ezio Melottie5e7a7c2013-03-16 21:49:20 +0200359 importlib.invalidate_caches()
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200360 self._fix_ns_for_legacy_pyc(expected_ns, alter_sys)
361 self.check_code_execution(create_ns, expected_ns)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000362 finally:
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000363 self._del_pkg(pkg_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000364 if verbose > 1: print("Package executed successfully")
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000365
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000366 def _add_relative_modules(self, base_dir, source, depth):
Guido van Rossum806c2462007-08-06 23:33:07 +0000367 if depth <= 1:
368 raise ValueError("Relative module test needs depth > 1")
369 pkg_name = "__runpy_pkg__"
370 module_dir = base_dir
371 for i in range(depth):
372 parent_dir = module_dir
373 module_dir = os.path.join(module_dir, pkg_name)
374 # Add sibling module
Skip Montanaro7a98be22007-08-16 14:35:24 +0000375 sibling_fname = os.path.join(module_dir, "sibling.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200376 create_empty_file(sibling_fname)
Nick Coghlan761bb112012-07-14 23:59:22 +1000377 if verbose > 1: print(" Added sibling module:", sibling_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000378 # Add nephew module
379 uncle_dir = os.path.join(parent_dir, "uncle")
380 self._add_pkg_dir(uncle_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000381 if verbose > 1: print(" Added uncle package:", uncle_dir)
Guido van Rossum806c2462007-08-06 23:33:07 +0000382 cousin_dir = os.path.join(uncle_dir, "cousin")
383 self._add_pkg_dir(cousin_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000384 if verbose > 1: print(" Added cousin package:", cousin_dir)
Skip Montanaro7a98be22007-08-16 14:35:24 +0000385 nephew_fname = os.path.join(cousin_dir, "nephew.py")
Victor Stinnerbf816222011-06-30 23:25:47 +0200386 create_empty_file(nephew_fname)
Nick Coghlan761bb112012-07-14 23:59:22 +1000387 if verbose > 1: print(" Added nephew module:", nephew_fname)
Guido van Rossum806c2462007-08-06 23:33:07 +0000388
389 def _check_relative_imports(self, depth, run_name=None):
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000390 contents = r"""\
Guido van Rossum806c2462007-08-06 23:33:07 +0000391from __future__ import absolute_import
392from . import sibling
393from ..uncle.cousin import nephew
394"""
Nick Coghlan720c7e22013-12-15 20:33:02 +1000395 pkg_dir, mod_fname, mod_name, mod_spec = (
Guido van Rossum806c2462007-08-06 23:33:07 +0000396 self._make_pkg(contents, depth))
Nick Coghlan761bb112012-07-14 23:59:22 +1000397 if run_name is None:
398 expected_name = mod_name
399 else:
400 expected_name = run_name
Guido van Rossum806c2462007-08-06 23:33:07 +0000401 try:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000402 self._add_relative_modules(pkg_dir, contents, depth)
403 pkg_name = mod_name.rpartition('.')[0]
Nick Coghlan761bb112012-07-14 23:59:22 +1000404 if verbose > 1: print("Running from source:", mod_name)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000405 d1 = run_module(mod_name, run_name=run_name) # Read from source
Nick Coghlan761bb112012-07-14 23:59:22 +1000406 self.assertEqual(d1["__name__"], expected_name)
407 self.assertEqual(d1["__package__"], pkg_name)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000408 self.assertIn("sibling", d1)
409 self.assertIn("nephew", d1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000410 del d1 # Ensure __loader__ entry doesn't keep file open
Brett Cannonfd074152012-04-14 14:10:13 -0400411 importlib.invalidate_caches()
Guido van Rossum806c2462007-08-06 23:33:07 +0000412 __import__(mod_name)
413 os.remove(mod_fname)
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200414 if not sys.dont_write_bytecode:
415 make_legacy_pyc(mod_fname)
416 unload(mod_name) # In case the loader caches paths
417 if verbose > 1: print("Running from compiled:", mod_name)
Ezio Melottie5e7a7c2013-03-16 21:49:20 +0200418 importlib.invalidate_caches()
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200419 d2 = run_module(mod_name, run_name=run_name) # Read from bytecode
420 self.assertEqual(d2["__name__"], expected_name)
421 self.assertEqual(d2["__package__"], pkg_name)
422 self.assertIn("sibling", d2)
423 self.assertIn("nephew", d2)
424 del d2 # Ensure __loader__ entry doesn't keep file open
Guido van Rossum806c2462007-08-06 23:33:07 +0000425 finally:
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000426 self._del_pkg(pkg_dir)
Nick Coghlan761bb112012-07-14 23:59:22 +1000427 if verbose > 1: print("Module executed successfully")
Guido van Rossum806c2462007-08-06 23:33:07 +0000428
Thomas Woutersa9773292006-04-21 09:43:23 +0000429 def test_run_module(self):
430 for depth in range(4):
Nick Coghlan761bb112012-07-14 23:59:22 +1000431 if verbose > 1: print("Testing package depth:", depth)
Thomas Woutersa9773292006-04-21 09:43:23 +0000432 self._check_module(depth)
433
Nick Coghlan720c7e22013-12-15 20:33:02 +1000434 def test_run_module_in_namespace_package(self):
435 for depth in range(1, 4):
436 if verbose > 1: print("Testing package depth:", depth)
437 self._check_module(depth, namespace=True, parent_namespaces=True)
438
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000439 def test_run_package(self):
440 for depth in range(1, 4):
Nick Coghlan761bb112012-07-14 23:59:22 +1000441 if verbose > 1: print("Testing package depth:", depth)
Benjamin Petersonf6489f92009-11-25 17:46:26 +0000442 self._check_package(depth)
443
Martin Panter657257e2015-12-03 01:23:10 +0000444 def test_run_package_init_exceptions(self):
445 # These were previously wrapped in an ImportError; see Issue 14285
446 result = self._make_pkg("", 1, "__main__")
447 pkg_dir, _, mod_name, _ = result
448 mod_name = mod_name.replace(".__main__", "")
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000449 self.addCleanup(self._del_pkg, pkg_dir)
Martin Panter657257e2015-12-03 01:23:10 +0000450 init = os.path.join(pkg_dir, "__runpy_pkg__", "__init__.py")
451
452 exceptions = (ImportError, AttributeError, TypeError, ValueError)
453 for exception in exceptions:
454 name = exception.__name__
455 with self.subTest(name):
456 source = "raise {0}('{0} in __init__.py.')".format(name)
457 with open(init, "wt", encoding="ascii") as mod_file:
458 mod_file.write(source)
459 try:
460 run_module(mod_name)
461 except exception as err:
462 self.assertNotIn("finding spec", format(err))
463 else:
464 self.fail("Nothing raised; expected {}".format(name))
Martin Panter7dda4212015-12-10 06:47:06 +0000465 try:
466 run_module(mod_name + ".submodule")
467 except exception as err:
468 self.assertNotIn("finding spec", format(err))
469 else:
470 self.fail("Nothing raised; expected {}".format(name))
Martin Panter657257e2015-12-03 01:23:10 +0000471
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000472 def test_submodule_imported_warning(self):
473 pkg_dir, _, mod_name, _ = self._make_pkg("", 1)
474 try:
475 __import__(mod_name)
476 with self.assertWarnsRegex(RuntimeWarning,
477 r"found in sys\.modules"):
478 run_module(mod_name)
479 finally:
480 self._del_pkg(pkg_dir)
481
482 def test_package_imported_no_warning(self):
483 pkg_dir, _, mod_name, _ = self._make_pkg("", 1, "__main__")
484 self.addCleanup(self._del_pkg, pkg_dir)
485 package = mod_name.replace(".__main__", "")
486 # No warning should occur if we only imported the parent package
487 __import__(package)
488 self.assertIn(package, sys.modules)
489 with warnings.catch_warnings():
490 warnings.simplefilter("error", RuntimeWarning)
491 run_module(package)
492 # But the warning should occur if we imported the __main__ submodule
493 __import__(mod_name)
494 with self.assertWarnsRegex(RuntimeWarning, r"found in sys\.modules"):
495 run_module(package)
496
Nick Coghlan720c7e22013-12-15 20:33:02 +1000497 def test_run_package_in_namespace_package(self):
498 for depth in range(1, 4):
499 if verbose > 1: print("Testing package depth:", depth)
500 self._check_package(depth, parent_namespaces=True)
501
502 def test_run_namespace_package(self):
503 for depth in range(1, 4):
504 if verbose > 1: print("Testing package depth:", depth)
505 self._check_package(depth, namespace=True)
506
507 def test_run_namespace_package_in_namespace_package(self):
508 for depth in range(1, 4):
509 if verbose > 1: print("Testing package depth:", depth)
510 self._check_package(depth, namespace=True, parent_namespaces=True)
511
Nick Coghlan761bb112012-07-14 23:59:22 +1000512 def test_run_module_alter_sys(self):
513 for depth in range(4):
514 if verbose > 1: print("Testing package depth:", depth)
515 self._check_module(depth, alter_sys=True)
516
517 def test_run_package_alter_sys(self):
518 for depth in range(1, 4):
519 if verbose > 1: print("Testing package depth:", depth)
520 self._check_package(depth, alter_sys=True)
521
Guido van Rossum806c2462007-08-06 23:33:07 +0000522 def test_explicit_relative_import(self):
523 for depth in range(2, 5):
Nick Coghlan761bb112012-07-14 23:59:22 +1000524 if verbose > 1: print("Testing relative imports at depth:", depth)
Guido van Rossum806c2462007-08-06 23:33:07 +0000525 self._check_relative_imports(depth)
526
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000527 def test_main_relative_import(self):
528 for depth in range(2, 5):
Nick Coghlan761bb112012-07-14 23:59:22 +1000529 if verbose > 1: print("Testing main relative imports at depth:", depth)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000530 self._check_relative_imports(depth, "__main__")
531
Nick Coghlan761bb112012-07-14 23:59:22 +1000532 def test_run_name(self):
533 depth = 1
534 run_name = "And now for something completely different"
Nick Coghlan720c7e22013-12-15 20:33:02 +1000535 pkg_dir, mod_fname, mod_name, mod_spec = (
Nick Coghlan761bb112012-07-14 23:59:22 +1000536 self._make_pkg(example_source, depth))
537 forget(mod_name)
538 expected_ns = example_namespace.copy()
539 expected_ns.update({
540 "__name__": run_name,
541 "__file__": mod_fname,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000542 "__cached__": importlib.util.cache_from_source(mod_fname),
Nick Coghlan761bb112012-07-14 23:59:22 +1000543 "__package__": mod_name.rpartition(".")[0],
Nick Coghlan720c7e22013-12-15 20:33:02 +1000544 "__spec__": mod_spec,
Nick Coghlan761bb112012-07-14 23:59:22 +1000545 })
546 def create_ns(init_globals):
547 return run_module(mod_name, init_globals, run_name)
548 try:
549 self.check_code_execution(create_ns, expected_ns)
550 finally:
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000551 self._del_pkg(pkg_dir)
Thomas Woutersa9773292006-04-21 09:43:23 +0000552
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000553 def test_pkgutil_walk_packages(self):
554 # This is a dodgy hack to use the test_runpy infrastructure to test
555 # issue #15343. Issue #15348 declares this is indeed a dodgy hack ;)
556 import pkgutil
557 max_depth = 4
558 base_name = "__runpy_pkg__"
559 package_suffixes = ["uncle", "uncle.cousin"]
560 module_suffixes = ["uncle.cousin.nephew", base_name + ".sibling"]
561 expected_packages = set()
562 expected_modules = set()
563 for depth in range(1, max_depth):
564 pkg_name = ".".join([base_name] * depth)
565 expected_packages.add(pkg_name)
566 for name in package_suffixes:
567 expected_packages.add(pkg_name + "." + name)
568 for name in module_suffixes:
569 expected_modules.add(pkg_name + "." + name)
570 pkg_name = ".".join([base_name] * max_depth)
571 expected_packages.add(pkg_name)
572 expected_modules.add(pkg_name + ".runpy_test")
Nick Coghlan720c7e22013-12-15 20:33:02 +1000573 pkg_dir, mod_fname, mod_name, mod_spec = (
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000574 self._make_pkg("", max_depth))
Martin Panter9c8aa9b2016-08-21 04:07:58 +0000575 self.addCleanup(self._del_pkg, pkg_dir)
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000576 for depth in range(2, max_depth+1):
577 self._add_relative_modules(pkg_dir, "", depth)
Eric Snowd5f92232016-09-07 18:37:17 -0700578 for moduleinfo in pkgutil.walk_packages([pkg_dir]):
579 self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
580 self.assertIsInstance(moduleinfo.module_finder,
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000581 importlib.machinery.FileFinder)
Eric Snowd5f92232016-09-07 18:37:17 -0700582 if moduleinfo.ispkg:
583 expected_packages.remove(moduleinfo.name)
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000584 else:
Eric Snowd5f92232016-09-07 18:37:17 -0700585 expected_modules.remove(moduleinfo.name)
Nick Coghlan8ecf5042012-07-15 21:19:18 +1000586 self.assertEqual(len(expected_packages), 0, expected_packages)
587 self.assertEqual(len(expected_modules), 0, expected_modules)
Nick Coghlan761bb112012-07-14 23:59:22 +1000588
589class RunPathTestCase(unittest.TestCase, CodeExecutionMixin):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000590 """Unit tests for runpy.run_path"""
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000591
Nick Coghlan720c7e22013-12-15 20:33:02 +1000592 def _make_test_script(self, script_dir, script_basename,
593 source=None, omit_suffix=False):
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000594 if source is None:
Nick Coghlan761bb112012-07-14 23:59:22 +1000595 source = example_source
Nick Coghlan720c7e22013-12-15 20:33:02 +1000596 return make_script(script_dir, script_basename,
597 source, omit_suffix)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000598
599 def _check_script(self, script_name, expected_name, expected_file,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000600 expected_argv0, mod_name=None,
601 expect_spec=True, check_loader=True):
Nick Coghlan761bb112012-07-14 23:59:22 +1000602 # First check is without run_name
603 def create_ns(init_globals):
604 return run_path(script_name, init_globals)
605 expected_ns = example_namespace.copy()
Nick Coghlan720c7e22013-12-15 20:33:02 +1000606 if mod_name is None:
607 spec_name = expected_name
608 else:
609 spec_name = mod_name
610 if expect_spec:
611 mod_spec = importlib.util.spec_from_file_location(spec_name,
612 expected_file)
613 mod_cached = mod_spec.cached
614 if not check_loader:
615 mod_spec.loader = None
616 else:
617 mod_spec = mod_cached = None
618
Nick Coghlan761bb112012-07-14 23:59:22 +1000619 expected_ns.update({
620 "__name__": expected_name,
621 "__file__": expected_file,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000622 "__cached__": mod_cached,
Nick Coghlan761bb112012-07-14 23:59:22 +1000623 "__package__": "",
Nick Coghlan720c7e22013-12-15 20:33:02 +1000624 "__spec__": mod_spec,
Nick Coghlan761bb112012-07-14 23:59:22 +1000625 "run_argv0": expected_argv0,
626 "run_name_in_sys_modules": True,
627 "module_in_sys_modules": True,
628 })
629 self.check_code_execution(create_ns, expected_ns)
630 # Second check makes sure run_name works in all cases
631 run_name = "prove.issue15230.is.fixed"
632 def create_ns(init_globals):
633 return run_path(script_name, init_globals, run_name)
Nick Coghlan720c7e22013-12-15 20:33:02 +1000634 if expect_spec and mod_name is None:
635 mod_spec = importlib.util.spec_from_file_location(run_name,
636 expected_file)
637 if not check_loader:
638 mod_spec.loader = None
639 expected_ns["__spec__"] = mod_spec
Nick Coghlan761bb112012-07-14 23:59:22 +1000640 expected_ns["__name__"] = run_name
641 expected_ns["__package__"] = run_name.rpartition(".")[0]
642 self.check_code_execution(create_ns, expected_ns)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000643
644 def _check_import_error(self, script_name, msg):
Nick Coghlan16eb0fb2009-11-18 11:35:25 +0000645 msg = re.escape(msg)
Ezio Melottied3a7d22010-12-01 02:32:32 +0000646 self.assertRaisesRegex(ImportError, msg, run_path, script_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000647
648 def test_basic_script(self):
649 with temp_dir() as script_dir:
650 mod_name = 'script'
651 script_name = self._make_test_script(script_dir, mod_name)
652 self._check_script(script_name, "<run_path>", script_name,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000653 script_name, expect_spec=False)
654
655 def test_basic_script_no_suffix(self):
656 with temp_dir() as script_dir:
657 mod_name = 'script'
658 script_name = self._make_test_script(script_dir, mod_name,
659 omit_suffix=True)
660 self._check_script(script_name, "<run_path>", script_name,
661 script_name, expect_spec=False)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000662
663 def test_script_compiled(self):
664 with temp_dir() as script_dir:
665 mod_name = 'script'
666 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000667 compiled_name = py_compile.compile(script_name, doraise=True)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000668 os.remove(script_name)
669 self._check_script(compiled_name, "<run_path>", compiled_name,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000670 compiled_name, expect_spec=False)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000671
672 def test_directory(self):
673 with temp_dir() as script_dir:
674 mod_name = '__main__'
675 script_name = self._make_test_script(script_dir, mod_name)
676 self._check_script(script_dir, "<run_path>", script_name,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000677 script_dir, mod_name=mod_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000678
679 def test_directory_compiled(self):
680 with temp_dir() as script_dir:
681 mod_name = '__main__'
682 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000683 compiled_name = py_compile.compile(script_name, doraise=True)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000684 os.remove(script_name)
Ezio Melottic28f6fa2013-03-16 19:48:51 +0200685 if not sys.dont_write_bytecode:
686 legacy_pyc = make_legacy_pyc(script_name)
687 self._check_script(script_dir, "<run_path>", legacy_pyc,
Nick Coghlan720c7e22013-12-15 20:33:02 +1000688 script_dir, mod_name=mod_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000689
690 def test_directory_error(self):
691 with temp_dir() as script_dir:
692 mod_name = 'not_main'
693 script_name = self._make_test_script(script_dir, mod_name)
694 msg = "can't find '__main__' module in %r" % script_dir
695 self._check_import_error(script_dir, msg)
696
697 def test_zipfile(self):
698 with temp_dir() as script_dir:
699 mod_name = '__main__'
700 script_name = self._make_test_script(script_dir, mod_name)
701 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
Nick Coghlan720c7e22013-12-15 20:33:02 +1000702 self._check_script(zip_name, "<run_path>", fname, zip_name,
703 mod_name=mod_name, check_loader=False)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000704
705 def test_zipfile_compiled(self):
706 with temp_dir() as script_dir:
707 mod_name = '__main__'
708 script_name = self._make_test_script(script_dir, mod_name)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000709 compiled_name = py_compile.compile(script_name, doraise=True)
710 zip_name, fname = make_zip_script(script_dir, 'test_zip',
711 compiled_name)
Nick Coghlan720c7e22013-12-15 20:33:02 +1000712 self._check_script(zip_name, "<run_path>", fname, zip_name,
713 mod_name=mod_name, check_loader=False)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000714
715 def test_zipfile_error(self):
716 with temp_dir() as script_dir:
717 mod_name = 'not_main'
718 script_name = self._make_test_script(script_dir, mod_name)
719 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
720 msg = "can't find '__main__' module in %r" % zip_name
721 self._check_import_error(zip_name, msg)
722
Brett Cannon31f59292011-02-21 19:29:56 +0000723 @no_tracing
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000724 def test_main_recursion_error(self):
725 with temp_dir() as script_dir, temp_dir() as dummy_dir:
726 mod_name = '__main__'
727 source = ("import runpy\n"
728 "runpy.run_path(%r)\n") % dummy_dir
729 script_name = self._make_test_script(script_dir, mod_name, source)
730 zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
731 msg = "recursion depth exceeded"
Yury Selivanovf488fb42015-07-03 01:04:23 -0400732 self.assertRaisesRegex(RecursionError, msg, run_path, zip_name)
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000733
Victor Stinner6c471022011-07-04 01:45:39 +0200734 def test_encoding(self):
735 with temp_dir() as script_dir:
736 filename = os.path.join(script_dir, 'script.py')
737 with open(filename, 'w', encoding='latin1') as f:
738 f.write("""
739#coding:latin1
Benjamin Peterson951a9e32012-10-12 11:44:10 -0400740s = "non-ASCII: h\xe9"
Victor Stinner6c471022011-07-04 01:45:39 +0200741""")
742 result = run_path(filename)
Benjamin Peterson951a9e32012-10-12 11:44:10 -0400743 self.assertEqual(result['s'], "non-ASCII: h\xe9")
Nick Coghlan260bd3e2009-11-16 06:49:25 +0000744
745
Thomas Woutersa9773292006-04-21 09:43:23 +0000746if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400747 unittest.main()