You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
New feature: show line number correspondences
Option --linemap on uncompile show how original source-code line numbers map to uncompiled source lines
This commit is contained in:
2
setup.py
2
setup.py
@@ -24,6 +24,6 @@ setup(
|
|||||||
py_modules = py_modules,
|
py_modules = py_modules,
|
||||||
test_suite = 'nose.collector',
|
test_suite = 'nose.collector',
|
||||||
url = web,
|
url = web,
|
||||||
test_requires = ['nose>=1.0'],
|
tests_require = ['nose>=1.0'],
|
||||||
version = VERSION,
|
version = VERSION,
|
||||||
zip_safe = zip_safe)
|
zip_safe = zip_safe)
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, os, getopt, tempfile, time
|
import sys, os, getopt, time
|
||||||
|
|
||||||
program, ext = os.path.splitext(os.path.basename(__file__))
|
program, ext = os.path.splitext(os.path.basename(__file__))
|
||||||
|
|
||||||
@@ -35,7 +35,8 @@ Options:
|
|||||||
-p <integer> use <integer> number of processes
|
-p <integer> use <integer> number of processes
|
||||||
-r recurse directories looking for .pyc and .pyo files
|
-r recurse directories looking for .pyc and .pyo files
|
||||||
--verify compare generated source with input byte-code
|
--verify compare generated source with input byte-code
|
||||||
(requires -o)
|
--linemaps generated line number correspondencies between byte-code
|
||||||
|
and generated source output
|
||||||
--help show this message
|
--help show this message
|
||||||
|
|
||||||
Debugging Options:
|
Debugging Options:
|
||||||
@@ -81,8 +82,8 @@ def main_bin():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
||||||
'help asm grammar recurse timestamp tree verify version '
|
'help asm grammar linemaps recurse timestamp tree '
|
||||||
'showgrammar'.split(' '))
|
'verify version showgrammar'.split(' '))
|
||||||
except getopt.GetoptError as e:
|
except getopt.GetoptError as e:
|
||||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
@@ -97,6 +98,8 @@ def main_bin():
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif opt == '--verify':
|
elif opt == '--verify':
|
||||||
options['do_verify'] = True
|
options['do_verify'] = True
|
||||||
|
elif opt == '--linemaps':
|
||||||
|
options['do_linemaps'] = True
|
||||||
elif opt in ('--asm', '-a'):
|
elif opt in ('--asm', '-a'):
|
||||||
options['showasm'] = 'after'
|
options['showasm'] = 'after'
|
||||||
options['do_verify'] = False
|
options['do_verify'] = False
|
||||||
@@ -146,11 +149,7 @@ def main_bin():
|
|||||||
usage()
|
usage()
|
||||||
|
|
||||||
if outfile == '-':
|
if outfile == '-':
|
||||||
if 'do_verify' in options and options['do_verify'] and len(files) == 1:
|
outfile = None # use stdout
|
||||||
junk, outfile = tempfile.mkstemp(suffix=".pyc",
|
|
||||||
prefix=files[0][0:-4]+'-')
|
|
||||||
else:
|
|
||||||
outfile = None # use stdout
|
|
||||||
elif outfile and os.path.isdir(outfile):
|
elif outfile and os.path.isdir(outfile):
|
||||||
out_base = outfile; outfile = None
|
out_base = outfile; outfile = None
|
||||||
elif outfile and len(files) > 1:
|
elif outfile and len(files) > 1:
|
||||||
|
14
uncompyle6/linenumbers.py
Normal file
14
uncompyle6/linenumbers.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from xdis.load import load_file, load_module
|
||||||
|
from xdis.bytecode import findlinestarts, offset2line
|
||||||
|
|
||||||
|
def line_number_mapping(pyc_filename, src_filename):
|
||||||
|
(version, timestamp, magic_int, code_obj1, is_pypy,
|
||||||
|
source_size) = load_module(pyc_filename)
|
||||||
|
try:
|
||||||
|
code_obj2 = load_file(src_filename)
|
||||||
|
except SyntaxError as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
linestarts_orig = findlinestarts(code_obj1)
|
||||||
|
linestarts_uncompiled = list(findlinestarts(code_obj2))
|
||||||
|
return [[line, offset2line(offset, linestarts_uncompiled)] for offset, line in linestarts_orig]
|
@@ -1,5 +1,5 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import datetime, os, sys
|
import datetime, os, subprocess, sys, tempfile
|
||||||
|
|
||||||
from uncompyle6 import verify, IS_PYPY
|
from uncompyle6 import verify, IS_PYPY
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
@@ -7,6 +7,7 @@ from uncompyle6.disas import check_object_path
|
|||||||
from uncompyle6.semantics import pysource
|
from uncompyle6.semantics import pysource
|
||||||
from uncompyle6.parser import ParserError
|
from uncompyle6.parser import ParserError
|
||||||
from uncompyle6.version import VERSION
|
from uncompyle6.version import VERSION
|
||||||
|
from uncompyle6.linenumbers import line_number_mapping
|
||||||
|
|
||||||
from xdis.load import load_module
|
from xdis.load import load_module
|
||||||
|
|
||||||
@@ -76,7 +77,8 @@ def uncompyle_file(filename, outstream=None, showasm=None, showast=False,
|
|||||||
# FIXME: combine into an options parameter
|
# FIXME: combine into an options parameter
|
||||||
def main(in_base, out_base, files, codes, outfile=None,
|
def main(in_base, out_base, files, codes, outfile=None,
|
||||||
showasm=None, showast=False, do_verify=False,
|
showasm=None, showast=False, do_verify=False,
|
||||||
showgrammar=False, raise_on_error=False):
|
showgrammar=False, raise_on_error=False,
|
||||||
|
do_linemaps=False):
|
||||||
"""
|
"""
|
||||||
in_base base directory for input files
|
in_base base directory for input files
|
||||||
out_base base directory for output files (ignored when
|
out_base base directory for output files (ignored when
|
||||||
@@ -99,7 +101,6 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
pass
|
pass
|
||||||
return open(outfile, 'w')
|
return open(outfile, 'w')
|
||||||
|
|
||||||
of = outfile
|
|
||||||
tot_files = okay_files = failed_files = verify_failed_files = 0
|
tot_files = okay_files = failed_files = verify_failed_files = 0
|
||||||
|
|
||||||
# for code in codes:
|
# for code in codes:
|
||||||
@@ -117,10 +118,21 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
|
|
||||||
# print (infile, file=sys.stderr)
|
# print (infile, file=sys.stderr)
|
||||||
|
|
||||||
if of: # outfile was given as parameter
|
if outfile: # outfile was given as parameter
|
||||||
outstream = _get_outstream(outfile)
|
outstream = _get_outstream(outfile)
|
||||||
elif out_base is None:
|
elif out_base is None:
|
||||||
outstream = sys.stdout
|
outstream = sys.stdout
|
||||||
|
if do_linemaps or do_verify:
|
||||||
|
prefix = os.path.basename(filename)
|
||||||
|
if prefix.endswith('.py'):
|
||||||
|
prefix = prefix[:-len('.py')]
|
||||||
|
junk, outfile = tempfile.mkstemp(suffix=".pyc",
|
||||||
|
prefix=prefix)
|
||||||
|
# Unbuffer output
|
||||||
|
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
|
||||||
|
tee = subprocess.Popen(["tee", outfile], stdin=subprocess.PIPE)
|
||||||
|
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())
|
||||||
else:
|
else:
|
||||||
if filename.endswith('.pyc'):
|
if filename.endswith('.pyc'):
|
||||||
outfile = os.path.join(out_base, filename[0:-1])
|
outfile = os.path.join(out_base, filename[0:-1])
|
||||||
@@ -152,7 +164,13 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
# sys.stderr.write("\n# Can't uncompile %s\n" % infile)
|
# sys.stderr.write("\n# Can't uncompile %s\n" % infile)
|
||||||
else: # uncompile successful
|
else: # uncompile successful
|
||||||
if outfile:
|
if outfile:
|
||||||
|
if do_linemaps:
|
||||||
|
mapping = line_number_mapping(infile, outfile)
|
||||||
|
print("\n\n## Line number correspondences", infile)
|
||||||
|
for m in mapping:
|
||||||
|
print("## %s" % m, infile)
|
||||||
outstream.close()
|
outstream.close()
|
||||||
|
|
||||||
if do_verify:
|
if do_verify:
|
||||||
weak_verify = do_verify == 'weak'
|
weak_verify = do_verify == 'weak'
|
||||||
try:
|
try:
|
||||||
|
Reference in New Issue
Block a user