Python3 try/except handling improvements. Add Walker exception and use

that: fixes erroneous uncompyle success message on parse error.
This commit is contained in:
rocky
2015-12-26 00:12:02 -05:00
parent 0409cee6a9
commit fe9c8d5734
7 changed files with 74 additions and 35 deletions

Binary file not shown.

View File

@@ -5,23 +5,28 @@
try:
x = 1
except RuntimeError as e:
y = 2
except:
pass
# # Tests:
# # trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
# # try_middle COME_FROM
# # except_stmt ::= except_cond1 except_suite
# # except_suite ::= ...
# Tests:
# trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
# try_middle COME_FROM
# except_stmt ::= except_cond1 except_suite
# except_suite ::= ...
# try:
# x = 1
# except ImportError:
# pass
try:
x = 1
except ImportError:
pass
# try:
# x = 2
# except ImportError:
# x = 3
# finally:
# x = 4
try:
x = 2
except ImportError:
x = 3
finally:
x = 4
try:
x = 1
except ImportError as e:
x = 2

View File

@@ -1,6 +1,13 @@
def handle(module):
try:
module = 1
except ImportError as exc:
module = exc
return module
try:
pass
except ImportError as exc:
pass
finally:
del exc
y = 1

View File

@@ -27,8 +27,10 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
try:
pysource.deparse_code(version, co, out, showasm, showast, showgrammar)
except pysource.ParserError as e : # parser failed, dump disassembly
print(e, file=real_out)
except pysource.WalkerError as e:
# deparsing failed
if real_out != out:
print(e, file=real_out)
raise
def uncompyle_file(filename, outstream=None, showasm=False, showast=False,

View File

@@ -81,8 +81,10 @@ def_op('BINARY_TRUE_DIVIDE', 27)
def_op('INPLACE_FLOOR_DIVIDE', 28)
def_op('INPLACE_TRUE_DIVIDE', 29)
# Gone from Python 3 are
# Python 2's SLICE+0 .. SLICE+3
# Gone from Python 3 are Python2's
# SLICE+0 .. SLICE+3
# STORE_SLICE+0 .. STORE_SLICE+3
# DELETE_SLICE+0 .. DELETE_SLICE+3
def_op('STORE_MAP', 54)
def_op('INPLACE_ADD', 55)

View File

@@ -449,6 +449,7 @@ class Python3Parser(PythonParser):
except_stmt ::= except_cond1 except_suite
except_stmt ::= except_cond2 except_suite
except_stmt ::= except_cond2 except_suite_finalize
except_stmt ::= except
# Python3 introduced POP_EXCEPT
@@ -457,10 +458,11 @@ class Python3Parser(PythonParser):
# This is used in Python 3 in
# "except ... as e" to remove 'e' after the c_stmts_opt finishes
except_suite ::= SETUP_FINALLY c_stmts_opt
POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM LOAD_CONST
STORE_NAME DELETE_NAME END_FINALLY
JUMP_FORWARD
except_suite_finalize ::= SETUP_FINALLY c_stmts_opt except_var_finalize
END_FINALLY JUMP_FORWARD
except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM LOAD_CONST
designator del_stmt
except_suite ::= return_stmts

View File

@@ -63,7 +63,6 @@ from __future__ import print_function
import inspect, sys, re
from uncompyle6 import PYTHON3
from uncompyle6.parser import get_python_parser
from uncompyle6.parsers.astnode import AST
@@ -124,9 +123,14 @@ TAB = ' ' *4 # is less spacy than "\t"
INDENT_PER_LEVEL = ' ' # additional intent per pretty-print level
TABLE_R = {
'POP_TOP': ( '%|%c\n', 0 ),
'STORE_ATTR': ( '%c.%[1]{pattr}', 0),
# 'STORE_SUBSCR': ( '%c[%c]', 0, 1 ),
'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ),
# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ),
}
if not PYTHON3:
TABLE_R.update({
'STORE_SLICE+0': ( '%c[:]', 0 ),
'STORE_SLICE+1': ( '%c[%p:]', 0, (1, 100) ),
'STORE_SLICE+2': ( '%c[:%p]', 0, (1, 100) ),
@@ -135,9 +139,8 @@ TABLE_R = {
'DELETE_SLICE+1': ( '%|del %c[%c:]\n', 0, 1 ),
'DELETE_SLICE+2': ( '%|del %c[:%c]\n', 0, 1 ),
'DELETE_SLICE+3': ( '%|del %c[%c:%c]\n', 0, 1, 2 ),
'DELETE_ATTR': ( '%|del %c.%[-1]{pattr}\n', 0 ),
# 'EXEC_STMT': ( '%|exec %c in %[1]C\n', 0, (0,maxint,', ') ),
}
})
TABLE_R0 = {
# 'BUILD_LIST': ( '[%C]', (0,-1,', ') ),
# 'BUILD_TUPLE': ( '(%C)', (0,-1,', ') ),
@@ -317,6 +320,7 @@ TABLE_DIRECT = {
'except_cond1': ( '%|except %c:\n', 1 ),
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ),
'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ),
'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ),
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 3),
@@ -438,7 +442,6 @@ class ParserError(python_parser.ParserError):
lines.extend( ['', str(self.error)] )
return '\n'.join(lines)
def find_globals(node, globs):
"""Find globals in this statement."""
for n in node:
@@ -467,6 +470,13 @@ def find_none(node):
return True
return False
class WalkerError(Exception):
def __init__(self, errmsg):
self.errmsg = errmsg
def __str__(self):
return self.errmsg
class Walker(GenericASTTraversal, object):
stacked_params = ('f', 'indent', 'isLambda', '_globals')
@@ -1233,8 +1243,6 @@ class Walker(GenericASTTraversal, object):
# self.print_("-----")
# self.print(startnode)
# from trepan.api import debug
# debug(start_opts={'startup-profile': True})
fmt = entry[0]
arg = 1
@@ -1262,7 +1270,18 @@ class Walker(GenericASTTraversal, object):
elif typ == ',':
pass
elif typ == 'c':
self.preorder(node[entry[arg]])
# FIXME: In Python3 sometimes like from
# importfrom
# importlist2
# import_as
# designator
# STORE_NAME 'load_entry_point'
# POP_TOP '' (2, (0, 1))
# we get that weird POP_TOP tuple, e.g (2, (0,1)).
# Why? and
# Is there some sort of invalid bounds access going on?
if isinstance(entry[arg], int):
self.preorder(node[entry[arg]])
arg += 1
elif typ == 'p':
p = self.prec
@@ -1637,6 +1656,8 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
for g in deparsed.mod_globs:
deparsed.write('# global %s ## Warning: Unused global' % g)
if deparsed.ERROR:
raise WalkerError("Deparsing stopped due to parse error")
return deparsed
if __name__ == '__main__':