mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-12-04 19:07:03 +00:00
3.8 SETUP_EXCEPT removal workaround; reinstate option -c | --compile
This commit is contained in:
parent
cfe7feed4d
commit
7f65a8a6dd
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env 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>
|
||||
#
|
||||
from __future__ import print_function
|
||||
@ -30,7 +30,8 @@ Options:
|
||||
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
||||
uncompyle6 -o /tmp /usr/lib/python1.5
|
||||
-> /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
|
||||
-p <integer> use <integer> number of processes
|
||||
-r recurse directories looking for .pyc and .pyo files
|
||||
@ -43,10 +44,10 @@ Options:
|
||||
--help show this message
|
||||
|
||||
Debugging Options:
|
||||
--asm -a include byte-code (disables --verify)
|
||||
--grammar -g show matching grammar
|
||||
--tree -t include syntax tree (disables --verify)
|
||||
--tree++ add template rules to --tree when possible
|
||||
--asm | -a include byte-code (disables --verify)
|
||||
--grammar | -g show matching grammar
|
||||
--tree | -t include syntax tree (disables --verify)
|
||||
--tree++ add template rules to --tree when possible
|
||||
|
||||
Extensions of generated files:
|
||||
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
||||
@ -61,10 +62,7 @@ from uncompyle6.main import main, status_msg
|
||||
from uncompyle6.version import VERSION
|
||||
|
||||
def usage():
|
||||
print("""usage:
|
||||
%s [--verify | --weak-verify ] [--asm] [--tree[+]] [--grammar] [-o <path>] FILE|DIR...
|
||||
%s [--help | -h | --version | -V]
|
||||
""" % (program, program))
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -82,13 +80,13 @@ def main_bin():
|
||||
numproc = 0
|
||||
outfile = '-'
|
||||
out_base = None
|
||||
codes = []
|
||||
source_paths = []
|
||||
timestamp = False
|
||||
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
||||
|
||||
try:
|
||||
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
||||
'help asm grammar linemaps recurse '
|
||||
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtdrVo:p:',
|
||||
'help asm compile= grammar linemaps recurse '
|
||||
'timestamp tree tree+ '
|
||||
'fragments verify verify-run version '
|
||||
'weak-verify '
|
||||
@ -130,8 +128,8 @@ def main_bin():
|
||||
outfile = val
|
||||
elif opt in ('--timestamp', '-d'):
|
||||
timestamp = True
|
||||
elif opt == '-c':
|
||||
codes.append(val)
|
||||
elif opt in ('--compile', '-c'):
|
||||
source_paths.append(val)
|
||||
elif opt == '-p':
|
||||
numproc = int(val)
|
||||
elif opt in ('--recurse', '-r'):
|
||||
@ -143,33 +141,33 @@ def main_bin():
|
||||
# expand directory if specified
|
||||
if recurse_dirs:
|
||||
expanded_files = []
|
||||
for f in files:
|
||||
for f in pyc_paths:
|
||||
if os.path.isdir(f):
|
||||
for root, _, dir_files in os.walk(f):
|
||||
for df in dir_files:
|
||||
if df.endswith('.pyc') or df.endswith('.pyo'):
|
||||
expanded_files.append(os.path.join(root, df))
|
||||
files = expanded_files
|
||||
pyc_paths = expanded_files
|
||||
|
||||
# argl, commonprefix works on strings, not on path parts,
|
||||
# thus we must handle the case with files in 'some/classes'
|
||||
# and 'some/cmds'
|
||||
src_base = os.path.commonprefix(files)
|
||||
src_base = os.path.commonprefix(pyc_paths)
|
||||
if src_base[-1:] != os.sep:
|
||||
src_base = os.path.dirname(src_base)
|
||||
if 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:
|
||||
print("No files given", file=sys.stderr)
|
||||
if not pyc_paths and not source_paths:
|
||||
print("No input files given to decompile", file=sys.stderr)
|
||||
usage()
|
||||
|
||||
if outfile == '-':
|
||||
outfile = None # use stdout
|
||||
elif outfile and os.path.isdir(outfile):
|
||||
out_base = outfile; outfile = None
|
||||
elif outfile and len(files) > 1:
|
||||
elif outfile and len(pyc_paths) > 1:
|
||||
out_base = outfile; outfile = None
|
||||
|
||||
if timestamp:
|
||||
@ -177,10 +175,10 @@ def main_bin():
|
||||
|
||||
if numproc <= 1:
|
||||
try:
|
||||
result = main(src_base, out_base, files, None, outfile,
|
||||
result = main(src_base, out_base, pyc_paths, source_paths, outfile,
|
||||
**options)
|
||||
result = list(result) + [options.get('do_verify', None)]
|
||||
if len(files) > 1:
|
||||
if len(pyc_paths) > 1:
|
||||
mess = status_msg(do_verify, *result)
|
||||
print('# ' + mess)
|
||||
pass
|
||||
@ -196,8 +194,8 @@ def main_bin():
|
||||
except ImportError:
|
||||
from queue import Empty
|
||||
|
||||
fqueue = Queue(len(files)+numproc)
|
||||
for f in files:
|
||||
fqueue = Queue(len(pyc_paths)+numproc)
|
||||
for f in pyc_paths:
|
||||
fqueue.put(f)
|
||||
for i in range(numproc):
|
||||
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
|
||||
# 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
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
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 xdis.code import iscode
|
||||
@ -119,6 +119,22 @@ def decompile(
|
||||
# deparsing failed
|
||||
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,
|
||||
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
|
||||
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,
|
||||
showgrammar=False, raise_on_error=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)
|
||||
outfile write output to this filename (overwrites out_base)
|
||||
|
||||
Note: `codes` is not use. Historical compatability?
|
||||
|
||||
For redirecting output to
|
||||
- <filename> outfile=<filename> (out_base is ignored)
|
||||
- files below out_base out_base=...
|
||||
@ -171,7 +185,10 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
current_outfile = outfile
|
||||
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)
|
||||
# print("XXX", infile)
|
||||
if not os.path.exists(infile):
|
||||
|
@ -916,7 +916,7 @@ class Scanner3(Scanner):
|
||||
# Python 3.5 may remove as dead code a JUMP
|
||||
# instruction after a RETURN_VALUE. So we check
|
||||
# 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
|
||||
# Check that next instruction after pops and jump is
|
||||
# not from SETUP_EXCEPT
|
||||
@ -928,7 +928,7 @@ class Scanner3(Scanner):
|
||||
if next_op in targets:
|
||||
for try_op in targets[next_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
|
||||
pass
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user