blob: 1277b93ea5e37c1246ae008df8676d6149ff46ed [file] [log] [blame]
Guido van Rossum63566e21998-01-19 04:01:26 +00001"""Routine to "compile" a .py file to a .pyc (or .pyo) file.
2
3This module has intimate knowledge of the format of .pyc files.
4"""
Guido van Rossum3bb54481994-08-29 10:52:58 +00005
Brett Cannon14581d52013-01-26 08:48:36 -05006import importlib._bootstrap
7import 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
70 defaults to the PEP 3147 location.
71 :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
88 corresponding .pyc (or .pyo) file.
89
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,
93 and thus they won't be able to write the .pyc/.pyo file, and then
94 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 Cannondf960682013-06-15 14:07:21 -0400108 cfile = importlib.util.cache_from_source(file,
109 debug_override=not optimize)
Brett Cannon14581d52013-01-26 08:48:36 -0500110 else:
Brett Cannondf960682013-06-15 14:07:21 -0400111 cfile = importlib.util.cache_from_source(file)
Brett Cannon33915eb2013-06-14 18:33:00 -0400112 if os.path.islink(cfile):
113 msg = ('{} is a symlink and will be changed into a regular file if '
114 'import writes a byte-compiled file to it')
Brett Cannon9674bd02013-06-17 17:48:30 -0400115 raise FileExistsError(msg.format(cfile))
Brett Cannon33915eb2013-06-14 18:33:00 -0400116 elif os.path.exists(cfile) and not os.path.isfile(cfile):
117 msg = ('{} is a non-regular file and will be changed into a regular '
118 'one if import writes a byte-compiled file to it')
Brett Cannon9674bd02013-06-17 17:48:30 -0400119 raise FileExistsError(msg.format(cfile))
Brett Cannon14581d52013-01-26 08:48:36 -0500120 loader = importlib.machinery.SourceFileLoader('<py_compile>', file)
121 source_bytes = loader.get_data(file)
Guido van Rossumf984a651998-09-29 15:57:42 +0000122 try:
Brett Cannon14581d52013-01-26 08:48:36 -0500123 code = loader.source_to_code(source_bytes, dfile or file,
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400124 _optimize=optimize)
Guido van Rossumb940e112007-01-10 16:19:56 +0000125 except Exception as err:
Guido van Rossumbd4a63e2007-08-10 17:36:34 +0000126 py_exc = PyCompileError(err.__class__, err, dfile or file)
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000127 if doraise:
128 raise py_exc
129 else:
Georg Brandle537d6e2005-06-10 17:15:18 +0000130 sys.stderr.write(py_exc.msg + '\n')
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000131 return
Benjamin Peterson25216ba2010-05-08 19:52:21 +0000132 try:
Meador Inge22b9b372011-11-28 09:27:32 -0600133 dirname = os.path.dirname(cfile)
134 if dirname:
135 os.makedirs(dirname)
Brett Cannon14581d52013-01-26 08:48:36 -0500136 except FileExistsError:
137 pass
138 source_stats = loader.path_stats(file)
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400139 bytecode = importlib._bootstrap._code_to_bytecode(
140 code, source_stats['mtime'], source_stats['size'])
141 mode = importlib._bootstrap._calc_mode(file)
142 importlib._bootstrap._write_atomic(cfile, bytecode, mode)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000143 return cfile
Fred Drake61cf4402002-08-21 20:56:21 +0000144
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400145
Fred Drake61cf4402002-08-21 20:56:21 +0000146def main(args=None):
147 """Compile several source files.
148
149 The files named in 'args' (or on the command line, if 'args' is
150 not specified) are compiled and the resulting bytecode is cached
151 in the normal manner. This function does not search a directory
152 structure to locate source files; it only compiles files named
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000153 explicitly. If '-' is the only parameter in args, the list of
154 files is taken from standard input.
Fred Drake61cf4402002-08-21 20:56:21 +0000155
156 """
157 if args is None:
158 args = sys.argv[1:]
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000159 rv = 0
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000160 if args == ['-']:
161 while True:
162 filename = sys.stdin.readline()
163 if not filename:
164 break
165 filename = filename.rstrip('\n')
166 try:
167 compile(filename, doraise=True)
168 except PyCompileError as error:
169 rv = 1
170 sys.stderr.write("%s\n" % error.msg)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200171 except OSError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000172 rv = 1
173 sys.stderr.write("%s\n" % error)
174 else:
175 for filename in args:
176 try:
177 compile(filename, doraise=True)
Matthias Klose1c994732010-04-20 19:48:04 +0000178 except PyCompileError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000179 # return value to indicate at least one failure
180 rv = 1
181 sys.stderr.write(error.msg)
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000182 return rv
Tim Peters2c60f7a2003-01-29 03:49:43 +0000183
Fred Drake61cf4402002-08-21 20:56:21 +0000184if __name__ == "__main__":
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000185 sys.exit(main())