You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
3.8 SETUP_EXCEPT removal workaround; reinstate option -c | --compile
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Mode: -*- python -*-
|
# Mode: -*- python -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
# Copyright (c) 2015-2017, 2019 by Rocky Bernstein
|
||||||
# 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
|
||||||
@@ -30,7 +30,8 @@ Options:
|
|||||||
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
||||||
uncompyle6 -o /tmp /usr/lib/python1.5
|
uncompyle6 -o /tmp /usr/lib/python1.5
|
||||||
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
|
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
|
||||||
-c <file> attempts a disassembly after compiling <file>
|
--compile | -c <python-file>
|
||||||
|
attempts a decompilation after compiling <python-file>
|
||||||
-d print timestamps
|
-d print timestamps
|
||||||
-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
|
||||||
@@ -43,9 +44,9 @@ Options:
|
|||||||
--help show this message
|
--help show this message
|
||||||
|
|
||||||
Debugging Options:
|
Debugging Options:
|
||||||
--asm -a include byte-code (disables --verify)
|
--asm | -a include byte-code (disables --verify)
|
||||||
--grammar -g show matching grammar
|
--grammar | -g show matching grammar
|
||||||
--tree -t include syntax tree (disables --verify)
|
--tree | -t include syntax tree (disables --verify)
|
||||||
--tree++ add template rules to --tree when possible
|
--tree++ add template rules to --tree when possible
|
||||||
|
|
||||||
Extensions of generated files:
|
Extensions of generated files:
|
||||||
@@ -61,10 +62,7 @@ from uncompyle6.main import main, status_msg
|
|||||||
from uncompyle6.version import VERSION
|
from uncompyle6.version import VERSION
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print("""usage:
|
print(__doc__)
|
||||||
%s [--verify | --weak-verify ] [--asm] [--tree[+]] [--grammar] [-o <path>] FILE|DIR...
|
|
||||||
%s [--help | -h | --version | -V]
|
|
||||||
""" % (program, program))
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -82,13 +80,13 @@ def main_bin():
|
|||||||
numproc = 0
|
numproc = 0
|
||||||
outfile = '-'
|
outfile = '-'
|
||||||
out_base = None
|
out_base = None
|
||||||
codes = []
|
source_paths = []
|
||||||
timestamp = False
|
timestamp = False
|
||||||
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtdrVo:p:',
|
||||||
'help asm grammar linemaps recurse '
|
'help asm compile= grammar linemaps recurse '
|
||||||
'timestamp tree tree+ '
|
'timestamp tree tree+ '
|
||||||
'fragments verify verify-run version '
|
'fragments verify verify-run version '
|
||||||
'weak-verify '
|
'weak-verify '
|
||||||
@@ -130,8 +128,8 @@ def main_bin():
|
|||||||
outfile = val
|
outfile = val
|
||||||
elif opt in ('--timestamp', '-d'):
|
elif opt in ('--timestamp', '-d'):
|
||||||
timestamp = True
|
timestamp = True
|
||||||
elif opt == '-c':
|
elif opt in ('--compile', '-c'):
|
||||||
codes.append(val)
|
source_paths.append(val)
|
||||||
elif opt == '-p':
|
elif opt == '-p':
|
||||||
numproc = int(val)
|
numproc = int(val)
|
||||||
elif opt in ('--recurse', '-r'):
|
elif opt in ('--recurse', '-r'):
|
||||||
@@ -143,33 +141,33 @@ def main_bin():
|
|||||||
# expand directory if specified
|
# expand directory if specified
|
||||||
if recurse_dirs:
|
if recurse_dirs:
|
||||||
expanded_files = []
|
expanded_files = []
|
||||||
for f in files:
|
for f in pyc_paths:
|
||||||
if os.path.isdir(f):
|
if os.path.isdir(f):
|
||||||
for root, _, dir_files in os.walk(f):
|
for root, _, dir_files in os.walk(f):
|
||||||
for df in dir_files:
|
for df in dir_files:
|
||||||
if df.endswith('.pyc') or df.endswith('.pyo'):
|
if df.endswith('.pyc') or df.endswith('.pyo'):
|
||||||
expanded_files.append(os.path.join(root, df))
|
expanded_files.append(os.path.join(root, df))
|
||||||
files = expanded_files
|
pyc_paths = expanded_files
|
||||||
|
|
||||||
# argl, commonprefix works on strings, not on path parts,
|
# argl, commonprefix works on strings, not on path parts,
|
||||||
# thus we must handle the case with files in 'some/classes'
|
# thus we must handle the case with files in 'some/classes'
|
||||||
# and 'some/cmds'
|
# and 'some/cmds'
|
||||||
src_base = os.path.commonprefix(files)
|
src_base = os.path.commonprefix(pyc_paths)
|
||||||
if src_base[-1:] != os.sep:
|
if src_base[-1:] != os.sep:
|
||||||
src_base = os.path.dirname(src_base)
|
src_base = os.path.dirname(src_base)
|
||||||
if src_base:
|
if src_base:
|
||||||
sb_len = len( os.path.join(src_base, '') )
|
sb_len = len( os.path.join(src_base, '') )
|
||||||
files = [f[sb_len:] for f in files]
|
pyc_paths = [f[sb_len:] for f in pyc_paths]
|
||||||
|
|
||||||
if not files:
|
if not pyc_paths and not source_paths:
|
||||||
print("No files given", file=sys.stderr)
|
print("No input files given to decompile", file=sys.stderr)
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
if outfile == '-':
|
if outfile == '-':
|
||||||
outfile = None # use stdout
|
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(pyc_paths) > 1:
|
||||||
out_base = outfile; outfile = None
|
out_base = outfile; outfile = None
|
||||||
|
|
||||||
if timestamp:
|
if timestamp:
|
||||||
@@ -177,10 +175,10 @@ def main_bin():
|
|||||||
|
|
||||||
if numproc <= 1:
|
if numproc <= 1:
|
||||||
try:
|
try:
|
||||||
result = main(src_base, out_base, files, None, outfile,
|
result = main(src_base, out_base, pyc_paths, source_paths, outfile,
|
||||||
**options)
|
**options)
|
||||||
result = list(result) + [options.get('do_verify', None)]
|
result = list(result) + [options.get('do_verify', None)]
|
||||||
if len(files) > 1:
|
if len(pyc_paths) > 1:
|
||||||
mess = status_msg(do_verify, *result)
|
mess = status_msg(do_verify, *result)
|
||||||
print('# ' + mess)
|
print('# ' + mess)
|
||||||
pass
|
pass
|
||||||
@@ -196,8 +194,8 @@ def main_bin():
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
|
|
||||||
fqueue = Queue(len(files)+numproc)
|
fqueue = Queue(len(pyc_paths)+numproc)
|
||||||
for f in files:
|
for f in pyc_paths:
|
||||||
fqueue.put(f)
|
fqueue.put(f)
|
||||||
for i in range(numproc):
|
for i in range(numproc):
|
||||||
fqueue.put(None)
|
fqueue.put(None)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2018 Rocky Bernstein <rocky@gnu.org>
|
# Copyright (C) 2018-2019 Rocky Bernstein <rocky@gnu.org>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import datetime, os, subprocess, sys, tempfile
|
import datetime, py_compile, os, subprocess, sys, tempfile
|
||||||
|
|
||||||
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
@@ -119,6 +119,22 @@ def decompile(
|
|||||||
# deparsing failed
|
# deparsing failed
|
||||||
raise pysource.SourceWalkerError(str(e))
|
raise pysource.SourceWalkerError(str(e))
|
||||||
|
|
||||||
|
def compile_file(source_path):
|
||||||
|
if source_path.endswith('.py'):
|
||||||
|
basename = source_path[:-3]
|
||||||
|
else:
|
||||||
|
basename = source_path
|
||||||
|
|
||||||
|
if hasattr(sys, 'pypy_version_info'):
|
||||||
|
bytecode_path = "%s-pypy%s.pyc" % (basename, PYTHON_VERSION)
|
||||||
|
else:
|
||||||
|
bytecode_path = "%s-%s.pyc" % (basename, PYTHON_VERSION)
|
||||||
|
|
||||||
|
print("compiling %s to %s" % (source_path, bytecode_path))
|
||||||
|
py_compile.compile(source_path, bytecode_path, 'exec')
|
||||||
|
return bytecode_path
|
||||||
|
|
||||||
|
|
||||||
def decompile_file(filename, outstream=None, showasm=None, showast=False,
|
def decompile_file(filename, outstream=None, showasm=None, showast=False,
|
||||||
showgrammar=False, mapstream=None, do_fragments=False):
|
showgrammar=False, mapstream=None, do_fragments=False):
|
||||||
"""
|
"""
|
||||||
@@ -150,7 +166,7 @@ def decompile_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, compiled_files, source_files, 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, do_fragments=False):
|
do_linemaps=False, do_fragments=False):
|
||||||
@@ -160,8 +176,6 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
files list of filenames to be uncompyled (relative to in_base)
|
files list of filenames to be uncompyled (relative to in_base)
|
||||||
outfile write output to this filename (overwrites out_base)
|
outfile write output to this filename (overwrites out_base)
|
||||||
|
|
||||||
Note: `codes` is not use. Historical compatability?
|
|
||||||
|
|
||||||
For redirecting output to
|
For redirecting output to
|
||||||
- <filename> outfile=<filename> (out_base is ignored)
|
- <filename> outfile=<filename> (out_base is ignored)
|
||||||
- files below out_base out_base=...
|
- files below out_base out_base=...
|
||||||
@@ -171,7 +185,10 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
current_outfile = outfile
|
current_outfile = outfile
|
||||||
linemap_stream = None
|
linemap_stream = None
|
||||||
|
|
||||||
for filename in files:
|
for source_path in source_files:
|
||||||
|
compiled_files.append(compile_file(source_path))
|
||||||
|
|
||||||
|
for filename in compiled_files:
|
||||||
infile = os.path.join(in_base, filename)
|
infile = os.path.join(in_base, filename)
|
||||||
# print("XXX", infile)
|
# print("XXX", infile)
|
||||||
if not os.path.exists(infile):
|
if not os.path.exists(infile):
|
||||||
|
@@ -916,7 +916,7 @@ class Scanner3(Scanner):
|
|||||||
# Python 3.5 may remove as dead code a JUMP
|
# Python 3.5 may remove as dead code a JUMP
|
||||||
# instruction after a RETURN_VALUE. So we check
|
# instruction after a RETURN_VALUE. So we check
|
||||||
# based on seeing SETUP_EXCEPT various places.
|
# based on seeing SETUP_EXCEPT various places.
|
||||||
if code[rtarget] == self.opc.SETUP_EXCEPT:
|
if self.version < 3.8 and code[rtarget] == self.opc.SETUP_EXCEPT:
|
||||||
return
|
return
|
||||||
# Check that next instruction after pops and jump is
|
# Check that next instruction after pops and jump is
|
||||||
# not from SETUP_EXCEPT
|
# not from SETUP_EXCEPT
|
||||||
@@ -928,7 +928,7 @@ class Scanner3(Scanner):
|
|||||||
if next_op in targets:
|
if next_op in targets:
|
||||||
for try_op in targets[next_op]:
|
for try_op in targets[next_op]:
|
||||||
come_from_op = code[try_op]
|
come_from_op = code[try_op]
|
||||||
if come_from_op == self.opc.SETUP_EXCEPT:
|
if self.version < 3.8 and come_from_op == self.opc.SETUP_EXCEPT:
|
||||||
return
|
return
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
Reference in New Issue
Block a user