Home | History | Annotate | Download | only in test
      1 try:
      2     import _thread
      3 except ImportError:
      4     _thread = None
      5 import importlib
      6 import importlib.util
      7 import os
      8 import os.path
      9 import sys
     10 from test import support
     11 import unittest
     12 import warnings
     13 with warnings.catch_warnings():
     14     warnings.simplefilter('ignore', DeprecationWarning)
     15     import imp
     16 
     17 
     18 def requires_load_dynamic(meth):
     19     """Decorator to skip a test if not running under CPython or lacking
     20     imp.load_dynamic()."""
     21     meth = support.cpython_only(meth)
     22     return unittest.skipIf(not hasattr(imp, 'load_dynamic'),
     23                            'imp.load_dynamic() required')(meth)
     24 
     25 
     26 @unittest.skipIf(_thread is None, '_thread module is required')
     27 class LockTests(unittest.TestCase):
     28 
     29     """Very basic test of import lock functions."""
     30 
     31     def verify_lock_state(self, expected):
     32         self.assertEqual(imp.lock_held(), expected,
     33                              "expected imp.lock_held() to be %r" % expected)
     34     def testLock(self):
     35         LOOPS = 50
     36 
     37         # The import lock may already be held, e.g. if the test suite is run
     38         # via "import test.autotest".
     39         lock_held_at_start = imp.lock_held()
     40         self.verify_lock_state(lock_held_at_start)
     41 
     42         for i in range(LOOPS):
     43             imp.acquire_lock()
     44             self.verify_lock_state(True)
     45 
     46         for i in range(LOOPS):
     47             imp.release_lock()
     48 
     49         # The original state should be restored now.
     50         self.verify_lock_state(lock_held_at_start)
     51 
     52         if not lock_held_at_start:
     53             try:
     54                 imp.release_lock()
     55             except RuntimeError:
     56                 pass
     57             else:
     58                 self.fail("release_lock() without lock should raise "
     59                             "RuntimeError")
     60 
     61 class ImportTests(unittest.TestCase):
     62     def setUp(self):
     63         mod = importlib.import_module('test.encoded_modules')
     64         self.test_strings = mod.test_strings
     65         self.test_path = mod.__path__
     66 
     67     def test_import_encoded_module(self):
     68         for modname, encoding, teststr in self.test_strings:
     69             mod = importlib.import_module('test.encoded_modules.'
     70                                           'module_' + modname)
     71             self.assertEqual(teststr, mod.test)
     72 
     73     def test_find_module_encoding(self):
     74         for mod, encoding, _ in self.test_strings:
     75             with imp.find_module('module_' + mod, self.test_path)[0] as fd:
     76                 self.assertEqual(fd.encoding, encoding)
     77 
     78         path = [os.path.dirname(__file__)]
     79         with self.assertRaises(SyntaxError):
     80             imp.find_module('badsyntax_pep3120', path)
     81 
     82     def test_issue1267(self):
     83         for mod, encoding, _ in self.test_strings:
     84             fp, filename, info  = imp.find_module('module_' + mod,
     85                                                   self.test_path)
     86             with fp:
     87                 self.assertNotEqual(fp, None)
     88                 self.assertEqual(fp.encoding, encoding)
     89                 self.assertEqual(fp.tell(), 0)
     90                 self.assertEqual(fp.readline(), '# test %s encoding\n'
     91                                  % encoding)
     92 
     93         fp, filename, info = imp.find_module("tokenize")
     94         with fp:
     95             self.assertNotEqual(fp, None)
     96             self.assertEqual(fp.encoding, "utf-8")
     97             self.assertEqual(fp.tell(), 0)
     98             self.assertEqual(fp.readline(),
     99                              '"""Tokenization help for Python programs.\n')
    100 
    101     def test_issue3594(self):
    102         temp_mod_name = 'test_imp_helper'
    103         sys.path.insert(0, '.')
    104         try:
    105             with open(temp_mod_name + '.py', 'w') as file:
    106                 file.write("# coding: cp1252\nu = 'test.test_imp'\n")
    107             file, filename, info = imp.find_module(temp_mod_name)
    108             file.close()
    109             self.assertEqual(file.encoding, 'cp1252')
    110         finally:
    111             del sys.path[0]
    112             support.unlink(temp_mod_name + '.py')
    113             support.unlink(temp_mod_name + '.pyc')
    114 
    115     def test_issue5604(self):
    116         # Test cannot cover imp.load_compiled function.
    117         # Martin von Loewis note what shared library cannot have non-ascii
    118         # character because init_xxx function cannot be compiled
    119         # and issue never happens for dynamic modules.
    120         # But sources modified to follow generic way for processing pathes.
    121 
    122         # the return encoding could be uppercase or None
    123         fs_encoding = sys.getfilesystemencoding()
    124 
    125         # covers utf-8 and Windows ANSI code pages
    126         # one non-space symbol from every page
    127         # (http://en.wikipedia.org/wiki/Code_page)
    128         known_locales = {
    129             'utf-8' : b'\xc3\xa4',
    130             'cp1250' : b'\x8C',
    131             'cp1251' : b'\xc0',
    132             'cp1252' : b'\xc0',
    133             'cp1253' : b'\xc1',
    134             'cp1254' : b'\xc0',
    135             'cp1255' : b'\xe0',
    136             'cp1256' : b'\xe0',
    137             'cp1257' : b'\xc0',
    138             'cp1258' : b'\xc0',
    139             }
    140 
    141         if sys.platform == 'darwin':
    142             self.assertEqual(fs_encoding, 'utf-8')
    143             # Mac OS X uses the Normal Form D decomposition
    144             # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
    145             special_char = b'a\xcc\x88'
    146         else:
    147             special_char = known_locales.get(fs_encoding)
    148 
    149         if not special_char:
    150             self.skipTest("can't run this test with %s as filesystem encoding"
    151                           % fs_encoding)
    152         decoded_char = special_char.decode(fs_encoding)
    153         temp_mod_name = 'test_imp_helper_' + decoded_char
    154         test_package_name = 'test_imp_helper_package_' + decoded_char
    155         init_file_name = os.path.join(test_package_name, '__init__.py')
    156         try:
    157             # if the curdir is not in sys.path the test fails when run with
    158             # ./python ./Lib/test/regrtest.py test_imp
    159             sys.path.insert(0, os.curdir)
    160             with open(temp_mod_name + '.py', 'w') as file:
    161                 file.write('a = 1\n')
    162             file, filename, info = imp.find_module(temp_mod_name)
    163             with file:
    164                 self.assertIsNotNone(file)
    165                 self.assertTrue(filename[:-3].endswith(temp_mod_name))
    166                 self.assertEqual(info[0], '.py')
    167                 self.assertEqual(info[1], 'r')
    168                 self.assertEqual(info[2], imp.PY_SOURCE)
    169 
    170                 mod = imp.load_module(temp_mod_name, file, filename, info)
    171                 self.assertEqual(mod.a, 1)
    172 
    173             with warnings.catch_warnings():
    174                 warnings.simplefilter('ignore')
    175                 mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
    176             self.assertEqual(mod.a, 1)
    177 
    178             with warnings.catch_warnings():
    179                 warnings.simplefilter('ignore')
    180                 if not sys.dont_write_bytecode:
    181                     mod = imp.load_compiled(
    182                         temp_mod_name,
    183                         imp.cache_from_source(temp_mod_name + '.py'))
    184             self.assertEqual(mod.a, 1)
    185 
    186             if not os.path.exists(test_package_name):
    187                 os.mkdir(test_package_name)
    188             with open(init_file_name, 'w') as file:
    189                 file.write('b = 2\n')
    190             with warnings.catch_warnings():
    191                 warnings.simplefilter('ignore')
    192                 package = imp.load_package(test_package_name, test_package_name)
    193             self.assertEqual(package.b, 2)
    194         finally:
    195             del sys.path[0]
    196             for ext in ('.py', '.pyc'):
    197                 support.unlink(temp_mod_name + ext)
    198                 support.unlink(init_file_name + ext)
    199             support.rmtree(test_package_name)
    200             support.rmtree('__pycache__')
    201 
    202     def test_issue9319(self):
    203         path = os.path.dirname(__file__)
    204         self.assertRaises(SyntaxError,
    205                           imp.find_module, "badsyntax_pep3120", [path])
    206 
    207     def test_load_from_source(self):
    208         # Verify that the imp module can correctly load and find .py files
    209         # XXX (ncoghlan): It would be nice to use support.CleanImport
    210         # here, but that breaks because the os module registers some
    211         # handlers in copy_reg on import. Since CleanImport doesn't
    212         # revert that registration, the module is left in a broken
    213         # state after reversion. Reinitialising the module contents
    214         # and just reverting os.environ to its previous state is an OK
    215         # workaround
    216         orig_path = os.path
    217         orig_getenv = os.getenv
    218         with support.EnvironmentVarGuard():
    219             x = imp.find_module("os")
    220             self.addCleanup(x[0].close)
    221             new_os = imp.load_module("os", *x)
    222             self.assertIs(os, new_os)
    223             self.assertIs(orig_path, new_os.path)
    224             self.assertIsNot(orig_getenv, new_os.getenv)
    225 
    226     @requires_load_dynamic
    227     def test_issue15828_load_extensions(self):
    228         # Issue 15828 picked up that the adapter between the old imp API
    229         # and importlib couldn't handle C extensions
    230         example = "_heapq"
    231         x = imp.find_module(example)
    232         file_ = x[0]
    233         if file_ is not None:
    234             self.addCleanup(file_.close)
    235         mod = imp.load_module(example, *x)
    236         self.assertEqual(mod.__name__, example)
    237 
    238     @requires_load_dynamic
    239     def test_issue16421_multiple_modules_in_one_dll(self):
    240         # Issue 16421: loading several modules from the same compiled file fails
    241         m = '_testimportmultiple'
    242         fileobj, pathname, description = imp.find_module(m)
    243         fileobj.close()
    244         mod0 = imp.load_dynamic(m, pathname)
    245         mod1 = imp.load_dynamic('_testimportmultiple_foo', pathname)
    246         mod2 = imp.load_dynamic('_testimportmultiple_bar', pathname)
    247         self.assertEqual(mod0.__name__, m)
    248         self.assertEqual(mod1.__name__, '_testimportmultiple_foo')
    249         self.assertEqual(mod2.__name__, '_testimportmultiple_bar')
    250         with self.assertRaises(ImportError):
    251             imp.load_dynamic('nonexistent', pathname)
    252 
    253     @requires_load_dynamic
    254     def test_load_dynamic_ImportError_path(self):
    255         # Issue #1559549 added `name` and `path` attributes to ImportError
    256         # in order to provide better detail. Issue #10854 implemented those
    257         # attributes on import failures of extensions on Windows.
    258         path = 'bogus file path'
    259         name = 'extension'
    260         with self.assertRaises(ImportError) as err:
    261             imp.load_dynamic(name, path)
    262         self.assertIn(path, err.exception.path)
    263         self.assertEqual(name, err.exception.name)
    264 
    265     @requires_load_dynamic
    266     def test_load_module_extension_file_is_None(self):
    267         # When loading an extension module and the file is None, open one
    268         # on the behalf of imp.load_dynamic().
    269         # Issue #15902
    270         name = '_testimportmultiple'
    271         found = imp.find_module(name)
    272         if found[0] is not None:
    273             found[0].close()
    274         if found[2][2] != imp.C_EXTENSION:
    275             self.skipTest("found module doesn't appear to be a C extension")
    276         imp.load_module(name, None, *found[1:])
    277 
    278     @requires_load_dynamic
    279     def test_issue24748_load_module_skips_sys_modules_check(self):
    280         name = 'test.imp_dummy'
    281         try:
    282             del sys.modules[name]
    283         except KeyError:
    284             pass
    285         try:
    286             module = importlib.import_module(name)
    287             spec = importlib.util.find_spec('_testmultiphase')
    288             module = imp.load_dynamic(name, spec.origin)
    289             self.assertEqual(module.__name__, name)
    290             self.assertEqual(module.__spec__.name, name)
    291             self.assertEqual(module.__spec__.origin, spec.origin)
    292             self.assertRaises(AttributeError, getattr, module, 'dummy_name')
    293             self.assertEqual(module.int_const, 1969)
    294             self.assertIs(sys.modules[name], module)
    295         finally:
    296             try:
    297                 del sys.modules[name]
    298             except KeyError:
    299                 pass
    300 
    301     @unittest.skipIf(sys.dont_write_bytecode,
    302         "test meaningful only when writing bytecode")
    303     def test_bug7732(self):
    304         with support.temp_cwd():
    305             source = support.TESTFN + '.py'
    306             os.mkdir(source)
    307             self.assertRaisesRegex(ImportError, '^No module',
    308                 imp.find_module, support.TESTFN, ["."])
    309 
    310     def test_multiple_calls_to_get_data(self):
    311         # Issue #18755: make sure multiple calls to get_data() can succeed.
    312         loader = imp._LoadSourceCompatibility('imp', imp.__file__,
    313                                               open(imp.__file__))
    314         loader.get_data(imp.__file__)  # File should be closed
    315         loader.get_data(imp.__file__)  # Will need to create a newly opened file
    316 
    317 
    318 class ReloadTests(unittest.TestCase):
    319 
    320     """Very basic tests to make sure that imp.reload() operates just like
    321     reload()."""
    322 
    323     def test_source(self):
    324         # XXX (ncoghlan): It would be nice to use test.support.CleanImport
    325         # here, but that breaks because the os module registers some
    326         # handlers in copy_reg on import. Since CleanImport doesn't
    327         # revert that registration, the module is left in a broken
    328         # state after reversion. Reinitialising the module contents
    329         # and just reverting os.environ to its previous state is an OK
    330         # workaround
    331         with support.EnvironmentVarGuard():
    332             import os
    333             imp.reload(os)
    334 
    335     def test_extension(self):
    336         with support.CleanImport('time'):
    337             import time
    338             imp.reload(time)
    339 
    340     def test_builtin(self):
    341         with support.CleanImport('marshal'):
    342             import marshal
    343             imp.reload(marshal)
    344 
    345     def test_with_deleted_parent(self):
    346         # see #18681
    347         from html import parser
    348         html = sys.modules.pop('html')
    349         def cleanup():
    350             sys.modules['html'] = html
    351         self.addCleanup(cleanup)
    352         with self.assertRaisesRegex(ImportError, 'html'):
    353             imp.reload(parser)
    354 
    355 
    356 class PEP3147Tests(unittest.TestCase):
    357     """Tests of PEP 3147."""
    358 
    359     tag = imp.get_tag()
    360 
    361     @unittest.skipUnless(sys.implementation.cache_tag is not None,
    362                          'requires sys.implementation.cache_tag not be None')
    363     def test_cache_from_source(self):
    364         # Given the path to a .py file, return the path to its PEP 3147
    365         # defined .pyc file (i.e. under __pycache__).
    366         path = os.path.join('foo', 'bar', 'baz', 'qux.py')
    367         expect = os.path.join('foo', 'bar', 'baz', '__pycache__',
    368                               'qux.{}.pyc'.format(self.tag))
    369         self.assertEqual(imp.cache_from_source(path, True), expect)
    370 
    371     @unittest.skipUnless(sys.implementation.cache_tag is not None,
    372                          'requires sys.implementation.cache_tag to not be '
    373                          'None')
    374     def test_source_from_cache(self):
    375         # Given the path to a PEP 3147 defined .pyc file, return the path to
    376         # its source.  This tests the good path.
    377         path = os.path.join('foo', 'bar', 'baz', '__pycache__',
    378                             'qux.{}.pyc'.format(self.tag))
    379         expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
    380         self.assertEqual(imp.source_from_cache(path), expect)
    381 
    382 
    383 class NullImporterTests(unittest.TestCase):
    384     @unittest.skipIf(support.TESTFN_UNENCODABLE is None,
    385                      "Need an undecodeable filename")
    386     def test_unencodeable(self):
    387         name = support.TESTFN_UNENCODABLE
    388         os.mkdir(name)
    389         try:
    390             self.assertRaises(ImportError, imp.NullImporter, name)
    391         finally:
    392             os.rmdir(name)
    393 
    394 
    395 if __name__ == "__main__":
    396     unittest.main()
    397