test_imp.py revision 7fdd0fe48f3f342273c1d396df142b1d4b9a1a5c
1import imp
2import os
3import os.path
4import shutil
5import sys
6import unittest
7from test import support
8import importlib
9
10class LockTests(unittest.TestCase):
11
12    """Very basic test of import lock functions."""
13
14    def verify_lock_state(self, expected):
15        self.assertEqual(imp.lock_held(), expected,
16                             "expected imp.lock_held() to be %r" % expected)
17    def testLock(self):
18        LOOPS = 50
19
20        # The import lock may already be held, e.g. if the test suite is run
21        # via "import test.autotest".
22        lock_held_at_start = imp.lock_held()
23        self.verify_lock_state(lock_held_at_start)
24
25        for i in range(LOOPS):
26            imp.acquire_lock()
27            self.verify_lock_state(True)
28
29        for i in range(LOOPS):
30            imp.release_lock()
31
32        # The original state should be restored now.
33        self.verify_lock_state(lock_held_at_start)
34
35        if not lock_held_at_start:
36            try:
37                imp.release_lock()
38            except RuntimeError:
39                pass
40            else:
41                self.fail("release_lock() without lock should raise "
42                            "RuntimeError")
43
44class ImportTests(unittest.TestCase):
45    def setUp(self):
46        mod = importlib.import_module('test.encoded_modules')
47        self.test_strings = mod.test_strings
48        self.test_path = mod.__path__
49
50    def test_import_encoded_module(self):
51        for modname, encoding, teststr in self.test_strings:
52            mod = importlib.import_module('test.encoded_modules.'
53                                          'module_' + modname)
54            self.assertEqual(teststr, mod.test)
55
56    def test_find_module_encoding(self):
57        for mod, encoding, _ in self.test_strings:
58            with imp.find_module('module_' + mod, self.test_path)[0] as fd:
59                self.assertEqual(fd.encoding, encoding)
60
61    def test_issue1267(self):
62        for mod, encoding, _ in self.test_strings:
63            fp, filename, info  = imp.find_module('module_' + mod,
64                                                  self.test_path)
65            with fp:
66                self.assertNotEqual(fp, None)
67                self.assertEqual(fp.encoding, encoding)
68                self.assertEqual(fp.tell(), 0)
69                self.assertEqual(fp.readline(), '# test %s encoding\n'
70                                 % encoding)
71
72        fp, filename, info = imp.find_module("tokenize")
73        with fp:
74            self.assertNotEqual(fp, None)
75            self.assertEqual(fp.encoding, "utf-8")
76            self.assertEqual(fp.tell(), 0)
77            self.assertEqual(fp.readline(),
78                             '"""Tokenization help for Python programs.\n')
79
80    def test_issue3594(self):
81        temp_mod_name = 'test_imp_helper'
82        sys.path.insert(0, '.')
83        try:
84            with open(temp_mod_name + '.py', 'w') as file:
85                file.write("# coding: cp1252\nu = 'test.test_imp'\n")
86            file, filename, info = imp.find_module(temp_mod_name)
87            file.close()
88            self.assertEqual(file.encoding, 'cp1252')
89        finally:
90            del sys.path[0]
91            support.unlink(temp_mod_name + '.py')
92            support.unlink(temp_mod_name + '.pyc')
93            support.unlink(temp_mod_name + '.pyo')
94
95    def test_issue5604(self):
96        # Test cannot cover imp.load_compiled function.
97        # Martin von Loewis note what shared library cannot have non-ascii
98        # character because init_xxx function cannot be compiled
99        # and issue never happens for dynamic modules.
100        # But sources modified to follow generic way for processing pathes.
101
102        # the return encoding could be uppercase or None
103        fs_encoding = sys.getfilesystemencoding()
104
105        # covers utf-8 and Windows ANSI code pages
106        # one non-space symbol from every page
107        # (http://en.wikipedia.org/wiki/Code_page)
108        known_locales = {
109            'utf-8' : b'\xc3\xa4',
110            'cp1250' : b'\x8C',
111            'cp1251' : b'\xc0',
112            'cp1252' : b'\xc0',
113            'cp1253' : b'\xc1',
114            'cp1254' : b'\xc0',
115            'cp1255' : b'\xe0',
116            'cp1256' : b'\xe0',
117            'cp1257' : b'\xc0',
118            'cp1258' : b'\xc0',
119            }
120
121        if sys.platform == 'darwin':
122            self.assertEqual(fs_encoding, 'utf-8')
123            # Mac OS X uses the Normal Form D decomposition
124            # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
125            special_char = b'a\xcc\x88'
126        else:
127            special_char = known_locales.get(fs_encoding)
128
129        if not special_char:
130            self.skipTest("can't run this test with %s as filesystem encoding"
131                          % fs_encoding)
132        decoded_char = special_char.decode(fs_encoding)
133        temp_mod_name = 'test_imp_helper_' + decoded_char
134        test_package_name = 'test_imp_helper_package_' + decoded_char
135        init_file_name = os.path.join(test_package_name, '__init__.py')
136        try:
137            # if the curdir is not in sys.path the test fails when run with
138            # ./python ./Lib/test/regrtest.py test_imp
139            sys.path.insert(0, os.curdir)
140            with open(temp_mod_name + '.py', 'w') as file:
141                file.write('a = 1\n')
142            file, filename, info = imp.find_module(temp_mod_name)
143            with file:
144                self.assertIsNotNone(file)
145                self.assertTrue(filename[:-3].endswith(temp_mod_name))
146                self.assertEqual(info[0], '.py')
147                self.assertEqual(info[1], 'U')
148                self.assertEqual(info[2], imp.PY_SOURCE)
149
150                mod = imp.load_module(temp_mod_name, file, filename, info)
151                self.assertEqual(mod.a, 1)
152
153            mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
154            self.assertEqual(mod.a, 1)
155
156            mod = imp.load_compiled(
157                temp_mod_name, imp.cache_from_source(temp_mod_name + '.py'))
158            self.assertEqual(mod.a, 1)
159
160            if not os.path.exists(test_package_name):
161                os.mkdir(test_package_name)
162            with open(init_file_name, 'w') as file:
163                file.write('b = 2\n')
164            package = imp.load_package(test_package_name, test_package_name)
165            self.assertEqual(package.b, 2)
166        finally:
167            del sys.path[0]
168            for ext in ('.py', '.pyc', '.pyo'):
169                support.unlink(temp_mod_name + ext)
170                support.unlink(init_file_name + ext)
171            support.rmtree(test_package_name)
172
173    def test_issue9319(self):
174        self.assertRaises(SyntaxError,
175                          imp.find_module, "test/badsyntax_pep3120")
176
177
178class ReloadTests(unittest.TestCase):
179
180    """Very basic tests to make sure that imp.reload() operates just like
181    reload()."""
182
183    def test_source(self):
184        # XXX (ncoghlan): It would be nice to use test.support.CleanImport
185        # here, but that breaks because the os module registers some
186        # handlers in copy_reg on import. Since CleanImport doesn't
187        # revert that registration, the module is left in a broken
188        # state after reversion. Reinitialising the module contents
189        # and just reverting os.environ to its previous state is an OK
190        # workaround
191        with support.EnvironmentVarGuard():
192            import os
193            imp.reload(os)
194
195    def test_extension(self):
196        with support.CleanImport('time'):
197            import time
198            imp.reload(time)
199
200    def test_builtin(self):
201        with support.CleanImport('marshal'):
202            import marshal
203            imp.reload(marshal)
204
205
206class PEP3147Tests(unittest.TestCase):
207    """Tests of PEP 3147."""
208
209    tag = imp.get_tag()
210
211    def test_cache_from_source(self):
212        # Given the path to a .py file, return the path to its PEP 3147
213        # defined .pyc file (i.e. under __pycache__).
214        self.assertEqual(
215            imp.cache_from_source('/foo/bar/baz/qux.py', True),
216            '/foo/bar/baz/__pycache__/qux.{}.pyc'.format(self.tag))
217
218    def test_cache_from_source_optimized(self):
219        # Given the path to a .py file, return the path to its PEP 3147
220        # defined .pyo file (i.e. under __pycache__).
221        self.assertEqual(
222            imp.cache_from_source('/foo/bar/baz/qux.py', False),
223            '/foo/bar/baz/__pycache__/qux.{}.pyo'.format(self.tag))
224
225    def test_cache_from_source_cwd(self):
226        self.assertEqual(imp.cache_from_source('foo.py', True),
227                         os.sep.join(('__pycache__',
228                                      'foo.{}.pyc'.format(self.tag))))
229
230    def test_cache_from_source_override(self):
231        # When debug_override is not None, it can be any true-ish or false-ish
232        # value.
233        self.assertEqual(
234            imp.cache_from_source('/foo/bar/baz.py', []),
235            '/foo/bar/__pycache__/baz.{}.pyo'.format(self.tag))
236        self.assertEqual(
237            imp.cache_from_source('/foo/bar/baz.py', [17]),
238            '/foo/bar/__pycache__/baz.{}.pyc'.format(self.tag))
239        # However if the bool-ishness can't be determined, the exception
240        # propagates.
241        class Bearish:
242            def __bool__(self): raise RuntimeError
243        self.assertRaises(
244            RuntimeError,
245            imp.cache_from_source, '/foo/bar/baz.py', Bearish())
246
247    @unittest.skipIf(os.altsep is None,
248                     'test meaningful only where os.altsep is defined')
249    def test_altsep_cache_from_source(self):
250        # Windows path and PEP 3147.
251        self.assertEqual(
252            imp.cache_from_source('\\foo\\bar\\baz\\qux.py', True),
253            '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
254
255    @unittest.skipIf(os.altsep is None,
256                     'test meaningful only where os.altsep is defined')
257    def test_altsep_and_sep_cache_from_source(self):
258        # Windows path and PEP 3147 where altsep is right of sep.
259        self.assertEqual(
260            imp.cache_from_source('\\foo\\bar/baz\\qux.py', True),
261            '\\foo\\bar/baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
262
263    @unittest.skipIf(os.altsep is None,
264                     'test meaningful only where os.altsep is defined')
265    def test_sep_altsep_and_sep_cache_from_source(self):
266        # Windows path and PEP 3147 where sep is right of altsep.
267        self.assertEqual(
268            imp.cache_from_source('\\foo\\bar\\baz/qux.py', True),
269            '\\foo\\bar\\baz/__pycache__/qux.{}.pyc'.format(self.tag))
270
271    def test_source_from_cache(self):
272        # Given the path to a PEP 3147 defined .pyc file, return the path to
273        # its source.  This tests the good path.
274        self.assertEqual(imp.source_from_cache(
275            '/foo/bar/baz/__pycache__/qux.{}.pyc'.format(self.tag)),
276            '/foo/bar/baz/qux.py')
277
278    def test_source_from_cache_bad_path(self):
279        # When the path to a pyc file is not in PEP 3147 format, a ValueError
280        # is raised.
281        self.assertRaises(
282            ValueError, imp.source_from_cache, '/foo/bar/bazqux.pyc')
283
284    def test_source_from_cache_no_slash(self):
285        # No slashes at all in path -> ValueError
286        self.assertRaises(
287            ValueError, imp.source_from_cache, 'foo.cpython-32.pyc')
288
289    def test_source_from_cache_too_few_dots(self):
290        # Too few dots in final path component -> ValueError
291        self.assertRaises(
292            ValueError, imp.source_from_cache, '__pycache__/foo.pyc')
293
294    def test_source_from_cache_too_many_dots(self):
295        # Too many dots in final path component -> ValueError
296        self.assertRaises(
297            ValueError, imp.source_from_cache,
298            '__pycache__/foo.cpython-32.foo.pyc')
299
300    def test_source_from_cache_no__pycache__(self):
301        # Another problem with the path -> ValueError
302        self.assertRaises(
303            ValueError, imp.source_from_cache,
304            '/foo/bar/foo.cpython-32.foo.pyc')
305
306    def test_package___file__(self):
307        # Test that a package's __file__ points to the right source directory.
308        os.mkdir('pep3147')
309        sys.path.insert(0, os.curdir)
310        def cleanup():
311            if sys.path[0] == os.curdir:
312                del sys.path[0]
313            shutil.rmtree('pep3147')
314        self.addCleanup(cleanup)
315        # Touch the __init__.py file.
316        with open('pep3147/__init__.py', 'w'):
317            pass
318        m = __import__('pep3147')
319        # Ensure we load the pyc file.
320        support.forget('pep3147')
321        m = __import__('pep3147')
322        self.assertEqual(m.__file__,
323                         os.sep.join(('.', 'pep3147', '__init__.py')))
324
325
326class NullImporterTests(unittest.TestCase):
327    @unittest.skipIf(support.TESTFN_UNENCODABLE is None,
328                     "Need an undecodeable filename")
329    def test_unencodeable(self):
330        name = support.TESTFN_UNENCODABLE
331        os.mkdir(name)
332        try:
333            self.assertRaises(ImportError, imp.NullImporter, name)
334        finally:
335            os.rmdir(name)
336
337
338def test_main():
339    tests = [
340        ImportTests,
341        PEP3147Tests,
342        ReloadTests,
343        NullImporterTests,
344        ]
345    try:
346        import _thread
347    except ImportError:
348        pass
349    else:
350        tests.append(LockTests)
351    support.run_unittest(*tests)
352
353if __name__ == "__main__":
354    test_main()
355