1 | # Test the runpy module
|
---|
2 | import unittest
|
---|
3 | import os
|
---|
4 | import os.path
|
---|
5 | import sys
|
---|
6 | import re
|
---|
7 | import tempfile
|
---|
8 | from test.test_support import verbose, run_unittest, forget
|
---|
9 | from test.script_helper import (temp_dir, make_script, compile_script,
|
---|
10 | make_pkg, make_zip_script, make_zip_pkg)
|
---|
11 |
|
---|
12 |
|
---|
13 | from 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 |
|
---|
21 | class 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 |
|
---|
83 | class 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"""\
|
---|
233 | from __future__ import absolute_import
|
---|
234 | from . import sibling
|
---|
235 | from ..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_explicit_relative_import(self):
|
---|
274 | for depth in range(2, 5):
|
---|
275 | if verbose: print "Testing relative imports at depth:", depth
|
---|
276 | self._check_relative_imports(depth)
|
---|
277 |
|
---|
278 | def test_main_relative_import(self):
|
---|
279 | for depth in range(2, 5):
|
---|
280 | if verbose: print "Testing main relative imports at depth:", depth
|
---|
281 | self._check_relative_imports(depth, "__main__")
|
---|
282 |
|
---|
283 |
|
---|
284 | class RunPathTest(unittest.TestCase):
|
---|
285 | """Unit tests for runpy.run_path"""
|
---|
286 | # Based on corresponding tests in test_cmd_line_script
|
---|
287 |
|
---|
288 | test_source = """\
|
---|
289 | # Script may be run with optimisation enabled, so don't rely on assert
|
---|
290 | # statements being executed
|
---|
291 | def assertEqual(lhs, rhs):
|
---|
292 | if lhs != rhs:
|
---|
293 | raise AssertionError('%r != %r' % (lhs, rhs))
|
---|
294 | def assertIs(lhs, rhs):
|
---|
295 | if lhs is not rhs:
|
---|
296 | raise AssertionError('%r is not %r' % (lhs, rhs))
|
---|
297 | # Check basic code execution
|
---|
298 | result = ['Top level assignment']
|
---|
299 | def f():
|
---|
300 | result.append('Lower level reference')
|
---|
301 | f()
|
---|
302 | assertEqual(result, ['Top level assignment', 'Lower level reference'])
|
---|
303 | # Check the sys module
|
---|
304 | import sys
|
---|
305 | assertIs(globals(), sys.modules[__name__].__dict__)
|
---|
306 | argv0 = sys.argv[0]
|
---|
307 | """
|
---|
308 |
|
---|
309 | def _make_test_script(self, script_dir, script_basename, source=None):
|
---|
310 | if source is None:
|
---|
311 | source = self.test_source
|
---|
312 | return make_script(script_dir, script_basename, source)
|
---|
313 |
|
---|
314 | def _check_script(self, script_name, expected_name, expected_file,
|
---|
315 | expected_argv0, expected_package):
|
---|
316 | result = run_path(script_name)
|
---|
317 | self.assertEqual(result["__name__"], expected_name)
|
---|
318 | self.assertEqual(result["__file__"], expected_file)
|
---|
319 | self.assertIn("argv0", result)
|
---|
320 | self.assertEqual(result["argv0"], expected_argv0)
|
---|
321 | self.assertEqual(result["__package__"], expected_package)
|
---|
322 |
|
---|
323 | def _check_import_error(self, script_name, msg):
|
---|
324 | msg = re.escape(msg)
|
---|
325 | self.assertRaisesRegexp(ImportError, msg, run_path, script_name)
|
---|
326 |
|
---|
327 | def test_basic_script(self):
|
---|
328 | with temp_dir() as script_dir:
|
---|
329 | mod_name = 'script'
|
---|
330 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
331 | self._check_script(script_name, "<run_path>", script_name,
|
---|
332 | script_name, None)
|
---|
333 |
|
---|
334 | def test_script_compiled(self):
|
---|
335 | with temp_dir() as script_dir:
|
---|
336 | mod_name = 'script'
|
---|
337 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
338 | compiled_name = compile_script(script_name)
|
---|
339 | os.remove(script_name)
|
---|
340 | self._check_script(compiled_name, "<run_path>", compiled_name,
|
---|
341 | compiled_name, None)
|
---|
342 |
|
---|
343 | def test_directory(self):
|
---|
344 | with temp_dir() as script_dir:
|
---|
345 | mod_name = '__main__'
|
---|
346 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
347 | self._check_script(script_dir, "<run_path>", script_name,
|
---|
348 | script_dir, '')
|
---|
349 |
|
---|
350 | def test_directory_compiled(self):
|
---|
351 | with temp_dir() as script_dir:
|
---|
352 | mod_name = '__main__'
|
---|
353 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
354 | compiled_name = compile_script(script_name)
|
---|
355 | os.remove(script_name)
|
---|
356 | self._check_script(script_dir, "<run_path>", compiled_name,
|
---|
357 | script_dir, '')
|
---|
358 |
|
---|
359 | def test_directory_error(self):
|
---|
360 | with temp_dir() as script_dir:
|
---|
361 | mod_name = 'not_main'
|
---|
362 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
363 | msg = "can't find '__main__' module in %r" % script_dir
|
---|
364 | self._check_import_error(script_dir, msg)
|
---|
365 |
|
---|
366 | def test_zipfile(self):
|
---|
367 | with temp_dir() as script_dir:
|
---|
368 | mod_name = '__main__'
|
---|
369 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
370 | zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
|
---|
371 | self._check_script(zip_name, "<run_path>", fname, zip_name, '')
|
---|
372 |
|
---|
373 | def test_zipfile_compiled(self):
|
---|
374 | with temp_dir() as script_dir:
|
---|
375 | mod_name = '__main__'
|
---|
376 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
377 | compiled_name = compile_script(script_name)
|
---|
378 | zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name)
|
---|
379 | self._check_script(zip_name, "<run_path>", fname, zip_name, '')
|
---|
380 |
|
---|
381 | def test_zipfile_error(self):
|
---|
382 | with temp_dir() as script_dir:
|
---|
383 | mod_name = 'not_main'
|
---|
384 | script_name = self._make_test_script(script_dir, mod_name)
|
---|
385 | zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
|
---|
386 | msg = "can't find '__main__' module in %r" % zip_name
|
---|
387 | self._check_import_error(zip_name, msg)
|
---|
388 |
|
---|
389 | def test_main_recursion_error(self):
|
---|
390 | with temp_dir() as script_dir, temp_dir() as dummy_dir:
|
---|
391 | mod_name = '__main__'
|
---|
392 | source = ("import runpy\n"
|
---|
393 | "runpy.run_path(%r)\n") % dummy_dir
|
---|
394 | script_name = self._make_test_script(script_dir, mod_name, source)
|
---|
395 | zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name)
|
---|
396 | msg = "recursion depth exceeded"
|
---|
397 | self.assertRaisesRegexp(RuntimeError, msg, run_path, zip_name)
|
---|
398 |
|
---|
399 |
|
---|
400 |
|
---|
401 | def test_main():
|
---|
402 | run_unittest(RunModuleCodeTest, RunModuleTest, RunPathTest)
|
---|
403 |
|
---|
404 | if __name__ == "__main__":
|
---|
405 | test_main()
|
---|