1import importlib.util 2import os 3import py_compile 4import shutil 5import stat 6import sys 7import tempfile 8import unittest 9 10from test import support 11 12 13class 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 126if __name__ == "__main__": 127 unittest.main() 128