3.8 SETUP_EXCEPT removal workaround; reinstate option -c | --compile

This commit is contained in:
rocky 2019-04-11 07:19:35 -04:00
parent cfe7feed4d
commit 7f65a8a6dd
3 changed files with 49 additions and 34 deletions

View File

@ -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)

View File

@ -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):

View File

@ -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