py_compile.py revision e537d6e93e0b5c37a96090df9ec831bd1bf8e2fb
1"""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""" 5 6import __builtin__ 7import imp 8import marshal 9import os 10import sys 11import traceback 12 13MAGIC = imp.get_magic() 14 15__all__ = ["compile", "main", "PyCompileError"] 16 17 18class PyCompileError(Exception): 19 """Exception raised when an error occurs while attempting to 20 compile the file. 21 22 To raise this exception, use 23 24 raise PyCompileError(exc_type,exc_value,file[,msg]) 25 26 where 27 28 exc_type: exception type to be used in error message 29 type name can be accesses as class variable 30 'exc_type_name' 31 32 exc_value: exception value to be used in error message 33 can be accesses as class variable 'exc_value' 34 35 file: name of file being compiled to be used in error message 36 can be accesses as class variable 'file' 37 38 msg: string message to be written as error message 39 If no value is given, a default exception message will be given, 40 consistent with 'standard' py_compile output. 41 message (or default) can be accesses as class variable 'msg' 42 43 """ 44 45 def __init__(self, exc_type, exc_value, file, msg=''): 46 exc_type_name = exc_type.__name__ 47 if exc_type is SyntaxError: 48 tbtext = ''.join(traceback.format_exception_only(exc_type, exc_value)) 49 errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file) 50 else: 51 errmsg = "Sorry: %s: %s" % (exc_type_name,exc_value) 52 53 Exception.__init__(self,msg or errmsg,exc_type_name,exc_value,file) 54 55 self.exc_type_name = exc_type_name 56 self.exc_value = exc_value 57 self.file = file 58 self.msg = msg or errmsg 59 60 def __str__(self): 61 return self.msg 62 63 64# Define an internal helper according to the platform 65if os.name == "mac": 66 import MacOS 67 def set_creator_type(file): 68 MacOS.SetCreatorAndType(file, 'Pyth', 'PYC ') 69else: 70 def set_creator_type(file): 71 pass 72 73def wr_long(f, x): 74 """Internal; write a 32-bit int to a file in little-endian order.""" 75 f.write(chr( x & 0xff)) 76 f.write(chr((x >> 8) & 0xff)) 77 f.write(chr((x >> 16) & 0xff)) 78 f.write(chr((x >> 24) & 0xff)) 79 80def compile(file, cfile=None, dfile=None, doraise=False): 81 """Byte-compile one Python source file to Python bytecode. 82 83 Arguments: 84 85 file: source filename 86 cfile: target filename; defaults to source with 'c' or 'o' appended 87 ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo) 88 dfile: purported filename; defaults to source (this is the filename 89 that will show up in error messages) 90 doraise: flag indicating whether or not an exception should be 91 raised when a compile error is found. If an exception 92 occurs and this flag is set to False, a string 93 indicating the nature of the exception will be printed, 94 and the function will return to the caller. If an 95 exception occurs and this flag is set to True, a 96 PyCompileError exception will be raised. 97 98 Note that it isn't necessary to byte-compile Python modules for 99 execution efficiency -- Python itself byte-compiles a module when 100 it is loaded, and if it can, writes out the bytecode to the 101 corresponding .pyc (or .pyo) file. 102 103 However, if a Python installation is shared between users, it is a 104 good idea to byte-compile all modules upon installation, since 105 other users may not be able to write in the source directories, 106 and thus they won't be able to write the .pyc/.pyo file, and then 107 they would be byte-compiling every module each time it is loaded. 108 This can slow down program start-up considerably. 109 110 See compileall.py for a script/module that uses this module to 111 byte-compile all installed files (or all files in selected 112 directories). 113 114 """ 115 f = open(file, 'U') 116 try: 117 timestamp = long(os.fstat(f.fileno()).st_mtime) 118 except AttributeError: 119 timestamp = long(os.stat(file).st_mtime) 120 codestring = f.read() 121 f.close() 122 if codestring and codestring[-1] != '\n': 123 codestring = codestring + '\n' 124 try: 125 codeobject = __builtin__.compile(codestring, dfile or file,'exec') 126 except Exception,err: 127 py_exc = PyCompileError(err.__class__,err.args,dfile or file) 128 if doraise: 129 raise py_exc 130 else: 131 sys.stderr.write(py_exc.msg + '\n') 132 return 133 if cfile is None: 134 cfile = file + (__debug__ and 'c' or 'o') 135 fc = open(cfile, 'wb') 136 fc.write('\0\0\0\0') 137 wr_long(fc, timestamp) 138 marshal.dump(codeobject, fc) 139 fc.flush() 140 fc.seek(0, 0) 141 fc.write(MAGIC) 142 fc.close() 143 set_creator_type(cfile) 144 145def 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 152 explicitly. 153 154 """ 155 if args is None: 156 args = sys.argv[1:] 157 for filename in args: 158 try: 159 compile(filename, doraise=True) 160 except PyCompileError,err: 161 sys.stderr.write(err.msg) 162 163if __name__ == "__main__": 164 main() 165