PageRenderTime 296ms CodeModel.GetById 121ms app.highlight 19ms RepoModel.GetById 142ms app.codeStats 0ms

/Lib/py_compile.py

http://unladen-swallow.googlecode.com/
Python | 168 lines | 168 code | 0 blank | 0 comment | 0 complexity | 4fc271715098bc38abd1d2edd909251b MD5 | raw file
  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    rv = 0
158    for filename in args:
159        try:
160            compile(filename, doraise=True)
161        except PyCompileError, err:
162            # return value to indicate at least one failure
163            rv = 1
164            sys.stderr.write(err.msg)
165    return rv
166
167if __name__ == "__main__":
168    sys.exit(main())