blob: 11c5b505cc68523834114f221b56f46c26191be7 [file] [log] [blame]
Brett Cannonf299abd2015-04-13 14:21:02 -04001"""Routine to "compile" a .py file to a .pyc file.
Guido van Rossum63566e21998-01-19 04:01:26 +00002
3This module has intimate knowledge of the format of .pyc files.
4"""
Guido van Rossum3bb54481994-08-29 10:52:58 +00005
Eric Snow32439d62015-05-02 19:15:18 -06006import importlib._bootstrap_external
Brett Cannon14581d52013-01-26 08:48:36 -05007import importlib.machinery
Brett Cannondf960682013-06-15 14:07:21 -04008import importlib.util
Fred Drakea96f1a32002-08-21 20:23:22 +00009import os
Brett Cannon33915eb2013-06-14 18:33:00 -040010import os.path
Fred Drakea96f1a32002-08-21 20:23:22 +000011import sys
12import traceback
13
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000014__all__ = ["compile", "main", "PyCompileError"]
15
16
17class PyCompileError(Exception):
18 """Exception raised when an error occurs while attempting to
19 compile the file.
20
21 To raise this exception, use
22
23 raise PyCompileError(exc_type,exc_value,file[,msg])
24
25 where
Tim Peters2c60f7a2003-01-29 03:49:43 +000026
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000027 exc_type: exception type to be used in error message
28 type name can be accesses as class variable
29 'exc_type_name'
Tim Peters2c60f7a2003-01-29 03:49:43 +000030
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000031 exc_value: exception value to be used in error message
32 can be accesses as class variable 'exc_value'
Tim Peters2c60f7a2003-01-29 03:49:43 +000033
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000034 file: name of file being compiled to be used in error message
35 can be accesses as class variable 'file'
Tim Peters2c60f7a2003-01-29 03:49:43 +000036
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000037 msg: string message to be written as error message
Barry Warsaw28a691b2010-04-17 00:19:56 +000038 If no value is given, a default exception message will be
39 given, consistent with 'standard' py_compile output.
40 message (or default) can be accesses as class variable
41 'msg'
Tim Peters2c60f7a2003-01-29 03:49:43 +000042
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000043 """
Tim Peters2c60f7a2003-01-29 03:49:43 +000044
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000045 def __init__(self, exc_type, exc_value, file, msg=''):
46 exc_type_name = exc_type.__name__
47 if exc_type is SyntaxError:
Barry Warsaw28a691b2010-04-17 00:19:56 +000048 tbtext = ''.join(traceback.format_exception_only(
49 exc_type, exc_value))
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000050 errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)
51 else:
52 errmsg = "Sorry: %s: %s" % (exc_type_name,exc_value)
Tim Peters2c60f7a2003-01-29 03:49:43 +000053
Martin v. Löwis0c6774d2003-01-15 11:51:06 +000054 Exception.__init__(self,msg or errmsg,exc_type_name,exc_value,file)
55
56 self.exc_type_name = exc_type_name
57 self.exc_value = exc_value
58 self.file = file
59 self.msg = msg or errmsg
60
61 def __str__(self):
62 return self.msg
63
Skip Montanaroc62c81e2001-02-12 02:00:42 +000064
Georg Brandl8334fd92010-12-04 10:26:46 +000065def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
Guido van Rossum63566e21998-01-19 04:01:26 +000066 """Byte-compile one Python source file to Python bytecode.
67
Barry Warsaw28a691b2010-04-17 00:19:56 +000068 :param file: The source file name.
69 :param cfile: The target byte compiled file name. When not given, this
Brett Cannonf299abd2015-04-13 14:21:02 -040070 defaults to the PEP 3147/PEP 488 location.
Barry Warsaw28a691b2010-04-17 00:19:56 +000071 :param dfile: Purported file name, i.e. the file name that shows up in
72 error messages. Defaults to the source file name.
73 :param doraise: Flag indicating whether or not an exception should be
74 raised when a compile error is found. If an exception occurs and this
75 flag is set to False, a string indicating the nature of the exception
76 will be printed, and the function will return to the caller. If an
77 exception occurs and this flag is set to True, a PyCompileError
78 exception will be raised.
Georg Brandl8334fd92010-12-04 10:26:46 +000079 :param optimize: The optimization level for the compiler. Valid values
80 are -1, 0, 1 and 2. A value of -1 means to use the optimization
81 level of the current interpreter, as given by -O command line options.
82
Barry Warsaw28a691b2010-04-17 00:19:56 +000083 :return: Path to the resulting byte compiled file.
Tim Peters2c60f7a2003-01-29 03:49:43 +000084
Guido van Rossum63566e21998-01-19 04:01:26 +000085 Note that it isn't necessary to byte-compile Python modules for
86 execution efficiency -- Python itself byte-compiles a module when
87 it is loaded, and if it can, writes out the bytecode to the
Brett Cannonf299abd2015-04-13 14:21:02 -040088 corresponding .pyc file.
Guido van Rossum63566e21998-01-19 04:01:26 +000089
90 However, if a Python installation is shared between users, it is a
91 good idea to byte-compile all modules upon installation, since
92 other users may not be able to write in the source directories,
Brett Cannonf299abd2015-04-13 14:21:02 -040093 and thus they won't be able to write the .pyc file, and then
Guido van Rossum63566e21998-01-19 04:01:26 +000094 they would be byte-compiling every module each time it is loaded.
95 This can slow down program start-up considerably.
96
97 See compileall.py for a script/module that uses this module to
98 byte-compile all installed files (or all files in selected
99 directories).
Brett Cannon33915eb2013-06-14 18:33:00 -0400100
101 Do note that FileExistsError is raised if cfile ends up pointing at a
102 non-regular file or symlink. Because the compilation uses a file renaming,
103 the resulting file would be regular and thus not the same type of file as
104 it was previously.
Guido van Rossum63566e21998-01-19 04:01:26 +0000105 """
Brett Cannon14581d52013-01-26 08:48:36 -0500106 if cfile is None:
107 if optimize >= 0:
Brett Cannonf299abd2015-04-13 14:21:02 -0400108 optimization = optimize if optimize >= 1 else ''
Brett Cannondf960682013-06-15 14:07:21 -0400109 cfile = importlib.util.cache_from_source(file,
Brett Cannonf299abd2015-04-13 14:21:02 -0400110 optimization=optimization)
Brett Cannon14581d52013-01-26 08:48:36 -0500111 else:
Brett Cannondf960682013-06-15 14:07:21 -0400112 cfile = importlib.util.cache_from_source(file)
Brett Cannon33915eb2013-06-14 18:33:00 -0400113 if os.path.islink(cfile):
114 msg = ('{} is a symlink and will be changed into a regular file if '
115 'import writes a byte-compiled file to it')
Brett Cannon9674bd02013-06-17 17:48:30 -0400116 raise FileExistsError(msg.format(cfile))
Brett Cannon33915eb2013-06-14 18:33:00 -0400117 elif os.path.exists(cfile) and not os.path.isfile(cfile):
118 msg = ('{} is a non-regular file and will be changed into a regular '
119 'one if import writes a byte-compiled file to it')
Brett Cannon9674bd02013-06-17 17:48:30 -0400120 raise FileExistsError(msg.format(cfile))
Brett Cannon14581d52013-01-26 08:48:36 -0500121 loader = importlib.machinery.SourceFileLoader('<py_compile>', file)
122 source_bytes = loader.get_data(file)
Guido van Rossumf984a651998-09-29 15:57:42 +0000123 try:
Brett Cannon14581d52013-01-26 08:48:36 -0500124 code = loader.source_to_code(source_bytes, dfile or file,
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400125 _optimize=optimize)
Guido van Rossumb940e112007-01-10 16:19:56 +0000126 except Exception as err:
Guido van Rossumbd4a63e2007-08-10 17:36:34 +0000127 py_exc = PyCompileError(err.__class__, err, dfile or file)
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000128 if doraise:
129 raise py_exc
130 else:
Georg Brandle537d6e2005-06-10 17:15:18 +0000131 sys.stderr.write(py_exc.msg + '\n')
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000132 return
Benjamin Peterson25216ba2010-05-08 19:52:21 +0000133 try:
Meador Inge22b9b372011-11-28 09:27:32 -0600134 dirname = os.path.dirname(cfile)
135 if dirname:
136 os.makedirs(dirname)
Brett Cannon14581d52013-01-26 08:48:36 -0500137 except FileExistsError:
138 pass
139 source_stats = loader.path_stats(file)
Eric Snow32439d62015-05-02 19:15:18 -0600140 bytecode = importlib._bootstrap_external._code_to_bytecode(
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400141 code, source_stats['mtime'], source_stats['size'])
Eric Snow32439d62015-05-02 19:15:18 -0600142 mode = importlib._bootstrap_external._calc_mode(file)
143 importlib._bootstrap_external._write_atomic(cfile, bytecode, mode)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000144 return cfile
Fred Drake61cf4402002-08-21 20:56:21 +0000145
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400146
Fred Drake61cf4402002-08-21 20:56:21 +0000147def main(args=None):
148 """Compile several source files.
149
150 The files named in 'args' (or on the command line, if 'args' is
151 not specified) are compiled and the resulting bytecode is cached
152 in the normal manner. This function does not search a directory
153 structure to locate source files; it only compiles files named
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000154 explicitly. If '-' is the only parameter in args, the list of
155 files is taken from standard input.
Fred Drake61cf4402002-08-21 20:56:21 +0000156
157 """
158 if args is None:
159 args = sys.argv[1:]
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000160 rv = 0
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000161 if args == ['-']:
162 while True:
163 filename = sys.stdin.readline()
164 if not filename:
165 break
166 filename = filename.rstrip('\n')
167 try:
168 compile(filename, doraise=True)
169 except PyCompileError as error:
170 rv = 1
171 sys.stderr.write("%s\n" % error.msg)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200172 except OSError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000173 rv = 1
174 sys.stderr.write("%s\n" % error)
175 else:
176 for filename in args:
177 try:
178 compile(filename, doraise=True)
Matthias Klose1c994732010-04-20 19:48:04 +0000179 except PyCompileError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000180 # return value to indicate at least one failure
181 rv = 1
Berker Peksag34c9be72015-04-14 18:57:55 +0300182 sys.stderr.write("%s\n" % error.msg)
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000183 return rv
Tim Peters2c60f7a2003-01-29 03:49:43 +0000184
Fred Drake61cf4402002-08-21 20:56:21 +0000185if __name__ == "__main__":
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000186 sys.exit(main())