blob: cee35a5b6b1121311e17a0947867417fcfe63fad [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
Sjoerd Mullender2e5168c1995-07-19 11:21:47 +00006import imp
Brett Cannon14581d52013-01-26 08:48:36 -05007import importlib._bootstrap
8import importlib.machinery
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:
108 cfile = imp.cache_from_source(file, debug_override=not optimize)
109 else:
110 cfile = imp.cache_from_source(file)
Brett Cannon33915eb2013-06-14 18:33:00 -0400111 if os.path.islink(cfile):
112 msg = ('{} is a symlink and will be changed into a regular file if '
113 'import writes a byte-compiled file to it')
114 raise FileExistsError(msg.format(file, cfile))
115 elif os.path.exists(cfile) and not os.path.isfile(cfile):
116 msg = ('{} is a non-regular file and will be changed into a regular '
117 'one if import writes a byte-compiled file to it')
118 raise FileExistsError(msg.format(file, cfile))
Brett Cannon14581d52013-01-26 08:48:36 -0500119 loader = importlib.machinery.SourceFileLoader('<py_compile>', file)
120 source_bytes = loader.get_data(file)
Guido van Rossumf984a651998-09-29 15:57:42 +0000121 try:
Brett Cannon14581d52013-01-26 08:48:36 -0500122 code = loader.source_to_code(source_bytes, dfile or file,
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400123 _optimize=optimize)
Guido van Rossumb940e112007-01-10 16:19:56 +0000124 except Exception as err:
Guido van Rossumbd4a63e2007-08-10 17:36:34 +0000125 py_exc = PyCompileError(err.__class__, err, dfile or file)
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000126 if doraise:
127 raise py_exc
128 else:
Georg Brandle537d6e2005-06-10 17:15:18 +0000129 sys.stderr.write(py_exc.msg + '\n')
Martin v. Löwis0c6774d2003-01-15 11:51:06 +0000130 return
Benjamin Peterson25216ba2010-05-08 19:52:21 +0000131 try:
Meador Inge22b9b372011-11-28 09:27:32 -0600132 dirname = os.path.dirname(cfile)
133 if dirname:
134 os.makedirs(dirname)
Brett Cannon14581d52013-01-26 08:48:36 -0500135 except FileExistsError:
136 pass
137 source_stats = loader.path_stats(file)
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400138 bytecode = importlib._bootstrap._code_to_bytecode(
139 code, source_stats['mtime'], source_stats['size'])
140 mode = importlib._bootstrap._calc_mode(file)
141 importlib._bootstrap._write_atomic(cfile, bytecode, mode)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000142 return cfile
Fred Drake61cf4402002-08-21 20:56:21 +0000143
Brett Cannonedfd6ae2013-04-14 12:48:15 -0400144
Fred Drake61cf4402002-08-21 20:56:21 +0000145def main(args=None):
146 """Compile several source files.
147
148 The files named in 'args' (or on the command line, if 'args' is
149 not specified) are compiled and the resulting bytecode is cached
150 in the normal manner. This function does not search a directory
151 structure to locate source files; it only compiles files named
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000152 explicitly. If '-' is the only parameter in args, the list of
153 files is taken from standard input.
Fred Drake61cf4402002-08-21 20:56:21 +0000154
155 """
156 if args is None:
157 args = sys.argv[1:]
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000158 rv = 0
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000159 if args == ['-']:
160 while True:
161 filename = sys.stdin.readline()
162 if not filename:
163 break
164 filename = filename.rstrip('\n')
165 try:
166 compile(filename, doraise=True)
167 except PyCompileError as error:
168 rv = 1
169 sys.stderr.write("%s\n" % error.msg)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200170 except OSError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000171 rv = 1
172 sys.stderr.write("%s\n" % error)
173 else:
174 for filename in args:
175 try:
176 compile(filename, doraise=True)
Matthias Klose1c994732010-04-20 19:48:04 +0000177 except PyCompileError as error:
Barry Warsawd5f9bf52010-03-31 21:36:22 +0000178 # return value to indicate at least one failure
179 rv = 1
180 sys.stderr.write(error.msg)
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000181 return rv
Tim Peters2c60f7a2003-01-29 03:49:43 +0000182
Fred Drake61cf4402002-08-21 20:56:21 +0000183if __name__ == "__main__":
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000184 sys.exit(main())