You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Merge branch 'python-3.3-to-3.5' into python-2.4
This commit is contained in:
25
.github/ISSUE_TEMPLATE/bug-report.md
vendored
25
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -4,7 +4,10 @@ about: Tell us about uncompyle6 bugs
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- __Note:__ Bugs are not for asking questions about a problem you
|
<!-- __Note:__ If you are using this program to do something illegal - don't.
|
||||||
|
The issue may flagged to make it easier for those looking for illegal activity.
|
||||||
|
|
||||||
|
Bugs are not for asking questions about a problem you
|
||||||
are trying to solve that involve the use of uncompyle6 along the way,
|
are trying to solve that involve the use of uncompyle6 along the way,
|
||||||
although I may be more tolerent of this if you sponsor the project.
|
although I may be more tolerent of this if you sponsor the project.
|
||||||
|
|
||||||
@@ -12,16 +15,22 @@ Also, the unless you are a sponsor of the project, it may take a
|
|||||||
while, maybe a week or so, before the bug report is noticed, let alone
|
while, maybe a week or so, before the bug report is noticed, let alone
|
||||||
acted upon.
|
acted upon.
|
||||||
|
|
||||||
To set expectations, some legitimate bugs can take years
|
To set expectations, some legitimate bugs can take years to fix, but
|
||||||
to fix, but they eventually do get fixed. Funding the project was
|
they eventually do get fixed.
|
||||||
added to address the problem that there are lots of people seeking
|
|
||||||
help and reporting bugs, but few people who are willing or capable of
|
|
||||||
providing help or fixing bugs.
|
|
||||||
|
|
||||||
Finally, have you read https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md
|
Funding the project was added to partially address the problem that there are
|
||||||
?
|
lots of people seeking help and reporting bugs, but few people who are
|
||||||
|
willing or capable of providing help or fixing bugs.
|
||||||
|
|
||||||
|
Tasks or the kinds of things others can do but you can't do or don't
|
||||||
|
want to do yourself are typically the kind of thing that you pay
|
||||||
|
someone to do, especially when you are the primary beneficiary of the
|
||||||
|
work, or the task is complex, long, or tedious. If your code is over
|
||||||
|
30 lines long, it fits into this category.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
Please remove any of the optional sections if they are not applicable.
|
Please remove any of the optional sections if they are not applicable.
|
||||||
|
|
||||||
Prerequisites/Caveats
|
Prerequisites/Caveats
|
||||||
|
@@ -263,7 +263,7 @@ See Also
|
|||||||
|
|
||||||
|
|
||||||
.. _Cython: https://en.wikipedia.org/wiki/Cython
|
.. _Cython: https://en.wikipedia.org/wiki/Cython
|
||||||
.. _trepan: https://pypi.python.org/pypi/trepan2g
|
.. _trepan: https://pypi.python.org/pypi/trepan3k
|
||||||
.. _compiler: https://pypi.python.org/pypi/spark_parser
|
.. _compiler: https://pypi.python.org/pypi/spark_parser
|
||||||
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
||||||
.. _debuggers: https://pypi.python.org/pypi/trepan3k
|
.. _debuggers: https://pypi.python.org/pypi/trepan3k
|
||||||
|
@@ -93,11 +93,11 @@ class Code(object):
|
|||||||
the diassembled code is stored in the attribute '_tokens'.
|
the diassembled code is stored in the attribute '_tokens'.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, co, scanner, classname=None):
|
def __init__(self, co, scanner, classname=None, show_asm=None):
|
||||||
for i in dir(co):
|
for i in dir(co):
|
||||||
if i.startswith("co_"):
|
if i.startswith("co_"):
|
||||||
setattr(self, i, getattr(co, i))
|
setattr(self, i, getattr(co, i))
|
||||||
self._tokens, self._customize = scanner.ingest(co, classname)
|
self._tokens, self._customize = scanner.ingest(co, classname, show_asm=show_asm)
|
||||||
|
|
||||||
|
|
||||||
class Scanner(object):
|
class Scanner(object):
|
||||||
|
@@ -194,6 +194,7 @@ class Scanner37Base(Scanner):
|
|||||||
Also, when we encounter certain tokens, we add them to a set which will cause custom
|
Also, when we encounter certain tokens, we add them to a set which will cause custom
|
||||||
grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST
|
grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST
|
||||||
cause specific rules for the specific number of arguments they take.
|
cause specific rules for the specific number of arguments they take.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def tokens_append(j, token):
|
def tokens_append(j, token):
|
||||||
@@ -455,7 +456,7 @@ class Scanner37Base(Scanner):
|
|||||||
# as CONTINUE, but that's okay since we add a grammar
|
# as CONTINUE, but that's okay since we add a grammar
|
||||||
# rule for that.
|
# rule for that.
|
||||||
pattr = argval
|
pattr = argval
|
||||||
target = self.get_target(inst.offset)
|
target = inst.argval
|
||||||
if target <= inst.offset:
|
if target <= inst.offset:
|
||||||
next_opname = self.insts[i + 1].opname
|
next_opname = self.insts[i + 1].opname
|
||||||
|
|
||||||
|
@@ -84,12 +84,15 @@ def customize_for_version3(self, version):
|
|||||||
"""List comprehensions in Python 3 when handled as a closure.
|
"""List comprehensions in Python 3 when handled as a closure.
|
||||||
See if we can combine code.
|
See if we can combine code.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# FIXME: DRY with comprehension_walk_newer
|
||||||
p = self.prec
|
p = self.prec
|
||||||
self.prec = 27
|
self.prec = 27
|
||||||
|
|
||||||
code_obj = node[1].attr
|
code_obj = node[1].attr
|
||||||
assert iscode(code_obj)
|
assert iscode(code_obj), node[1]
|
||||||
code = Code(code_obj, self.scanner, self.currentclass)
|
code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
|
||||||
|
|
||||||
ast = self.build_ast(code._tokens, code._customize, code)
|
ast = self.build_ast(code._tokens, code._customize, code)
|
||||||
self.customize(code._customize)
|
self.customize(code._customize)
|
||||||
|
|
||||||
@@ -103,6 +106,10 @@ def customize_for_version3(self, version):
|
|||||||
|
|
||||||
n = ast[1]
|
n = ast[1]
|
||||||
|
|
||||||
|
# Pick out important parts of the comprehension:
|
||||||
|
# * the variables we iterate over: "stores"
|
||||||
|
# * the results we accumulate: "n"
|
||||||
|
|
||||||
# collections is the name of the expression(s) we are iterating over
|
# collections is the name of the expression(s) we are iterating over
|
||||||
collections = [node[-3]]
|
collections = [node[-3]]
|
||||||
list_ifs = []
|
list_ifs = []
|
||||||
|
@@ -1160,13 +1160,15 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
n_classdefdeco2 = n_classdef
|
n_classdefdeco2 = n_classdef
|
||||||
|
|
||||||
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False):
|
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False,
|
||||||
|
debug_opts=None):
|
||||||
"""convert parse tree to Python source code"""
|
"""convert parse tree to Python source code"""
|
||||||
|
|
||||||
rn = self.return_none
|
rn = self.return_none
|
||||||
self.return_none = returnNone
|
self.return_none = returnNone
|
||||||
old_name = self.name
|
old_name = self.name
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.debug_opts = debug_opts
|
||||||
# if code would be empty, append 'pass'
|
# if code would be empty, append 'pass'
|
||||||
if len(ast) == 0:
|
if len(ast) == 0:
|
||||||
self.println(self.indent, "pass")
|
self.println(self.indent, "pass")
|
||||||
|
@@ -666,7 +666,12 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
has_none = "None" in code.co_names
|
has_none = "None" in code.co_names
|
||||||
rn = has_none and not find_none(ast)
|
rn = has_none and not find_none(ast)
|
||||||
self.gen_source(
|
self.gen_source(
|
||||||
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
|
ast,
|
||||||
|
code.co_name,
|
||||||
|
scanner_code._customize,
|
||||||
|
is_lambda=is_lambda,
|
||||||
|
returnNone=rn,
|
||||||
|
debug_opts=self.debug_opts,
|
||||||
)
|
)
|
||||||
|
|
||||||
# In obscure cases, a function may be a generator but the "yield"
|
# In obscure cases, a function may be a generator but the "yield"
|
||||||
|
@@ -37,7 +37,7 @@ from uncompyle6.show import maybe_show_tree_param_default
|
|||||||
|
|
||||||
def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
||||||
"""Dump function definition, doc string, and function body in
|
"""Dump function definition, doc string, and function body in
|
||||||
Python version 3.6 and above.
|
Python version 3.6 and above.
|
||||||
"""
|
"""
|
||||||
# MAKE_CLOSURE adds an additional closure slot
|
# MAKE_CLOSURE adds an additional closure slot
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
|
|
||||||
def build_param(ast, name, default, annotation=None):
|
def build_param(ast, name, default, annotation=None):
|
||||||
"""build parameters:
|
"""build parameters:
|
||||||
- handle defaults
|
- handle defaults
|
||||||
- handle format tuple parameters
|
- handle format tuple parameters
|
||||||
"""
|
"""
|
||||||
value = default
|
value = default
|
||||||
maybe_show_tree_param_default(self.showast, name, value)
|
maybe_show_tree_param_default(self.showast, name, value)
|
||||||
@@ -123,8 +123,6 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
kw_node = node[pos_args]
|
kw_node = node[pos_args]
|
||||||
if kw_node == "expr":
|
if kw_node == "expr":
|
||||||
kw_node = kw_node[0]
|
kw_node = kw_node[0]
|
||||||
if kw_node == "dict":
|
|
||||||
kw_pairs = kw_node[-1].attr
|
|
||||||
|
|
||||||
defparams = []
|
defparams = []
|
||||||
# FIXME: DRY with code below
|
# FIXME: DRY with code below
|
||||||
@@ -149,7 +147,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
code = code_node.attr
|
code = code_node.attr
|
||||||
|
|
||||||
assert iscode(code)
|
assert iscode(code)
|
||||||
scanner_code = Code(code, self.scanner, self.currentclass)
|
debug_opts = self.debug_opts["asm"] if self.debug_opts else None
|
||||||
|
scanner_code = Code(code, self.scanner, self.currentclass, debug_opts)
|
||||||
|
|
||||||
# add defaults values to parameter names
|
# add defaults values to parameter names
|
||||||
argc = code.co_argcount
|
argc = code.co_argcount
|
||||||
@@ -349,7 +348,12 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
has_none = "None" in code.co_names
|
has_none = "None" in code.co_names
|
||||||
rn = has_none and not find_none(ast)
|
rn = has_none and not find_none(ast)
|
||||||
self.gen_source(
|
self.gen_source(
|
||||||
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
|
ast,
|
||||||
|
code.co_name,
|
||||||
|
scanner_code._customize,
|
||||||
|
is_lambda=is_lambda,
|
||||||
|
returnNone=rn,
|
||||||
|
debug_opts=self.debug_opts,
|
||||||
)
|
)
|
||||||
|
|
||||||
# In obscure cases, a function may be a generator but the "yield"
|
# In obscure cases, a function may be a generator but the "yield"
|
||||||
|
@@ -183,6 +183,8 @@ from uncompyle6.show import maybe_show_tree
|
|||||||
from uncompyle6.util import better_repr
|
from uncompyle6.util import better_repr
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
|
||||||
|
|
||||||
|
|
||||||
class SourceWalkerError(Exception):
|
class SourceWalkerError(Exception):
|
||||||
def __init__(self, errmsg):
|
def __init__(self, errmsg):
|
||||||
@@ -645,7 +647,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
attr = node.attr
|
attr = node.attr
|
||||||
data = node.pattr
|
data = node.pattr
|
||||||
datatype = type(data)
|
datatype = type(data)
|
||||||
if isinstance(data, float) :
|
if isinstance(data, float):
|
||||||
self.write(better_repr(data, self.version))
|
self.write(better_repr(data, self.version))
|
||||||
elif isinstance(data, complex):
|
elif isinstance(data, complex):
|
||||||
self.write(better_repr(data, self.version))
|
self.write(better_repr(data, self.version))
|
||||||
@@ -1176,10 +1178,11 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
"""
|
"""
|
||||||
p = self.prec
|
p = self.prec
|
||||||
self.prec = 27
|
self.prec = 27
|
||||||
code = node[code_index].attr
|
|
||||||
|
|
||||||
assert iscode(code), node[code_index]
|
code_obj = node[code_index].attr
|
||||||
code = Code(code, self.scanner, self.currentclass)
|
assert iscode(code_obj), node[code_index]
|
||||||
|
|
||||||
|
code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
|
||||||
|
|
||||||
ast = self.build_ast(code._tokens, code._customize, code)
|
ast = self.build_ast(code._tokens, code._customize, code)
|
||||||
self.customize(code._customize)
|
self.customize(code._customize)
|
||||||
@@ -2423,13 +2426,22 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.classes.pop(-1)
|
self.classes.pop(-1)
|
||||||
|
|
||||||
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False):
|
def gen_source(
|
||||||
|
self,
|
||||||
|
ast,
|
||||||
|
name,
|
||||||
|
customize,
|
||||||
|
is_lambda=False,
|
||||||
|
returnNone=False,
|
||||||
|
debug_opts=DEFAULT_DEBUG_OPTS,
|
||||||
|
):
|
||||||
"""convert SyntaxTree to Python source code"""
|
"""convert SyntaxTree to Python source code"""
|
||||||
|
|
||||||
rn = self.return_none
|
rn = self.return_none
|
||||||
self.return_none = returnNone
|
self.return_none = returnNone
|
||||||
old_name = self.name
|
old_name = self.name
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.debug_opts = debug_opts
|
||||||
# if code would be empty, append 'pass'
|
# if code would be empty, append 'pass'
|
||||||
if len(ast) == 0:
|
if len(ast) == 0:
|
||||||
self.println(self.indent, "pass")
|
self.println(self.indent, "pass")
|
||||||
@@ -2523,10 +2535,6 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
return MAP.get(node, MAP_DIRECT)
|
return MAP.get(node, MAP_DIRECT)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
|
|
||||||
|
|
||||||
|
|
||||||
def code_deparse(
|
def code_deparse(
|
||||||
co,
|
co,
|
||||||
out=sys.stdout,
|
out=sys.stdout,
|
||||||
@@ -2621,7 +2629,9 @@ def code_deparse(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# What we've been waiting for: Generate source from Syntax Tree!
|
# What we've been waiting for: Generate source from Syntax Tree!
|
||||||
deparsed.gen_source(deparsed.ast, co.co_name, customize)
|
deparsed.gen_source(
|
||||||
|
deparsed.ast, name=co.co_name, customize=customize, debug_opts=debug_opts
|
||||||
|
)
|
||||||
|
|
||||||
for g in sorted(deparsed.mod_globs):
|
for g in sorted(deparsed.mod_globs):
|
||||||
deparsed.write("# global %s ## Warning: Unused global\n" % g)
|
deparsed.write("# global %s ## Warning: Unused global\n" % g)
|
||||||
|
Reference in New Issue
Block a user