You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Python3 try/except handling improvements. Add Walker exception and use
that: fixes erroneous uncompyle success message on parse error.
This commit is contained in:
BIN
test/bytecode_3.4/05_try_except.pyc
Normal file
BIN
test/bytecode_3.4/05_try_except.pyc
Normal file
Binary file not shown.
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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__':
|
||||
|
Reference in New Issue
Block a user