Patch #661719: Expose compilation errors as exceptions on request.
diff --git a/Lib/py_compile.py b/Lib/py_compile.py
index 2d5c36a..95d6a08 100644
--- a/Lib/py_compile.py
+++ b/Lib/py_compile.py
@@ -12,7 +12,54 @@
 
 MAGIC = imp.get_magic()
 
-__all__ = ["compile", "main"]
+__all__ = ["compile", "main", "PyCompileError"]
+
+
+class PyCompileError(Exception):
+    """Exception raised when an error occurs while attempting to
+    compile the file.
+
+    To raise this exception, use
+
+        raise PyCompileError(exc_type,exc_value,file[,msg])
+
+    where
+    
+        exc_type:   exception type to be used in error message
+                    type name can be accesses as class variable
+                    'exc_type_name'
+                  
+        exc_value:  exception value to be used in error message
+                    can be accesses as class variable 'exc_value'
+                 
+        file:       name of file being compiled to be used in error message
+                    can be accesses as class variable 'file'
+                 
+        msg:        string message to be written as error message
+                    If no value is given, a default exception message will be given,
+                    consistent with 'standard' py_compile output.
+                    message (or default) can be accesses as class variable 'msg'
+    
+    """
+    
+    def __init__(self, exc_type, exc_value, file, msg=''):
+        exc_type_name = exc_type.__name__
+        if exc_type is SyntaxError:
+            tbtext = ''.join(traceback.format_exception_only(exc_type, exc_value))
+            errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)
+        else:
+            errmsg = "Sorry: %s: %s" % (exc_type_name,exc_value)
+            
+        Exception.__init__(self,msg or errmsg,exc_type_name,exc_value,file)
+
+        self.exc_type_name = exc_type_name
+        self.exc_value = exc_value
+        self.file = file
+        self.msg = msg or errmsg
+
+    def __str__(self):
+        return self.msg
+
 
 # Define an internal helper according to the platform
 if os.name == "mac":
@@ -30,17 +77,24 @@
     f.write(chr((x >> 16) & 0xff))
     f.write(chr((x >> 24) & 0xff))
 
-def compile(file, cfile=None, dfile=None):
+def compile(file, cfile=None, dfile=None, doraise=False):
     """Byte-compile one Python source file to Python bytecode.
 
     Arguments:
 
-    file:  source filename
-    cfile: target filename; defaults to source with 'c' or 'o' appended
-           ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
-    dfile: purported filename; defaults to source (this is the filename
-           that will show up in error messages)
-
+    file:    source filename
+    cfile:   target filename; defaults to source with 'c' or 'o' appended
+             ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
+    dfile:   purported filename; defaults to source (this is the filename
+             that will show up in error messages)
+    doraise: flag indicating whether or not an exception should be
+             raised when a compile error is found. If an exception
+             occurs and this flag is set to False, a string
+             indicating the nature of the exception will be printed,
+             and the function will return to the caller. If an
+             exception occurs and this flag is set to True, a
+             PyCompileError exception will be raised.
+    
     Note that it isn't necessary to byte-compile Python modules for
     execution efficiency -- Python itself byte-compiles a module when
     it is loaded, and if it can, writes out the bytecode to the
@@ -68,13 +122,14 @@
     if codestring and codestring[-1] != '\n':
         codestring = codestring + '\n'
     try:
-        codeobject = __builtin__.compile(codestring, dfile or file, 'exec')
-    except SyntaxError, detail:
-        lines = traceback.format_exception_only(SyntaxError, detail)
-        for line in lines:
-            sys.stderr.write(line.replace('File "<string>"',
-                                          'File "%s"' % (dfile or file)))
-        return
+        codeobject = __builtin__.compile(codestring, dfile or file,'exec')
+    except Exception,err:
+        py_exc = PyCompileError(err.__class__,err.args,dfile or file)
+        if doraise:
+            raise py_exc
+        else:
+            sys.stderr.write(py_exc.msg)
+            return
     if cfile is None:
         cfile = file + (__debug__ and 'c' or 'o')
     fc = open(cfile, 'wb')
@@ -100,7 +155,10 @@
     if args is None:
         args = sys.argv[1:]
     for filename in args:
-        compile(filename)
-
+        try:
+            compile(filename, doraise=True)
+        except PyCompileError,err:
+            sys.stderr.write(err.msg)
+            
 if __name__ == "__main__":
     main()