Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0c6774d

Browse files
committed
Patch #661719: Expose compilation errors as exceptions on request.
1 parent d69663d commit 0c6774d

5 files changed

Lines changed: 92 additions & 28 deletions

File tree

Doc/lib/libpycompile.tex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,22 @@ \section{\module{py_compile} ---
1919
permission to write the byte-code cache files in the directory
2020
containing the source code.
2121

22+
\begin{excdesc}{PyCompileError}
23+
Exception raised when an error occurs while attempting to compile the file.
24+
\end{excdesc}
2225

23-
\begin{funcdesc}{compile}{file\optional{, cfile\optional{, dfile}}}
26+
\begin{funcdesc}{compile}{file\optional{, cfile\optional{, dfile\optional{, doraise}}}}
2427
Compile a source file to byte-code and write out the byte-code cache
2528
file. The source code is loaded from the file name \var{file}. The
2629
byte-code is written to \var{cfile}, which defaults to \var{file}
2730
\code{+} \code{'c'} (\code{'o'} if optimization is enabled in the
2831
current interpreter). If \var{dfile} is specified, it is used as
2932
the name of the source file in error messages instead of \var{file}.
33+
If \var{doraise} = True, a PyCompileError is raised when an error is
34+
encountered while compiling \var{file}. If \var{doraise} = False (the default),
35+
an error string is written to sys.stderr, but no exception is raised.
3036
\end{funcdesc}
3137

32-
3338
\begin{funcdesc}{main}{\optional{args}}
3439
Compile several source files. The files named in \var{args} (or on
3540
the command line, if \var{args} is not specified) are compiled and

Lib/compileall.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,11 @@ def compile_dir(dir, maxlevels=10, ddir=None,
6262
if not quiet:
6363
print 'Compiling', fullname, '...'
6464
try:
65-
ok = py_compile.compile(fullname, None, dfile)
65+
ok = py_compile.compile(fullname, None, dfile, True)
6666
except KeyboardInterrupt:
6767
raise KeyboardInterrupt
68-
except:
69-
# XXX py_compile catches SyntaxErrors
70-
if type(sys.exc_type) == type(''):
71-
exc_type_name = sys.exc_type
72-
else: exc_type_name = sys.exc_type.__name__
73-
print 'Sorry:', exc_type_name + ':',
74-
print sys.exc_value
68+
except py_compile.PyCompileError,err:
69+
print err.msg
7570
success = 0
7671
else:
7772
if ok == 0:

Lib/py_compile.py

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,54 @@
1212

1313
MAGIC = imp.get_magic()
1414

15-
__all__ = ["compile", "main"]
15+
__all__ = ["compile", "main", "PyCompileError"]
16+
17+
18+
class 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+
1663

1764
# Define an internal helper according to the platform
1865
if os.name == "mac":
@@ -30,17 +77,24 @@ def wr_long(f, x):
3077
f.write(chr((x >> 16) & 0xff))
3178
f.write(chr((x >> 24) & 0xff))
3279

33-
def compile(file, cfile=None, dfile=None):
80+
def compile(file, cfile=None, dfile=None, doraise=False):
3481
"""Byte-compile one Python source file to Python bytecode.
3582
3683
Arguments:
3784
38-
file: source filename
39-
cfile: target filename; defaults to source with 'c' or 'o' appended
40-
('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
41-
dfile: purported filename; defaults to source (this is the filename
42-
that will show up in error messages)
43-
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+
4498
Note that it isn't necessary to byte-compile Python modules for
4599
execution efficiency -- Python itself byte-compiles a module when
46100
it is loaded, and if it can, writes out the bytecode to the
@@ -68,13 +122,14 @@ def compile(file, cfile=None, dfile=None):
68122
if codestring and codestring[-1] != '\n':
69123
codestring = codestring + '\n'
70124
try:
71-
codeobject = __builtin__.compile(codestring, dfile or file, 'exec')
72-
except SyntaxError, detail:
73-
lines = traceback.format_exception_only(SyntaxError, detail)
74-
for line in lines:
75-
sys.stderr.write(line.replace('File "<string>"',
76-
'File "%s"' % (dfile or file)))
77-
return
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)
132+
return
78133
if cfile is None:
79134
cfile = file + (__debug__ and 'c' or 'o')
80135
fc = open(cfile, 'wb')
@@ -100,7 +155,10 @@ def main(args=None):
100155
if args is None:
101156
args = sys.argv[1:]
102157
for filename in args:
103-
compile(filename)
104-
158+
try:
159+
compile(filename, doraise=True)
160+
except PyCompileError,err:
161+
sys.stderr.write(err.msg)
162+
105163
if __name__ == "__main__":
106164
main()

Lib/zipfile.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,10 @@ def _get_codename(self, pathname, basename):
604604
import py_compile
605605
if self.debug:
606606
print "Compiling", file_py
607-
py_compile.compile(file_py, file_pyc)
607+
try:
608+
py_compile.compile(file_py, file_pyc, None, True)
609+
except py_compile.PyCompileError,err:
610+
print err.msg
608611
fname = file_pyc
609612
else:
610613
fname = file_pyc

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Extension modules
7878
Library
7979
-------
8080

81+
- py_compile has a new 'doraise' flag and a new PyCompileError
82+
exception.
83+
8184
- SimpleXMLRPCServer now supports CGI through the CGIXMLRPCRequestHandler
8285
class.
8386

0 commit comments

Comments
 (0)