You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Add deparse_code_with_fragments_and_map and simplify
This commit is contained in:
@@ -11,20 +11,14 @@ src_dir = get_srcdir()
|
|||||||
os.chdir(src_dir)
|
os.chdir(src_dir)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(("test_tuple", "function_to_test"), [
|
@pytest.mark.parametrize(("test_tuple"), [
|
||||||
(
|
|
||||||
('../test/bytecode_2.7/05_if.pyc', 'testdata/if-2.7.right',),
|
('../test/bytecode_2.7/05_if.pyc', 'testdata/if-2.7.right',),
|
||||||
disassemble_file
|
|
||||||
),
|
|
||||||
(
|
|
||||||
('../test/bytecode_2.7/05_ifelse.pyc', 'testdata/ifelse-2.7.right',),
|
('../test/bytecode_2.7/05_ifelse.pyc', 'testdata/ifelse-2.7.right',),
|
||||||
disassemble_file
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
def test_funcoutput(capfd, test_tuple, function_to_test):
|
def test_funcoutput(capfd, test_tuple):
|
||||||
|
|
||||||
in_file, filename_expected = test_tuple
|
in_file, filename_expected = test_tuple
|
||||||
function_to_test(in_file, native=False)
|
disassemble_file(in_file)
|
||||||
resout, reserr = capfd.readouterr()
|
resout, reserr = capfd.readouterr()
|
||||||
expected = open(filename_expected, "r").read()
|
expected = open(filename_expected, "r").read()
|
||||||
if resout != expected:
|
if resout != expected:
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2016 by Rocky Bernstein
|
# Copyright (c) 2015-2016, 2818 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
# Copyright (c) 1999 John Aycock
|
# Copyright (c) 1999 John Aycock
|
||||||
@@ -13,7 +13,7 @@ that is doing the extraction.
|
|||||||
|
|
||||||
Second, we need structured instruction information for the
|
Second, we need structured instruction information for the
|
||||||
(de)-parsing step. Python 3.4 and up provides this, but we still do
|
(de)-parsing step. Python 3.4 and up provides this, but we still do
|
||||||
want to run on Python 2.7.
|
want to run on earlier Python versions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
@@ -23,7 +23,6 @@ from collections import deque
|
|||||||
|
|
||||||
import uncompyle6
|
import uncompyle6
|
||||||
|
|
||||||
from xdis.main import disassemble_file as xdisassemble_file
|
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
from xdis.load import check_object_path, load_module
|
from xdis.load import check_object_path, load_module
|
||||||
from uncompyle6.scanner import get_scanner
|
from uncompyle6.scanner import get_scanner
|
||||||
@@ -65,17 +64,13 @@ def disco_loop(disasm, queue, real_out):
|
|||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def disassemble_file(filename, outstream=None, native=False):
|
def disassemble_file(filename, outstream=None):
|
||||||
"""
|
"""
|
||||||
disassemble Python byte-code file (.pyc)
|
disassemble Python byte-code file (.pyc)
|
||||||
|
|
||||||
If given a Python source file (".py") file, we'll
|
If given a Python source file (".py") file, we'll
|
||||||
try to find the corresponding compiled object.
|
try to find the corresponding compiled object.
|
||||||
"""
|
"""
|
||||||
if native:
|
|
||||||
xdisassemble_file(filename, outstream)
|
|
||||||
return
|
|
||||||
|
|
||||||
filename = check_object_path(filename)
|
filename = check_object_path(filename)
|
||||||
(version, timestamp, magic_int, co, is_pypy,
|
(version, timestamp, magic_int, co, is_pypy,
|
||||||
source_size) = load_module(filename)
|
source_size) = load_module(filename)
|
||||||
@@ -90,14 +85,14 @@ def _test():
|
|||||||
"""Simple test program to disassemble a file."""
|
"""Simple test program to disassemble a file."""
|
||||||
argc = len(sys.argv)
|
argc = len(sys.argv)
|
||||||
if argc != 2:
|
if argc != 2:
|
||||||
if argc == 1 and uncompyle6.PYTHON3:
|
if argc == 1:
|
||||||
fn = __file__
|
fn = __file__
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__)
|
sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__)
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
else:
|
else:
|
||||||
fn = sys.argv[1]
|
fn = sys.argv[1]
|
||||||
disassemble_file(fn, native=True)
|
disassemble_file(fn)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
_test()
|
_test()
|
||||||
|
@@ -1643,7 +1643,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
|
def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
|
||||||
showgrammar=False, is_pypy=False):
|
showgrammar=False, is_pypy=False, walker=FragmentsWalker):
|
||||||
"""
|
"""
|
||||||
Convert the code object co into a python source fragment.
|
Convert the code object co into a python source fragment.
|
||||||
|
|
||||||
@@ -1683,7 +1683,8 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
|
|||||||
|
|
||||||
# Build AST from disassembly.
|
# Build AST from disassembly.
|
||||||
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
|
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
|
||||||
deparsed = FragmentsWalker(version, scanner, showast=showast, debug_parser=debug_parser)
|
deparsed = walker(version, scanner, showast=showast,
|
||||||
|
debug_parser=debug_parser)
|
||||||
|
|
||||||
deparsed.ast = deparsed.build_ast(tokens, customize)
|
deparsed.ast = deparsed.build_ast(tokens, customize)
|
||||||
|
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
|
# Copyright (c) 2018 by Rocky Bernstein
|
||||||
from uncompyle6.semantics.pysource import SourceWalker, deparse_code
|
from uncompyle6.semantics.pysource import SourceWalker, deparse_code
|
||||||
|
import uncompyle6.semantics.fragments as fragments
|
||||||
|
|
||||||
# FIXME: does this handle nested code, and lambda properly
|
# FIXME: does this handle nested code, and lambda properly
|
||||||
class LineMapWalker(SourceWalker):
|
class LineMapWalker(SourceWalker):
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
if 'first_line' not in kwargs:
|
|
||||||
first_line = 0
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(LineMapWalker, self).__init__(*args, **kwargs)
|
super(LineMapWalker, self).__init__(*args, **kwargs)
|
||||||
self.source_linemap = {}
|
self.source_linemap = {}
|
||||||
@@ -28,6 +27,12 @@ class LineMapWalker(SourceWalker):
|
|||||||
self.source_linemap[self.current_line_number] = node.linestart
|
self.source_linemap[self.current_line_number] = node.linestart
|
||||||
return super(LineMapWalker, self).default(node)
|
return super(LineMapWalker, self).default(node)
|
||||||
|
|
||||||
|
class LineMapFragmentWalker(fragments.FragmentsWalker, LineMapWalker):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(LineMapFragmentWalker, self).__init__(*args, **kwargs)
|
||||||
|
self.source_linemap = {}
|
||||||
|
self.current_line_number = 0
|
||||||
|
|
||||||
def deparse_code_with_map(*args, **kwargs):
|
def deparse_code_with_map(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Like deparse_code but saves line number correspondences.
|
Like deparse_code but saves line number correspondences.
|
||||||
@@ -35,13 +40,21 @@ def deparse_code_with_map(*args, **kwargs):
|
|||||||
kwargs['walker'] = LineMapWalker
|
kwargs['walker'] = LineMapWalker
|
||||||
return deparse_code(*args, **kwargs)
|
return deparse_code(*args, **kwargs)
|
||||||
|
|
||||||
|
def deparse_code_with_fragments_and_map(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Like deparse_code_with_map but saves fragments.
|
||||||
|
"""
|
||||||
|
kwargs['walker'] = LineMapFragmentWalker
|
||||||
|
return fragments.deparse_code(*args, **kwargs)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
def deparse_test(co):
|
def deparse_test(co):
|
||||||
"This is a docstring"
|
"This is a docstring"
|
||||||
import sys
|
import sys
|
||||||
sys_version = float(sys.version[0:3])
|
sys_version = float(sys.version[0:3])
|
||||||
# deparsed = deparse_code(sys_version, co, showasm=True, showast=True)
|
# deparsed = deparse_code(sys_version, co, showasm=True, showast=True)
|
||||||
deparsed = deparse_code_with_map(sys_version, co, showasm=False, showast=False,
|
deparsed = deparse_code_with_map(sys_version, co, showasm=False,
|
||||||
|
showast=False,
|
||||||
showgrammar=False)
|
showgrammar=False)
|
||||||
a = 1; b = 2
|
a = 1; b = 2
|
||||||
print("\n")
|
print("\n")
|
||||||
@@ -49,5 +62,16 @@ if __name__ == '__main__':
|
|||||||
for line_no in
|
for line_no in
|
||||||
sorted(deparsed.source_linemap.keys())]
|
sorted(deparsed.source_linemap.keys())]
|
||||||
print(linemap)
|
print(linemap)
|
||||||
|
deparsed = deparse_code_with_fragments_and_map(sys_version,
|
||||||
|
co, showasm=False,
|
||||||
|
showast=False,
|
||||||
|
showgrammar=False)
|
||||||
|
a = 1; b = 2
|
||||||
|
print("\n")
|
||||||
|
linemap2 = [(line_no, deparsed.source_linemap[line_no])
|
||||||
|
for line_no in
|
||||||
|
sorted(deparsed.source_linemap.keys())]
|
||||||
|
print(linemap2)
|
||||||
|
assert linemap == linemap2
|
||||||
return
|
return
|
||||||
deparse_test(deparse_test.__code__)
|
deparse_test(deparse_test.__code__)
|
||||||
|
Reference in New Issue
Block a user