1import errno
2import imp
3import marshal
4import os
5import py_compile
6import random
7import stat
8import struct
9import sys
10import unittest
11import textwrap
12import shutil
13
14from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree,
15                               is_jython, check_warnings, EnvironmentVarGuard)
16from test import symlink_support
17from test import script_helper
18
19def _files(name):
20    return (name + os.extsep + "py",
21            name + os.extsep + "pyc",
22            name + os.extsep + "pyo",
23            name + os.extsep + "pyw",
24            name + "$py.class")
25
26def chmod_files(name):
27    for f in _files(name):
28        try:
29            os.chmod(f, 0600)
30        except OSError as exc:
31            if exc.errno != errno.ENOENT:
32                raise
33
34def remove_files(name):
35    for f in _files(name):
36        unlink(f)
37
38
39class ImportTests(unittest.TestCase):
40
41    def tearDown(self):
42        unload(TESTFN)
43    setUp = tearDown
44
45    def test_case_sensitivity(self):
46        # Brief digression to test that import is case-sensitive:  if we got
47        # this far, we know for sure that "random" exists.
48        try:
49            import RAnDoM
50        except ImportError:
51            pass
52        else:
53            self.fail("import of RAnDoM should have failed (case mismatch)")
54
55    def test_double_const(self):
56        # Another brief digression to test the accuracy of manifest float
57        # constants.
58        from test import double_const  # don't blink -- that *was* the test
59
60    def test_import(self):
61        def test_with_extension(ext):
62            # The extension is normally ".py", perhaps ".pyw".
63            source = TESTFN + ext
64            pyo = TESTFN + os.extsep + "pyo"
65            if is_jython:
66                pyc = TESTFN + "$py.class"
67            else:
68                pyc = TESTFN + os.extsep + "pyc"
69
70            with open(source, "w") as f:
71                print >> f, ("# This tests Python's ability to import a", ext,
72                             "file.")
73                a = random.randrange(1000)
74                b = random.randrange(1000)
75                print >> f, "a =", a
76                print >> f, "b =", b
77
78            try:
79                mod = __import__(TESTFN)
80            except ImportError, err:
81                self.fail("import from %s failed: %s" % (ext, err))
82            else:
83                self.assertEqual(mod.a, a,
84                    "module loaded (%s) but contents invalid" % mod)
85                self.assertEqual(mod.b, b,
86                    "module loaded (%s) but contents invalid" % mod)
87            finally:
88                unlink(source)
89
90            try:
91                if not sys.dont_write_bytecode:
92                    imp.reload(mod)
93            except ImportError, err:
94                self.fail("import from .pyc/.pyo failed: %s" % err)
95            finally:
96                unlink(pyc)
97                unlink(pyo)
98                unload(TESTFN)
99
100        sys.path.insert(0, os.curdir)
101        try:
102            test_with_extension(os.extsep + "py")
103            if sys.platform.startswith("win"):
104                for ext in [".PY", ".Py", ".pY", ".pyw", ".PYW", ".pYw"]:
105                    test_with_extension(ext)
106        finally:
107            del sys.path[0]
108
109    @unittest.skipUnless(os.name == 'posix',
110        "test meaningful only on posix systems")
111    @unittest.skipIf(sys.dont_write_bytecode,
112        "test meaningful only when writing bytecode")
113    def test_execute_bit_not_copied(self):
114        # Issue 6070: under posix .pyc files got their execute bit set if
115        # the .py file had the execute bit set, but they aren't executable.
116        oldmask = os.umask(022)
117        sys.path.insert(0, os.curdir)
118        try:
119            fname = TESTFN + os.extsep + "py"
120            f = open(fname, 'w').close()
121            os.chmod(fname, (stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH |
122                             stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))
123            __import__(TESTFN)
124            fn = fname + 'c'
125            if not os.path.exists(fn):
126                fn = fname + 'o'
127                if not os.path.exists(fn):
128                    self.fail("__import__ did not result in creation of "
129                              "either a .pyc or .pyo file")
130            s = os.stat(fn)
131            self.assertEqual(stat.S_IMODE(s.st_mode),
132                             stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
133        finally:
134            os.umask(oldmask)
135            remove_files(TESTFN)
136            unload(TESTFN)
137            del sys.path[0]
138
139    @unittest.skipIf(sys.dont_write_bytecode,
140        "test meaningful only when writing bytecode")
141    def test_rewrite_pyc_with_read_only_source(self):
142        # Issue 6074: a long time ago on posix, and more recently on Windows,
143        # a read only source file resulted in a read only pyc file, which
144        # led to problems with updating it later
145        sys.path.insert(0, os.curdir)
146        fname = TESTFN + os.extsep + "py"
147        try:
148            # Write a Python file, make it read-only and import it
149            with open(fname, 'w') as f:
150                f.write("x = 'original'\n")
151            # Tweak the mtime of the source to ensure pyc gets updated later
152            s = os.stat(fname)
153            os.utime(fname, (s.st_atime, s.st_mtime-100000000))
154            os.chmod(fname, 0400)
155            m1 = __import__(TESTFN)
156            self.assertEqual(m1.x, 'original')
157            # Change the file and then reimport it
158            os.chmod(fname, 0600)
159            with open(fname, 'w') as f:
160                f.write("x = 'rewritten'\n")
161            unload(TESTFN)
162            m2 = __import__(TESTFN)
163            self.assertEqual(m2.x, 'rewritten')
164            # Now delete the source file and check the pyc was rewritten
165            unlink(fname)
166            unload(TESTFN)
167            m3 = __import__(TESTFN)
168            self.assertEqual(m3.x, 'rewritten')
169        finally:
170            chmod_files(TESTFN)
171            remove_files(TESTFN)
172            unload(TESTFN)
173            del sys.path[0]
174
175    def test_imp_module(self):
176        # Verify that the imp module can correctly load and find .py files
177
178        # XXX (ncoghlan): It would be nice to use test_support.CleanImport
179        # here, but that breaks because the os module registers some
180        # handlers in copy_reg on import. Since CleanImport doesn't
181        # revert that registration, the module is left in a broken
182        # state after reversion. Reinitialising the module contents
183        # and just reverting os.environ to its previous state is an OK
184        # workaround
185        orig_path = os.path
186        orig_getenv = os.getenv
187        with EnvironmentVarGuard():
188            x = imp.find_module("os")
189            new_os = imp.load_module("os", *x)
190            self.assertIs(os, new_os)
191            self.assertIs(orig_path, new_os.path)
192            self.assertIsNot(orig_getenv, new_os.getenv)
193
194    def test_module_with_large_stack(self, module='longlist'):
195        # Regression test for http://bugs.python.org/issue561858.
196        filename = module + os.extsep + 'py'
197
198        # Create a file with a list of 65000 elements.
199        with open(filename, 'w+') as f:
200            f.write('d = [\n')
201            for i in range(65000):
202                f.write('"",\n')
203            f.write(']')
204
205        # Compile & remove .py file, we only need .pyc (or .pyo).
206        with open(filename, 'r') as f:
207            py_compile.compile(filename)
208        unlink(filename)
209
210        # Need to be able to load from current dir.
211        sys.path.append('')
212
213        # This used to crash.
214        exec 'import ' + module
215
216        # Cleanup.
217        del sys.path[-1]
218        unlink(filename + 'c')
219        unlink(filename + 'o')
220
221    def test_failing_import_sticks(self):
222        source = TESTFN + os.extsep + "py"
223        with open(source, "w") as f:
224            print >> f, "a = 1 // 0"
225
226        # New in 2.4, we shouldn't be able to import that no matter how often
227        # we try.
228        sys.path.insert(0, os.curdir)
229        try:
230            for i in [1, 2, 3]:
231                self.assertRaises(ZeroDivisionError, __import__, TESTFN)
232                self.assertNotIn(TESTFN, sys.modules,
233                                 "damaged module in sys.modules on %i try" % i)
234        finally:
235            del sys.path[0]
236            remove_files(TESTFN)
237
238    def test_failing_reload(self):
239        # A failing reload should leave the module object in sys.modules.
240        source = TESTFN + os.extsep + "py"
241        with open(source, "w") as f:
242            print >> f, "a = 1"
243            print >> f, "b = 2"
244
245        sys.path.insert(0, os.curdir)
246        try:
247            mod = __import__(TESTFN)
248            self.assertIn(TESTFN, sys.modules)
249            self.assertEqual(mod.a, 1, "module has wrong attribute values")
250            self.assertEqual(mod.b, 2, "module has wrong attribute values")
251
252            # On WinXP, just replacing the .py file wasn't enough to
253            # convince reload() to reparse it.  Maybe the timestamp didn't
254            # move enough.  We force it to get reparsed by removing the
255            # compiled file too.
256            remove_files(TESTFN)
257
258            # Now damage the module.
259            with open(source, "w") as f:
260                print >> f, "a = 10"
261                print >> f, "b = 20//0"
262
263            self.assertRaises(ZeroDivisionError, imp.reload, mod)
264
265            # But we still expect the module to be in sys.modules.
266            mod = sys.modules.get(TESTFN)
267            self.assertIsNot(mod, None, "expected module to be in sys.modules")
268
269            # We should have replaced a w/ 10, but the old b value should
270            # stick.
271            self.assertEqual(mod.a, 10, "module has wrong attribute values")
272            self.assertEqual(mod.b, 2, "module has wrong attribute values")
273
274        finally:
275            del sys.path[0]
276            remove_files(TESTFN)
277            unload(TESTFN)
278
279    def test_infinite_reload(self):
280        # http://bugs.python.org/issue742342 reports that Python segfaults
281        # (infinite recursion in C) when faced with self-recursive reload()ing.
282
283        sys.path.insert(0, os.path.dirname(__file__))
284        try:
285            import infinite_reload
286        finally:
287            del sys.path[0]
288
289    def test_import_name_binding(self):
290        # import x.y.z binds x in the current namespace.
291        import test as x
292        import test.test_support
293        self.assertIs(x, test, x.__name__)
294        self.assertTrue(hasattr(test.test_support, "__file__"))
295
296        # import x.y.z as w binds z as w.
297        import test.test_support as y
298        self.assertIs(y, test.test_support, y.__name__)
299
300    def test_import_initless_directory_warning(self):
301        with check_warnings(('', ImportWarning)):
302            # Just a random non-package directory we always expect to be
303            # somewhere in sys.path...
304            self.assertRaises(ImportError, __import__, "site-packages")
305
306    def test_import_by_filename(self):
307        path = os.path.abspath(TESTFN)
308        with self.assertRaises(ImportError) as c:
309            __import__(path)
310        self.assertEqual("Import by filename is not supported.",
311                         c.exception.args[0])
312
313    def test_import_in_del_does_not_crash(self):
314        # Issue 4236
315        testfn = script_helper.make_script('', TESTFN, textwrap.dedent("""\
316            import sys
317            class C:
318               def __del__(self):
319                  import imp
320            sys.argv.insert(0, C())
321            """))
322        try:
323            script_helper.assert_python_ok(testfn)
324        finally:
325            unlink(testfn)
326
327    def test_bug7732(self):
328        source = TESTFN + '.py'
329        os.mkdir(source)
330        try:
331            self.assertRaises((ImportError, IOError),
332                              imp.find_module, TESTFN, ["."])
333        finally:
334            os.rmdir(source)
335
336    def test_timestamp_overflow(self):
337        # A modification timestamp larger than 2**32 should not be a problem
338        # when importing a module (issue #11235).
339        sys.path.insert(0, os.curdir)
340        try:
341            source = TESTFN + ".py"
342            compiled = source + ('c' if __debug__ else 'o')
343            with open(source, 'w') as f:
344                pass
345            try:
346                os.utime(source, (2 ** 33 - 5, 2 ** 33 - 5))
347            except OverflowError:
348                self.skipTest("cannot set modification time to large integer")
349            except OSError as e:
350                if e.errno != getattr(errno, 'EOVERFLOW', None):
351                    raise
352                self.skipTest("cannot set modification time to large integer ({})".format(e))
353            __import__(TESTFN)
354            # The pyc file was created.
355            os.stat(compiled)
356        finally:
357            del sys.path[0]
358            remove_files(TESTFN)
359
360    def test_pyc_mtime(self):
361        # Test for issue #13863: .pyc timestamp sometimes incorrect on Windows.
362        sys.path.insert(0, os.curdir)
363        try:
364            # Jan 1, 2012; Jul 1, 2012.
365            mtimes = 1325376000, 1341100800
366
367            # Different names to avoid running into import caching.
368            tails = "spam", "eggs"
369            for mtime, tail in zip(mtimes, tails):
370                module = TESTFN + tail
371                source = module + ".py"
372                compiled = source + ('c' if __debug__ else 'o')
373
374                # Create a new Python file with the given mtime.
375                with open(source, 'w') as f:
376                    f.write("# Just testing\nx=1, 2, 3\n")
377                os.utime(source, (mtime, mtime))
378
379                # Generate the .pyc/o file; if it couldn't be created
380                # for some reason, skip the test.
381                m = __import__(module)
382                if not os.path.exists(compiled):
383                    unlink(source)
384                    self.skipTest("Couldn't create .pyc/.pyo file.")
385
386                # Actual modification time of .py file.
387                mtime1 = int(os.stat(source).st_mtime) & 0xffffffff
388
389                # mtime that was encoded in the .pyc file.
390                with open(compiled, 'rb') as f:
391                    mtime2 = struct.unpack('<L', f.read(8)[4:])[0]
392
393                unlink(compiled)
394                unlink(source)
395
396                self.assertEqual(mtime1, mtime2)
397        finally:
398            sys.path.pop(0)
399
400    def test_replace_parent_in_sys_modules(self):
401        dir_name = os.path.abspath(TESTFN)
402        os.mkdir(dir_name)
403        try:
404            pkg_dir = os.path.join(dir_name, 'sa')
405            os.mkdir(pkg_dir)
406            with open(os.path.join(pkg_dir, '__init__.py'), 'w') as init_file:
407                init_file.write("import v1")
408            with open(os.path.join(pkg_dir, 'v1.py'), 'w') as v1_file:
409                v1_file.write("import sys;"
410                              "sys.modules['sa'] = sys.modules[__name__];"
411                              "import sa")
412            sys.path.insert(0, dir_name)
413            # a segfault means the test failed!
414            import sa
415        finally:
416            rmtree(dir_name)
417
418    def test_fromlist_type(self):
419        with self.assertRaises(TypeError) as cm:
420            __import__('encodings', fromlist=[u'aliases'])
421        self.assertIn('must be str, not unicode', str(cm.exception))
422        with self.assertRaises(TypeError) as cm:
423            __import__('encodings', fromlist=[1])
424        self.assertIn('must be str, not int', str(cm.exception))
425
426
427class PycRewritingTests(unittest.TestCase):
428    # Test that the `co_filename` attribute on code objects always points
429    # to the right file, even when various things happen (e.g. both the .py
430    # and the .pyc file are renamed).
431
432    module_name = "unlikely_module_name"
433    module_source = """
434import sys
435code_filename = sys._getframe().f_code.co_filename
436module_filename = __file__
437constant = 1
438def func():
439    pass
440func_filename = func.func_code.co_filename
441"""
442    dir_name = os.path.abspath(TESTFN)
443    file_name = os.path.join(dir_name, module_name) + os.extsep + "py"
444    compiled_name = file_name + ("c" if __debug__ else "o")
445
446    def setUp(self):
447        self.sys_path = sys.path[:]
448        self.orig_module = sys.modules.pop(self.module_name, None)
449        os.mkdir(self.dir_name)
450        with open(self.file_name, "w") as f:
451            f.write(self.module_source)
452        sys.path.insert(0, self.dir_name)
453
454    def tearDown(self):
455        sys.path[:] = self.sys_path
456        if self.orig_module is not None:
457            sys.modules[self.module_name] = self.orig_module
458        else:
459            unload(self.module_name)
460        unlink(self.file_name)
461        unlink(self.compiled_name)
462        rmtree(self.dir_name)
463
464    def import_module(self):
465        ns = globals()
466        __import__(self.module_name, ns, ns)
467        return sys.modules[self.module_name]
468
469    def test_basics(self):
470        mod = self.import_module()
471        self.assertEqual(mod.module_filename, self.file_name)
472        self.assertEqual(mod.code_filename, self.file_name)
473        self.assertEqual(mod.func_filename, self.file_name)
474        del sys.modules[self.module_name]
475        mod = self.import_module()
476        if not sys.dont_write_bytecode:
477            self.assertEqual(mod.module_filename, self.compiled_name)
478        self.assertEqual(mod.code_filename, self.file_name)
479        self.assertEqual(mod.func_filename, self.file_name)
480
481    def test_incorrect_code_name(self):
482        py_compile.compile(self.file_name, dfile="another_module.py")
483        mod = self.import_module()
484        self.assertEqual(mod.module_filename, self.compiled_name)
485        self.assertEqual(mod.code_filename, self.file_name)
486        self.assertEqual(mod.func_filename, self.file_name)
487
488    def test_module_without_source(self):
489        target = "another_module.py"
490        py_compile.compile(self.file_name, dfile=target)
491        os.remove(self.file_name)
492        mod = self.import_module()
493        self.assertEqual(mod.module_filename, self.compiled_name)
494        self.assertEqual(mod.code_filename, target)
495        self.assertEqual(mod.func_filename, target)
496
497    def test_foreign_code(self):
498        py_compile.compile(self.file_name)
499        with open(self.compiled_name, "rb") as f:
500            header = f.read(8)
501            code = marshal.load(f)
502        constants = list(code.co_consts)
503        foreign_code = test_main.func_code
504        pos = constants.index(1)
505        constants[pos] = foreign_code
506        code = type(code)(code.co_argcount, code.co_nlocals, code.co_stacksize,
507                          code.co_flags, code.co_code, tuple(constants),
508                          code.co_names, code.co_varnames, code.co_filename,
509                          code.co_name, code.co_firstlineno, code.co_lnotab,
510                          code.co_freevars, code.co_cellvars)
511        with open(self.compiled_name, "wb") as f:
512            f.write(header)
513            marshal.dump(code, f)
514        mod = self.import_module()
515        self.assertEqual(mod.constant.co_filename, foreign_code.co_filename)
516
517
518class PathsTests(unittest.TestCase):
519    path = TESTFN
520
521    def setUp(self):
522        os.mkdir(self.path)
523        self.syspath = sys.path[:]
524
525    def tearDown(self):
526        rmtree(self.path)
527        sys.path[:] = self.syspath
528
529    # Regression test for http://bugs.python.org/issue1293.
530    def test_trailing_slash(self):
531        with open(os.path.join(self.path, 'test_trailing_slash.py'), 'w') as f:
532            f.write("testdata = 'test_trailing_slash'")
533        sys.path.append(self.path+'/')
534        mod = __import__("test_trailing_slash")
535        self.assertEqual(mod.testdata, 'test_trailing_slash')
536        unload("test_trailing_slash")
537
538    # Regression test for http://bugs.python.org/issue3677.
539    def _test_UNC_path(self):
540        with open(os.path.join(self.path, 'test_trailing_slash.py'), 'w') as f:
541            f.write("testdata = 'test_trailing_slash'")
542        # Create the UNC path, like \\myhost\c$\foo\bar.
543        path = os.path.abspath(self.path)
544        import socket
545        hn = socket.gethostname()
546        drive = path[0]
547        unc = "\\\\%s\\%s$"%(hn, drive)
548        unc += path[2:]
549        try:
550            os.listdir(unc)
551        except OSError as e:
552            if e.errno in (errno.EPERM, errno.EACCES):
553                # See issue #15338
554                self.skipTest("cannot access administrative share %r" % (unc,))
555            raise
556        sys.path.append(path)
557        mod = __import__("test_trailing_slash")
558        self.assertEqual(mod.testdata, 'test_trailing_slash')
559        unload("test_trailing_slash")
560
561    if sys.platform == "win32":
562        test_UNC_path = _test_UNC_path
563
564
565class RelativeImportTests(unittest.TestCase):
566
567    def tearDown(self):
568        unload("test.relimport")
569    setUp = tearDown
570
571    def test_relimport_star(self):
572        # This will import * from .test_import.
573        from . import relimport
574        self.assertTrue(hasattr(relimport, "RelativeImportTests"))
575
576    def test_issue3221(self):
577        # Regression test for http://bugs.python.org/issue3221.
578        def check_absolute():
579            exec "from os import path" in ns
580        def check_relative():
581            exec "from . import relimport" in ns
582
583        # Check both OK with __package__ and __name__ correct
584        ns = dict(__package__='test', __name__='test.notarealmodule')
585        check_absolute()
586        check_relative()
587
588        # Check both OK with only __name__ wrong
589        ns = dict(__package__='test', __name__='notarealpkg.notarealmodule')
590        check_absolute()
591        check_relative()
592
593        # Check relative fails with only __package__ wrong
594        ns = dict(__package__='foo', __name__='test.notarealmodule')
595        with check_warnings(('.+foo', RuntimeWarning)):
596            check_absolute()
597        self.assertRaises(SystemError, check_relative)
598
599        # Check relative fails with __package__ and __name__ wrong
600        ns = dict(__package__='foo', __name__='notarealpkg.notarealmodule')
601        with check_warnings(('.+foo', RuntimeWarning)):
602            check_absolute()
603        self.assertRaises(SystemError, check_relative)
604
605        # Check both fail with package set to a non-string
606        ns = dict(__package__=object())
607        self.assertRaises(ValueError, check_absolute)
608        self.assertRaises(ValueError, check_relative)
609
610    def test_absolute_import_without_future(self):
611        # If explicit relative import syntax is used, then do not try
612        # to perform an absolute import in the face of failure.
613        # Issue #7902.
614        with self.assertRaises(ImportError):
615            from .os import sep
616            self.fail("explicit relative import triggered an "
617                      "implicit absolute import")
618
619
620class TestSymbolicallyLinkedPackage(unittest.TestCase):
621    package_name = 'sample'
622
623    def setUp(self):
624        if os.path.exists(self.tagged):
625            shutil.rmtree(self.tagged)
626        if os.path.exists(self.package_name):
627            symlink_support.remove_symlink(self.package_name)
628        self.orig_sys_path = sys.path[:]
629
630        # create a sample package; imagine you have a package with a tag and
631        #  you want to symbolically link it from its untagged name.
632        os.mkdir(self.tagged)
633        init_file = os.path.join(self.tagged, '__init__.py')
634        open(init_file, 'w').close()
635        assert os.path.exists(init_file)
636
637        # now create a symlink to the tagged package
638        # sample -> sample-tagged
639        symlink_support.symlink(self.tagged, self.package_name)
640
641        assert os.path.isdir(self.package_name)
642        assert os.path.isfile(os.path.join(self.package_name, '__init__.py'))
643
644    @property
645    def tagged(self):
646        return self.package_name + '-tagged'
647
648    # regression test for issue6727
649    @unittest.skipUnless(
650        not hasattr(sys, 'getwindowsversion')
651        or sys.getwindowsversion() >= (6, 0),
652        "Windows Vista or later required")
653    @symlink_support.skip_unless_symlink
654    def test_symlinked_dir_importable(self):
655        # make sure sample can only be imported from the current directory.
656        sys.path[:] = ['.']
657
658        # and try to import the package
659        __import__(self.package_name)
660
661    def tearDown(self):
662        # now cleanup
663        if os.path.exists(self.package_name):
664            symlink_support.remove_symlink(self.package_name)
665        if os.path.exists(self.tagged):
666            shutil.rmtree(self.tagged)
667        sys.path[:] = self.orig_sys_path
668
669def test_main(verbose=None):
670    run_unittest(ImportTests, PycRewritingTests, PathsTests,
671        RelativeImportTests, TestSymbolicallyLinkedPackage)
672
673if __name__ == '__main__':
674    # Test needs to be a package, so we can do relative imports.
675    from test.test_import import test_main
676    test_main()
677