mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Patch #661719: Expose compilation errors as exceptions on request.
This commit is contained in:
		
							parent
							
								
									d69663d300
								
							
						
					
					
						commit
						0c6774d92b
					
				
					 5 changed files with 92 additions and 28 deletions
				
			
		| 
						 | 
					@ -19,17 +19,22 @@ modules for shared use, especially if some of the users may not have
 | 
				
			||||||
permission to write the byte-code cache files in the directory
 | 
					permission to write the byte-code cache files in the directory
 | 
				
			||||||
containing the source code.
 | 
					containing the source code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{excdesc}{PyCompileError}
 | 
				
			||||||
 | 
					Exception raised when an error occurs while attempting to compile the file.
 | 
				
			||||||
 | 
					\end{excdesc}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\begin{funcdesc}{compile}{file\optional{, cfile\optional{, dfile}}}
 | 
					\begin{funcdesc}{compile}{file\optional{, cfile\optional{, dfile\optional{, doraise}}}}
 | 
				
			||||||
  Compile a source file to byte-code and write out the byte-code cache 
 | 
					  Compile a source file to byte-code and write out the byte-code cache 
 | 
				
			||||||
  file.  The source code is loaded from the file name \var{file}.  The 
 | 
					  file.  The source code is loaded from the file name \var{file}.  The 
 | 
				
			||||||
  byte-code is written to \var{cfile}, which defaults to \var{file}
 | 
					  byte-code is written to \var{cfile}, which defaults to \var{file}
 | 
				
			||||||
  \code{+} \code{'c'} (\code{'o'} if optimization is enabled in the
 | 
					  \code{+} \code{'c'} (\code{'o'} if optimization is enabled in the
 | 
				
			||||||
  current interpreter).  If \var{dfile} is specified, it is used as
 | 
					  current interpreter).  If \var{dfile} is specified, it is used as
 | 
				
			||||||
  the name of the source file in error messages instead of \var{file}. 
 | 
					  the name of the source file in error messages instead of \var{file}. 
 | 
				
			||||||
 | 
					  If \var{doraise} = True, a PyCompileError is raised when an error is 
 | 
				
			||||||
 | 
					  encountered while compiling \var{file}. If \var{doraise} = False (the default), 
 | 
				
			||||||
 | 
					  an error string is written to sys.stderr, but no exception is raised.
 | 
				
			||||||
\end{funcdesc}
 | 
					\end{funcdesc}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
\begin{funcdesc}{main}{\optional{args}}
 | 
					\begin{funcdesc}{main}{\optional{args}}
 | 
				
			||||||
  Compile several source files.  The files named in \var{args} (or on
 | 
					  Compile several source files.  The files named in \var{args} (or on
 | 
				
			||||||
  the command line, if \var{args} is not specified) are compiled and
 | 
					  the command line, if \var{args} is not specified) are compiled and
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,16 +62,11 @@ def compile_dir(dir, maxlevels=10, ddir=None,
 | 
				
			||||||
                if not quiet:
 | 
					                if not quiet:
 | 
				
			||||||
                    print 'Compiling', fullname, '...'
 | 
					                    print 'Compiling', fullname, '...'
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    ok = py_compile.compile(fullname, None, dfile)
 | 
					                    ok = py_compile.compile(fullname, None, dfile, True)
 | 
				
			||||||
                except KeyboardInterrupt:
 | 
					                except KeyboardInterrupt:
 | 
				
			||||||
                    raise KeyboardInterrupt
 | 
					                    raise KeyboardInterrupt
 | 
				
			||||||
                except:
 | 
					                except py_compile.PyCompileError,err:
 | 
				
			||||||
                    # XXX py_compile catches SyntaxErrors
 | 
					                    print err.msg
 | 
				
			||||||
                    if type(sys.exc_type) == type(''):
 | 
					 | 
				
			||||||
                        exc_type_name = sys.exc_type
 | 
					 | 
				
			||||||
                    else: exc_type_name = sys.exc_type.__name__
 | 
					 | 
				
			||||||
                    print 'Sorry:', exc_type_name + ':',
 | 
					 | 
				
			||||||
                    print sys.exc_value
 | 
					 | 
				
			||||||
                    success = 0
 | 
					                    success = 0
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    if ok == 0:
 | 
					                    if ok == 0:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,54 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAGIC = imp.get_magic()
 | 
					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
 | 
					# Define an internal helper according to the platform
 | 
				
			||||||
if os.name == "mac":
 | 
					if os.name == "mac":
 | 
				
			||||||
| 
						 | 
					@ -30,7 +77,7 @@ def wr_long(f, x):
 | 
				
			||||||
    f.write(chr((x >> 16) & 0xff))
 | 
					    f.write(chr((x >> 16) & 0xff))
 | 
				
			||||||
    f.write(chr((x >> 24) & 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.
 | 
					    """Byte-compile one Python source file to Python bytecode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Arguments:
 | 
					    Arguments:
 | 
				
			||||||
| 
						 | 
					@ -40,6 +87,13 @@ def compile(file, cfile=None, dfile=None):
 | 
				
			||||||
             ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
 | 
					             ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
 | 
				
			||||||
    dfile:   purported filename; defaults to source (this is the filename
 | 
					    dfile:   purported filename; defaults to source (this is the filename
 | 
				
			||||||
             that will show up in error messages)
 | 
					             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
 | 
					    Note that it isn't necessary to byte-compile Python modules for
 | 
				
			||||||
    execution efficiency -- Python itself byte-compiles a module when
 | 
					    execution efficiency -- Python itself byte-compiles a module when
 | 
				
			||||||
| 
						 | 
					@ -68,12 +122,13 @@ def compile(file, cfile=None, dfile=None):
 | 
				
			||||||
    if codestring and codestring[-1] != '\n':
 | 
					    if codestring and codestring[-1] != '\n':
 | 
				
			||||||
        codestring = codestring + '\n'
 | 
					        codestring = codestring + '\n'
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        codeobject = __builtin__.compile(codestring, dfile or file, 'exec')
 | 
					        codeobject = __builtin__.compile(codestring, dfile or file,'exec')
 | 
				
			||||||
    except SyntaxError, detail:
 | 
					    except Exception,err:
 | 
				
			||||||
        lines = traceback.format_exception_only(SyntaxError, detail)
 | 
					        py_exc = PyCompileError(err.__class__,err.args,dfile or file)
 | 
				
			||||||
        for line in lines:
 | 
					        if doraise:
 | 
				
			||||||
            sys.stderr.write(line.replace('File "<string>"',
 | 
					            raise py_exc
 | 
				
			||||||
                                          'File "%s"' % (dfile or file)))
 | 
					        else:
 | 
				
			||||||
 | 
					            sys.stderr.write(py_exc.msg)
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
    if cfile is None:
 | 
					    if cfile is None:
 | 
				
			||||||
        cfile = file + (__debug__ and 'c' or 'o')
 | 
					        cfile = file + (__debug__ and 'c' or 'o')
 | 
				
			||||||
| 
						 | 
					@ -100,7 +155,10 @@ def main(args=None):
 | 
				
			||||||
    if args is None:
 | 
					    if args is None:
 | 
				
			||||||
        args = sys.argv[1:]
 | 
					        args = sys.argv[1:]
 | 
				
			||||||
    for filename in args:
 | 
					    for filename in args:
 | 
				
			||||||
        compile(filename)
 | 
					        try:
 | 
				
			||||||
 | 
					            compile(filename, doraise=True)
 | 
				
			||||||
 | 
					        except PyCompileError,err:
 | 
				
			||||||
 | 
					            sys.stderr.write(err.msg)
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -604,7 +604,10 @@ def _get_codename(self, pathname, basename):
 | 
				
			||||||
            import py_compile
 | 
					            import py_compile
 | 
				
			||||||
            if self.debug:
 | 
					            if self.debug:
 | 
				
			||||||
                print "Compiling", file_py
 | 
					                print "Compiling", file_py
 | 
				
			||||||
            py_compile.compile(file_py, file_pyc)
 | 
					            try:
 | 
				
			||||||
 | 
					                py_compile.compile(file_py, file_pyc, None, True)
 | 
				
			||||||
 | 
					            except py_compile.PyCompileError,err:
 | 
				
			||||||
 | 
					                print err.msg
 | 
				
			||||||
            fname = file_pyc
 | 
					            fname = file_pyc
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            fname = file_pyc
 | 
					            fname = file_pyc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,9 @@ Extension modules
 | 
				
			||||||
Library
 | 
					Library
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- py_compile has a new 'doraise' flag and a new PyCompileError
 | 
				
			||||||
 | 
					  exception.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- SimpleXMLRPCServer now supports CGI through the CGIXMLRPCRequestHandler
 | 
					- SimpleXMLRPCServer now supports CGI through the CGIXMLRPCRequestHandler
 | 
				
			||||||
  class.
 | 
					  class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue