Home | History | Annotate | Download | only in test
      1 # This test module covers support in various parts of the standard library
      2 # for working with modules located inside zipfiles
      3 # The tests are centralised in this fashion to make it easy to drop them
      4 # if a platform doesn't support zipimport
      5 import test.test_support
      6 import os
      7 import os.path
      8 import sys
      9 import textwrap
     10 import zipfile
     11 import zipimport
     12 import doctest
     13 import inspect
     14 import linecache
     15 import pdb
     16 import warnings
     17 from test.script_helper import (spawn_python, kill_python, run_python,
     18                                 temp_dir, make_script, make_zip_script)
     19 
     20 verbose = test.test_support.verbose
     21 
     22 # Library modules covered by this test set
     23 #  pdb (Issue 4201)
     24 #  inspect (Issue 4223)
     25 #  doctest (Issue 4197)
     26 
     27 # Other test modules with zipimport related tests
     28 #  test_zipimport (of course!)
     29 #  test_cmd_line_script (covers the zipimport support in runpy)
     30 
     31 # Retrieve some helpers from other test cases
     32 from test import (test_doctest, sample_doctest, sample_doctest_no_doctests,
     33                   sample_doctest_no_docstrings)
     34 from test.test_importhooks import ImportHooksBaseTestCase
     35 
     36 
     37 def _run_object_doctest(obj, module):
     38     # Direct doctest output (normally just errors) to real stdout; doctest
     39     # output shouldn't be compared by regrtest.
     40     save_stdout = sys.stdout
     41     sys.stdout = test.test_support.get_original_stdout()
     42     try:
     43         finder = doctest.DocTestFinder(verbose=verbose, recurse=False)
     44         runner = doctest.DocTestRunner(verbose=verbose)
     45         # Use the object's fully qualified name if it has one
     46         # Otherwise, use the module's name
     47         try:
     48             name = "%s.%s" % (obj.__module__, obj.__name__)
     49         except AttributeError:
     50             name = module.__name__
     51         for example in finder.find(obj, name, module):
     52             runner.run(example)
     53         f, t = runner.failures, runner.tries
     54         if f:
     55             raise test.test_support.TestFailed("%d of %d doctests failed" % (f, t))
     56     finally:
     57         sys.stdout = save_stdout
     58     if verbose:
     59         print 'doctest (%s) ... %d tests with zero failures' % (module.__name__, t)
     60     return f, t
     61 
     62 
     63 
     64 class ZipSupportTests(ImportHooksBaseTestCase):
     65     # We use the ImportHooksBaseTestCase to restore
     66     # the state of the import related information
     67     # in the sys module after each test
     68     # We also clear the linecache and zipimport cache
     69     # just to avoid any bogus errors due to name reuse in the tests
     70     def setUp(self):
     71         linecache.clearcache()
     72         zipimport._zip_directory_cache.clear()
     73         ImportHooksBaseTestCase.setUp(self)
     74 
     75 
     76     def test_inspect_getsource_issue4223(self):
     77         test_src = "def foo(): pass\n"
     78         with temp_dir() as d:
     79             init_name = make_script(d, '__init__', test_src)
     80             name_in_zip = os.path.join('zip_pkg',
     81                                        os.path.basename(init_name))
     82             zip_name, run_name = make_zip_script(d, 'test_zip',
     83                                                 init_name, name_in_zip)
     84             os.remove(init_name)
     85             sys.path.insert(0, zip_name)
     86             import zip_pkg
     87             self.assertEqual(inspect.getsource(zip_pkg.foo), test_src)
     88 
     89     def test_doctest_issue4197(self):
     90         # To avoid having to keep two copies of the doctest module's
     91         # unit tests in sync, this test works by taking the source of
     92         # test_doctest itself, rewriting it a bit to cope with a new
     93         # location, and then throwing it in a zip file to make sure
     94         # everything still works correctly
     95         test_src = inspect.getsource(test_doctest)
     96         test_src = test_src.replace(
     97                          "from test import test_doctest",
     98                          "import test_zipped_doctest as test_doctest")
     99         test_src = test_src.replace("test.test_doctest",
    100                                     "test_zipped_doctest")
    101         test_src = test_src.replace("test.sample_doctest",
    102                                     "sample_zipped_doctest")
    103         # The sample doctest files rewritten to include in the zipped version.
    104         sample_sources = {}
    105         for mod in [sample_doctest, sample_doctest_no_doctests,
    106                     sample_doctest_no_docstrings]:
    107             src = inspect.getsource(mod)
    108             src = src.replace("test.test_doctest", "test_zipped_doctest")
    109             # Rewrite the module name so that, for example,
    110             # "test.sample_doctest" becomes "sample_zipped_doctest".
    111             mod_name = mod.__name__.split(".")[-1]
    112             mod_name = mod_name.replace("sample_", "sample_zipped_")
    113             sample_sources[mod_name] = src
    114 
    115         with temp_dir() as d:
    116             script_name = make_script(d, 'test_zipped_doctest',
    117                                             test_src)
    118             zip_name, run_name = make_zip_script(d, 'test_zip',
    119                                                 script_name)
    120             z = zipfile.ZipFile(zip_name, 'a')
    121             for mod_name, src in sample_sources.items():
    122                 z.writestr(mod_name + ".py", src)
    123             z.close()
    124             if verbose:
    125                 zip_file = zipfile.ZipFile(zip_name, 'r')
    126                 print 'Contents of %r:' % zip_name
    127                 zip_file.printdir()
    128                 zip_file.close()
    129             os.remove(script_name)
    130             sys.path.insert(0, zip_name)
    131             import test_zipped_doctest
    132             # Some of the doc tests depend on the colocated text files
    133             # which aren't available to the zipped version (the doctest
    134             # module currently requires real filenames for non-embedded
    135             # tests). So we're forced to be selective about which tests
    136             # to run.
    137             # doctest could really use some APIs which take a text
    138             # string or a file object instead of a filename...
    139             known_good_tests = [
    140                 test_zipped_doctest.SampleClass,
    141                 test_zipped_doctest.SampleClass.NestedClass,
    142                 test_zipped_doctest.SampleClass.NestedClass.__init__,
    143                 test_zipped_doctest.SampleClass.__init__,
    144                 test_zipped_doctest.SampleClass.a_classmethod,
    145                 test_zipped_doctest.SampleClass.a_property,
    146                 test_zipped_doctest.SampleClass.a_staticmethod,
    147                 test_zipped_doctest.SampleClass.double,
    148                 test_zipped_doctest.SampleClass.get,
    149                 test_zipped_doctest.SampleNewStyleClass,
    150                 test_zipped_doctest.SampleNewStyleClass.__init__,
    151                 test_zipped_doctest.SampleNewStyleClass.double,
    152                 test_zipped_doctest.SampleNewStyleClass.get,
    153                 test_zipped_doctest.old_test1,
    154                 test_zipped_doctest.old_test2,
    155                 test_zipped_doctest.old_test3,
    156                 test_zipped_doctest.old_test4,
    157                 test_zipped_doctest.sample_func,
    158                 test_zipped_doctest.test_DocTest,
    159                 test_zipped_doctest.test_DocTestParser,
    160                 test_zipped_doctest.test_DocTestRunner.basics,
    161                 test_zipped_doctest.test_DocTestRunner.exceptions,
    162                 test_zipped_doctest.test_DocTestRunner.option_directives,
    163                 test_zipped_doctest.test_DocTestRunner.optionflags,
    164                 test_zipped_doctest.test_DocTestRunner.verbose_flag,
    165                 test_zipped_doctest.test_Example,
    166                 test_zipped_doctest.test_debug,
    167                 test_zipped_doctest.test_pdb_set_trace,
    168                 test_zipped_doctest.test_pdb_set_trace_nested,
    169                 test_zipped_doctest.test_testsource,
    170                 test_zipped_doctest.test_trailing_space_in_test,
    171                 test_zipped_doctest.test_DocTestSuite,
    172                 test_zipped_doctest.test_DocTestFinder,
    173             ]
    174             # These remaining tests are the ones which need access
    175             # to the data files, so we don't run them
    176             fail_due_to_missing_data_files = [
    177                 test_zipped_doctest.test_DocFileSuite,
    178                 test_zipped_doctest.test_testfile,
    179                 test_zipped_doctest.test_unittest_reportflags,
    180             ]
    181             # Needed for test_DocTestParser and test_debug
    182             deprecations = []
    183             if __debug__:
    184                 # Ignore all warnings about the use of class Tester in this module.
    185                 deprecations.append(("class Tester is deprecated", DeprecationWarning))
    186             if sys.py3kwarning:
    187                 deprecations += [
    188                     ("backquote not supported", SyntaxWarning),
    189                     ("execfile.. not supported", DeprecationWarning)]
    190             with test.test_support.check_warnings(*deprecations):
    191                 for obj in known_good_tests:
    192                     _run_object_doctest(obj, test_zipped_doctest)
    193 
    194     def test_doctest_main_issue4197(self):
    195         test_src = textwrap.dedent("""\
    196                     class Test:
    197                         ">>> 'line 2'"
    198                         pass
    199 
    200                     import doctest
    201                     doctest.testmod()
    202                     """)
    203         pattern = 'File "%s", line 2, in %s'
    204         with temp_dir() as d:
    205             script_name = make_script(d, 'script', test_src)
    206             exit_code, data = run_python(script_name)
    207             expected = pattern % (script_name, "__main__.Test")
    208             if verbose:
    209                 print "Expected line", expected
    210                 print "Got stdout:"
    211                 print data
    212             self.assertIn(expected, data)
    213             zip_name, run_name = make_zip_script(d, "test_zip",
    214                                                 script_name, '__main__.py')
    215             exit_code, data = run_python(zip_name)
    216             expected = pattern % (run_name, "__main__.Test")
    217             if verbose:
    218                 print "Expected line", expected
    219                 print "Got stdout:"
    220                 print data
    221             self.assertIn(expected, data)
    222 
    223     def test_pdb_issue4201(self):
    224         test_src = textwrap.dedent("""\
    225                     def f():
    226                         pass
    227 
    228                     import pdb
    229                     pdb.runcall(f)
    230                     """)
    231         with temp_dir() as d:
    232             script_name = make_script(d, 'script', test_src)
    233             p = spawn_python(script_name)
    234             p.stdin.write('l\n')
    235             data = kill_python(p)
    236             self.assertIn(script_name, data)
    237             zip_name, run_name = make_zip_script(d, "test_zip",
    238                                                 script_name, '__main__.py')
    239             p = spawn_python(zip_name)
    240             p.stdin.write('l\n')
    241             data = kill_python(p)
    242             self.assertIn(run_name, data)
    243 
    244 
    245 def test_main():
    246     test.test_support.run_unittest(ZipSupportTests)
    247     test.test_support.reap_children()
    248 
    249 if __name__ == '__main__':
    250     test_main()
    251