Home | History | Annotate | Download | only in test
      1 import importlib.util
      2 import os
      3 import py_compile
      4 import shutil
      5 import stat
      6 import sys
      7 import tempfile
      8 import unittest
      9 
     10 from test import support
     11 
     12 
     13 class PyCompileTests(unittest.TestCase):
     14 
     15     def setUp(self):
     16         self.directory = tempfile.mkdtemp()
     17         self.source_path = os.path.join(self.directory, '_test.py')
     18         self.pyc_path = self.source_path + 'c'
     19         self.cache_path = importlib.util.cache_from_source(self.source_path)
     20         self.cwd_drive = os.path.splitdrive(os.getcwd())[0]
     21         # In these tests we compute relative paths.  When using Windows, the
     22         # current working directory path and the 'self.source_path' might be
     23         # on different drives.  Therefore we need to switch to the drive where
     24         # the temporary source file lives.
     25         drive = os.path.splitdrive(self.source_path)[0]
     26         if drive:
     27             os.chdir(drive)
     28         with open(self.source_path, 'w') as file:
     29             file.write('x = 123\n')
     30 
     31     def tearDown(self):
     32         shutil.rmtree(self.directory)
     33         if self.cwd_drive:
     34             os.chdir(self.cwd_drive)
     35 
     36     def test_absolute_path(self):
     37         py_compile.compile(self.source_path, self.pyc_path)
     38         self.assertTrue(os.path.exists(self.pyc_path))
     39         self.assertFalse(os.path.exists(self.cache_path))
     40 
     41     def test_do_not_overwrite_symlinks(self):
     42         # In the face of a cfile argument being a symlink, bail out.
     43         # Issue #17222
     44         try:
     45             os.symlink(self.pyc_path + '.actual', self.pyc_path)
     46         except (NotImplementedError, OSError):
     47             self.skipTest('need to be able to create a symlink for a file')
     48         else:
     49             assert os.path.islink(self.pyc_path)
     50             with self.assertRaises(FileExistsError):
     51                 py_compile.compile(self.source_path, self.pyc_path)
     52 
     53     @unittest.skipIf(not os.path.exists(os.devnull) or os.path.isfile(os.devnull),
     54                      'requires os.devnull and for it to be a non-regular file')
     55     def test_do_not_overwrite_nonregular_files(self):
     56         # In the face of a cfile argument being a non-regular file, bail out.
     57         # Issue #17222
     58         with self.assertRaises(FileExistsError):
     59             py_compile.compile(self.source_path, os.devnull)
     60 
     61     def test_cache_path(self):
     62         py_compile.compile(self.source_path)
     63         self.assertTrue(os.path.exists(self.cache_path))
     64 
     65     def test_cwd(self):
     66         with support.change_cwd(self.directory):
     67             py_compile.compile(os.path.basename(self.source_path),
     68                                os.path.basename(self.pyc_path))
     69         self.assertTrue(os.path.exists(self.pyc_path))
     70         self.assertFalse(os.path.exists(self.cache_path))
     71 
     72     def test_relative_path(self):
     73         py_compile.compile(os.path.relpath(self.source_path),
     74                            os.path.relpath(self.pyc_path))
     75         self.assertTrue(os.path.exists(self.pyc_path))
     76         self.assertFalse(os.path.exists(self.cache_path))
     77 
     78     @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
     79                      'non-root user required')
     80     @unittest.skipIf(os.name == 'nt',
     81                      'cannot control directory permissions on Windows')
     82     def test_exceptions_propagate(self):
     83         # Make sure that exceptions raised thanks to issues with writing
     84         # bytecode.
     85         # http://bugs.python.org/issue17244
     86         mode = os.stat(self.directory)
     87         os.chmod(self.directory, stat.S_IREAD)
     88         try:
     89             with self.assertRaises(IOError):
     90                 py_compile.compile(self.source_path, self.pyc_path)
     91         finally:
     92             os.chmod(self.directory, mode.st_mode)
     93 
     94     def test_bad_coding(self):
     95         bad_coding = os.path.join(os.path.dirname(__file__), 'bad_coding2.py')
     96         with support.captured_stderr():
     97             self.assertIsNone(py_compile.compile(bad_coding, doraise=False))
     98         self.assertFalse(os.path.exists(
     99             importlib.util.cache_from_source(bad_coding)))
    100 
    101     @unittest.skipIf(sys.flags.optimize > 0, 'test does not work with -O')
    102     def test_double_dot_no_clobber(self):
    103         # http://bugs.python.org/issue22966
    104         # py_compile foo.bar.py -> __pycache__/foo.cpython-34.pyc
    105         weird_path = os.path.join(self.directory, 'foo.bar.py')
    106         cache_path = importlib.util.cache_from_source(weird_path)
    107         pyc_path = weird_path + 'c'
    108         head, tail = os.path.split(cache_path)
    109         penultimate_tail = os.path.basename(head)
    110         self.assertEqual(
    111             os.path.join(penultimate_tail, tail),
    112             os.path.join(
    113                 '__pycache__',
    114                 'foo.bar.{}.pyc'.format(sys.implementation.cache_tag)))
    115         with open(weird_path, 'w') as file:
    116             file.write('x = 123\n')
    117         py_compile.compile(weird_path)
    118         self.assertTrue(os.path.exists(cache_path))
    119         self.assertFalse(os.path.exists(pyc_path))
    120 
    121     def test_optimization_path(self):
    122         # Specifying optimized bytecode should lead to a path reflecting that.
    123         self.assertIn('opt-2', py_compile.compile(self.source_path, optimize=2))
    124 
    125 
    126 if __name__ == "__main__":
    127     unittest.main()
    128