1# Tests command line execution of scripts 2 3import contextlib 4import unittest 5import os 6import os.path 7import test.test_support 8from test.script_helper import (run_python, 9 temp_dir, make_script, compile_script, 10 assert_python_failure, make_pkg, 11 make_zip_script, make_zip_pkg) 12 13verbose = test.test_support.verbose 14 15 16example_args = ['test1', 'test2', 'test3'] 17 18test_source = """\ 19# Script may be run with optimisation enabled, so don't rely on assert 20# statements being executed 21def assertEqual(lhs, rhs): 22 if lhs != rhs: 23 raise AssertionError('%r != %r' % (lhs, rhs)) 24def assertIdentical(lhs, rhs): 25 if lhs is not rhs: 26 raise AssertionError('%r is not %r' % (lhs, rhs)) 27# Check basic code execution 28result = ['Top level assignment'] 29def f(): 30 result.append('Lower level reference') 31f() 32assertEqual(result, ['Top level assignment', 'Lower level reference']) 33# Check population of magic variables 34assertEqual(__name__, '__main__') 35print '__file__==%r' % __file__ 36print '__package__==%r' % __package__ 37# Check the sys module 38import sys 39assertIdentical(globals(), sys.modules[__name__].__dict__) 40print 'sys.argv[0]==%r' % sys.argv[0] 41""" 42 43def _make_test_script(script_dir, script_basename, source=test_source): 44 return make_script(script_dir, script_basename, source) 45 46def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, 47 source=test_source, depth=1): 48 return make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, 49 source, depth) 50 51# There's no easy way to pass the script directory in to get 52# -m to work (avoiding that is the whole point of making 53# directories and zipfiles executable!) 54# So we fake it for testing purposes with a custom launch script 55launch_source = """\ 56import sys, os.path, runpy 57sys.path.insert(0, %s) 58runpy._run_module_as_main(%r) 59""" 60 61def _make_launch_script(script_dir, script_basename, module_name, path=None): 62 if path is None: 63 path = "os.path.dirname(__file__)" 64 else: 65 path = repr(path) 66 source = launch_source % (path, module_name) 67 return make_script(script_dir, script_basename, source) 68 69class CmdLineTest(unittest.TestCase): 70 def _check_script(self, script_name, expected_file, 71 expected_argv0, expected_package, 72 *cmd_line_switches): 73 run_args = cmd_line_switches + (script_name,) 74 exit_code, data = run_python(*run_args) 75 if verbose: 76 print 'Output from test script %r:' % script_name 77 print data 78 self.assertEqual(exit_code, 0) 79 printed_file = '__file__==%r' % expected_file 80 printed_argv0 = 'sys.argv[0]==%r' % expected_argv0 81 printed_package = '__package__==%r' % expected_package 82 if verbose: 83 print 'Expected output:' 84 print printed_file 85 print printed_package 86 print printed_argv0 87 self.assertIn(printed_file, data) 88 self.assertIn(printed_package, data) 89 self.assertIn(printed_argv0, data) 90 91 def _check_import_error(self, script_name, expected_msg, 92 *cmd_line_switches): 93 run_args = cmd_line_switches + (script_name,) 94 exit_code, data = run_python(*run_args) 95 if verbose: 96 print 'Output from test script %r:' % script_name 97 print data 98 print 'Expected output: %r' % expected_msg 99 self.assertIn(expected_msg, data) 100 101 def test_basic_script(self): 102 with temp_dir() as script_dir: 103 script_name = _make_test_script(script_dir, 'script') 104 self._check_script(script_name, script_name, script_name, None) 105 106 def test_script_compiled(self): 107 with temp_dir() as script_dir: 108 script_name = _make_test_script(script_dir, 'script') 109 compiled_name = compile_script(script_name) 110 os.remove(script_name) 111 self._check_script(compiled_name, compiled_name, compiled_name, None) 112 113 def test_directory(self): 114 with temp_dir() as script_dir: 115 script_name = _make_test_script(script_dir, '__main__') 116 self._check_script(script_dir, script_name, script_dir, '') 117 118 def test_directory_compiled(self): 119 with temp_dir() as script_dir: 120 script_name = _make_test_script(script_dir, '__main__') 121 compiled_name = compile_script(script_name) 122 os.remove(script_name) 123 self._check_script(script_dir, compiled_name, script_dir, '') 124 125 def test_directory_error(self): 126 with temp_dir() as script_dir: 127 msg = "can't find '__main__' module in %r" % script_dir 128 self._check_import_error(script_dir, msg) 129 130 def test_zipfile(self): 131 with temp_dir() as script_dir: 132 script_name = _make_test_script(script_dir, '__main__') 133 zip_name, run_name = make_zip_script(script_dir, 'test_zip', script_name) 134 self._check_script(zip_name, run_name, zip_name, '') 135 136 def test_zipfile_compiled(self): 137 with temp_dir() as script_dir: 138 script_name = _make_test_script(script_dir, '__main__') 139 compiled_name = compile_script(script_name) 140 zip_name, run_name = make_zip_script(script_dir, 'test_zip', compiled_name) 141 self._check_script(zip_name, run_name, zip_name, '') 142 143 def test_zipfile_error(self): 144 with temp_dir() as script_dir: 145 script_name = _make_test_script(script_dir, 'not_main') 146 zip_name, run_name = make_zip_script(script_dir, 'test_zip', script_name) 147 msg = "can't find '__main__' module in %r" % zip_name 148 self._check_import_error(zip_name, msg) 149 150 def test_module_in_package(self): 151 with temp_dir() as script_dir: 152 pkg_dir = os.path.join(script_dir, 'test_pkg') 153 make_pkg(pkg_dir) 154 script_name = _make_test_script(pkg_dir, 'script') 155 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script') 156 self._check_script(launch_name, script_name, script_name, 'test_pkg') 157 158 def test_module_in_package_in_zipfile(self): 159 with temp_dir() as script_dir: 160 zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script') 161 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script', zip_name) 162 self._check_script(launch_name, run_name, run_name, 'test_pkg') 163 164 def test_module_in_subpackage_in_zipfile(self): 165 with temp_dir() as script_dir: 166 zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script', depth=2) 167 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.test_pkg.script', zip_name) 168 self._check_script(launch_name, run_name, run_name, 'test_pkg.test_pkg') 169 170 def test_package(self): 171 with temp_dir() as script_dir: 172 pkg_dir = os.path.join(script_dir, 'test_pkg') 173 make_pkg(pkg_dir) 174 script_name = _make_test_script(pkg_dir, '__main__') 175 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') 176 self._check_script(launch_name, script_name, 177 script_name, 'test_pkg') 178 179 def test_package_compiled(self): 180 with temp_dir() as script_dir: 181 pkg_dir = os.path.join(script_dir, 'test_pkg') 182 make_pkg(pkg_dir) 183 script_name = _make_test_script(pkg_dir, '__main__') 184 compiled_name = compile_script(script_name) 185 os.remove(script_name) 186 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') 187 self._check_script(launch_name, compiled_name, 188 compiled_name, 'test_pkg') 189 190 def test_package_error(self): 191 with temp_dir() as script_dir: 192 pkg_dir = os.path.join(script_dir, 'test_pkg') 193 make_pkg(pkg_dir) 194 msg = ("'test_pkg' is a package and cannot " 195 "be directly executed") 196 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') 197 self._check_import_error(launch_name, msg) 198 199 def test_package_recursion(self): 200 with temp_dir() as script_dir: 201 pkg_dir = os.path.join(script_dir, 'test_pkg') 202 make_pkg(pkg_dir) 203 main_dir = os.path.join(pkg_dir, '__main__') 204 make_pkg(main_dir) 205 msg = ("Cannot use package as __main__ module; " 206 "'test_pkg' is a package and cannot " 207 "be directly executed") 208 launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') 209 self._check_import_error(launch_name, msg) 210 211 @contextlib.contextmanager 212 def setup_test_pkg(self, *args): 213 with temp_dir() as script_dir, \ 214 test.test_support.change_cwd(script_dir): 215 pkg_dir = os.path.join(script_dir, 'test_pkg') 216 make_pkg(pkg_dir, *args) 217 yield pkg_dir 218 219 def check_dash_m_failure(self, *args): 220 rc, out, err = assert_python_failure('-m', *args) 221 if verbose > 1: 222 print(out) 223 self.assertEqual(rc, 1) 224 return err 225 226 def test_dash_m_error_code_is_one(self): 227 # If a module is invoked with the -m command line flag 228 # and results in an error that the return code to the 229 # shell is '1' 230 with self.setup_test_pkg() as pkg_dir: 231 script_name = _make_test_script(pkg_dir, 'other', "if __name__ == '__main__': raise ValueError") 232 err = self.check_dash_m_failure('test_pkg.other', *example_args) 233 self.assertIn(b'ValueError', err) 234 235 def test_dash_m_errors(self): 236 # Exercise error reporting for various invalid package executions 237 tests = ( 238 ('__builtin__', br'No code object available'), 239 ('__builtin__.x', br'No module named'), 240 ('__builtin__.x.y', br'No module named'), 241 ('os.path', br'Loader.*cannot handle'), 242 ('importlib', br'No module named.*' 243 br'is a package and cannot be directly executed'), 244 ('importlib.nonexistant', br'No module named'), 245 ) 246 for name, regex in tests: 247 rc, _, err = assert_python_failure('-m', name) 248 self.assertEqual(rc, 1) 249 self.assertRegexpMatches(err, regex) 250 self.assertNotIn(b'Traceback', err) 251 252 def test_dash_m_init_traceback(self): 253 # These were wrapped in an ImportError and tracebacks were 254 # suppressed; see Issue 14285 255 exceptions = (ImportError, AttributeError, TypeError, ValueError) 256 for exception in exceptions: 257 exception = exception.__name__ 258 init = "raise {0}('Exception in __init__.py')".format(exception) 259 with self.setup_test_pkg(init) as pkg_dir: 260 err = self.check_dash_m_failure('test_pkg') 261 self.assertIn(exception.encode('ascii'), err) 262 self.assertIn(b'Exception in __init__.py', err) 263 self.assertIn(b'Traceback', err) 264 265 def test_dash_m_main_traceback(self): 266 # Ensure that an ImportError's traceback is reported 267 with self.setup_test_pkg() as pkg_dir: 268 main = "raise ImportError('Exception in __main__ module')" 269 _make_test_script(pkg_dir, '__main__', main) 270 err = self.check_dash_m_failure('test_pkg') 271 self.assertIn(b'ImportError', err) 272 self.assertIn(b'Exception in __main__ module', err) 273 self.assertIn(b'Traceback', err) 274 275 276def test_main(): 277 test.test_support.run_unittest(CmdLineTest) 278 test.test_support.reap_children() 279 280if __name__ == '__main__': 281 test_main() 282