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: try:
x = 1 x = 1
except RuntimeError as e: except:
y = 2 pass
# # Tests: # Tests:
# # trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK # trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
# # try_middle COME_FROM # try_middle COME_FROM
# # except_stmt ::= except_cond1 except_suite # except_stmt ::= except_cond1 except_suite
# # except_suite ::= ... # except_suite ::= ...
# try: try:
# x = 1 x = 1
# except ImportError: except ImportError:
# pass pass
# try: try:
# x = 2 x = 2
# except ImportError: except ImportError:
# x = 3 x = 3
# finally: finally:
# x = 4 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: try:
pass pass
except ImportError as exc: except ImportError as exc:
pass pass
finally: finally:
del exc y = 1

View File

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

View File

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

View File

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

View File

@@ -63,7 +63,6 @@ from __future__ import print_function
import inspect, sys, re import inspect, sys, re
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
from uncompyle6.parser import get_python_parser from uncompyle6.parser import get_python_parser
from uncompyle6.parsers.astnode import AST 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 INDENT_PER_LEVEL = ' ' # additional intent per pretty-print level
TABLE_R = { TABLE_R = {
'POP_TOP': ( '%|%c\n', 0 ),
'STORE_ATTR': ( '%c.%[1]{pattr}', 0), 'STORE_ATTR': ( '%c.%[1]{pattr}', 0),
# 'STORE_SUBSCR': ( '%c[%c]', 0, 1 ), # '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+0': ( '%c[:]', 0 ),
'STORE_SLICE+1': ( '%c[%p:]', 0, (1, 100) ), 'STORE_SLICE+1': ( '%c[%p:]', 0, (1, 100) ),
'STORE_SLICE+2': ( '%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+1': ( '%|del %c[%c:]\n', 0, 1 ),
'DELETE_SLICE+2': ( '%|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_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 = { TABLE_R0 = {
# 'BUILD_LIST': ( '[%C]', (0,-1,', ') ), # 'BUILD_LIST': ( '[%C]', (0,-1,', ') ),
# 'BUILD_TUPLE': ( '(%C)', (0,-1,', ') ), # 'BUILD_TUPLE': ( '(%C)', (0,-1,', ') ),
@@ -317,6 +320,7 @@ TABLE_DIRECT = {
'except_cond1': ( '%|except %c:\n', 1 ), 'except_cond1': ( '%|except %c:\n', 1 ),
'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), '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 ), 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 5 ),
'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
'withasstmt': ( '%|with %c as %c:\n%+%c%-', 0, 2, 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)] ) lines.extend( ['', str(self.error)] )
return '\n'.join(lines) return '\n'.join(lines)
def find_globals(node, globs): def find_globals(node, globs):
"""Find globals in this statement.""" """Find globals in this statement."""
for n in node: for n in node:
@@ -467,6 +470,13 @@ def find_none(node):
return True return True
return False return False
class WalkerError(Exception):
def __init__(self, errmsg):
self.errmsg = errmsg
def __str__(self):
return self.errmsg
class Walker(GenericASTTraversal, object): class Walker(GenericASTTraversal, object):
stacked_params = ('f', 'indent', 'isLambda', '_globals') stacked_params = ('f', 'indent', 'isLambda', '_globals')
@@ -1233,8 +1243,6 @@ class Walker(GenericASTTraversal, object):
# self.print_("-----") # self.print_("-----")
# self.print(startnode) # self.print(startnode)
# from trepan.api import debug
# debug(start_opts={'startup-profile': True})
fmt = entry[0] fmt = entry[0]
arg = 1 arg = 1
@@ -1262,6 +1270,17 @@ class Walker(GenericASTTraversal, object):
elif typ == ',': elif typ == ',':
pass pass
elif typ == 'c': elif typ == 'c':
# 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]]) self.preorder(node[entry[arg]])
arg += 1 arg += 1
elif typ == 'p': elif typ == 'p':
@@ -1637,6 +1656,8 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
for g in deparsed.mod_globs: for g in deparsed.mod_globs:
deparsed.write('# global %s ## Warning: Unused global' % g) deparsed.write('# global %s ## Warning: Unused global' % g)
if deparsed.ERROR:
raise WalkerError("Deparsing stopped due to parse error")
return deparsed return deparsed
if __name__ == '__main__': if __name__ == '__main__':