Home | History | Annotate | Download | only in test
      1 # Tests command line execution of scripts
      2 
      3 import contextlib
      4 import unittest
      5 import os
      6 import os.path
      7 import test.test_support
      8 from 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 
     13 verbose = test.test_support.verbose
     14 
     15 
     16 example_args = ['test1', 'test2', 'test3']
     17 
     18 test_source = """\
     19 # Script may be run with optimisation enabled, so don't rely on assert
     20 # statements being executed
     21 def assertEqual(lhs, rhs):
     22     if lhs != rhs:
     23         raise AssertionError('%r != %r' % (lhs, rhs))
     24 def assertIdentical(lhs, rhs):
     25     if lhs is not rhs:
     26         raise AssertionError('%r is not %r' % (lhs, rhs))
     27 # Check basic code execution
     28 result = ['Top level assignment']
     29 def f():
     30     result.append('Lower level reference')
     31 f()
     32 assertEqual(result, ['Top level assignment', 'Lower level reference'])
     33 # Check population of magic variables
     34 assertEqual(__name__, '__main__')
     35 print '__file__==%r' % __file__
     36 print '__package__==%r' % __package__
     37 # Check the sys module
     38 import sys
     39 assertIdentical(globals(), sys.modules[__name__].__dict__)
     40 print 'sys.argv[0]==%r' % sys.argv[0]
     41 """
     42 
     43 def _make_test_script(script_dir, script_basename, source=test_source):
     44     return make_script(script_dir, script_basename, source)
     45 
     46 def _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
     55 launch_source = """\
     56 import sys, os.path, runpy
     57 sys.path.insert(0, %s)
     58 runpy._run_module_as_main(%r)
     59 """
     60 
     61 def _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 
     69 class 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 
    276 def test_main():
    277     test.test_support.run_unittest(CmdLineTest)
    278     test.test_support.reap_children()
    279 
    280 if __name__ == '__main__':
    281     test_main()
    282