diff --git a/uncompyle6/bin/pydisassemble.py b/uncompyle6/bin/pydisassemble.py index 219158fc..a2ea3659 100755 --- a/uncompyle6/bin/pydisassemble.py +++ b/uncompyle6/bin/pydisassemble.py @@ -1,10 +1,13 @@ #!/usr/bin/env python # Mode: -*- python -*- # -# Copyright (c) 2015-2016, 2018, 2020, 2022 by Rocky Bernstein +# Copyright (c) 2015-2016, 2018, 2020, 2022-2023 by Rocky Bernstein # from __future__ import print_function -import sys, os, getopt + +import getopt +import os +import sys from uncompyle6.code_fns import disassemble_file from uncompyle6.version import __version__ @@ -40,13 +43,19 @@ Options: -V | --version show version and stop -h | --help show this message -""".format(program) +""".format( + program +) + +PATTERNS = ("*.pyc", "*.pyo") -PATTERNS = ('*.pyc', '*.pyo') def main(): - Usage_short = """usage: %s FILE... -Type -h for for full help.""" % program + Usage_short = ( + """usage: %s FILE... +Type -h for for full help.""" + % program + ) if len(sys.argv) == 1: print("No file(s) given", file=sys.stderr) @@ -54,17 +63,18 @@ Type -h for for full help.""" % program sys.exit(1) try: - opts, files = getopt.getopt(sys.argv[1:], 'hVU', - ['help', 'version', 'uncompyle6']) + opts, files = getopt.getopt( + sys.argv[1:], "hVU", ["help", "version", "uncompyle6"] + ) 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) for opt, val in opts: - if opt in ('-h', '--help'): + if opt in ("-h", "--help"): print(__doc__) sys.exit(1) - elif opt in ('-V', '--version'): + elif opt in ("-V", "--version"): print("%s %s" % (program, __version__)) sys.exit(0) else: @@ -76,11 +86,11 @@ Type -h for for full help.""" % program if os.path.exists(files[0]): disassemble_file(file, sys.stdout) else: - print("Can't read %s - skipping" % files[0], - file=sys.stderr) + print("Can't read %s - skipping" % files[0], file=sys.stderr) pass pass return -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index fd3242d5..d5beaaad 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -1,14 +1,19 @@ #!/usr/bin/env python # Mode: -*- python -*- # -# Copyright (c) 2015-2017, 2019-2020 by Rocky Bernstein +# Copyright (c) 2015-2017, 2019-2020, 2023 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # from __future__ import print_function -import sys, os, getopt, time + +import getopt +import os +import sys +import time + from xdis.version_info import version_tuple_to_str -program = 'uncompyle6' +program = "uncompyle6" __doc__ = """ Usage: @@ -58,101 +63,120 @@ Extensions of generated files: '.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify) + '_unverified' successfully decompile but --verify failed + '_failed' decompile failed (contact author for enhancement) -""" % ((program,) * 5) +""" % ( + (program,) * 5 +) -program = 'uncompyle6' +program = "uncompyle6" from uncompyle6 import verify from uncompyle6.main import main, status_msg from uncompyle6.version import __version__ + def usage(): print(__doc__) sys.exit(1) def main_bin(): - if not (sys.version_info[0:2] in ((2, 6), (2, 7), (3, 0), - (3, 1), (3, 2), (3, 3), - (3, 4), (3, 5), (3, 6), - (3, 7), (3, 8), (3, 9), (3, 10) - )): + if not ( + sys.version_info[0:2] + in ( + (2, 6), + (2, 7), + (3, 0), + (3, 1), + (3, 2), + (3, 3), + (3, 4), + (3, 5), + (3, 6), + (3, 7), + (3, 8), + (3, 9), + (3, 10), + ) + ): print( f"Error: {program} can decompile only bytecode from Python 3.7" f""" to 3.8.\n\tYou have version: {version_tuple_to_str()}.""" ) sys.exit(-1) - do_verify = recurse_dirs = False + recurse_dirs = False numproc = 0 - outfile = '-' + outfile = "-" out_base = None source_paths = [] timestamp = False timestampfmt = "# %Y.%m.%d %H:%M:%S %Z" try: - opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtTdrVo:p:', - 'help asm compile= grammar linemaps recurse ' - 'timestamp tree= tree+ ' - 'fragments verify verify-run version ' - 'syntax-verify ' - 'showgrammar encoding='.split(' ')) + opts, pyc_paths = getopt.getopt( + sys.argv[1:], + "hac:gtTdrVo:p:", + "help asm compile= grammar linemaps recurse " + "timestamp tree= tree+ " + "fragments verify verify-run version " + "syntax-verify " + "showgrammar encoding=".split(" "), + ) 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) options = {} for opt, val in opts: - if opt in ('-h', '--help'): + if opt in ("-h", "--help"): print(__doc__) sys.exit(0) - elif opt in ('-V', '--version'): + elif opt in ("-V", "--version"): print("%s %s" % (program, __version__)) sys.exit(0) - elif opt == '--verify': - options['do_verify'] = 'strong' - elif opt == '--syntax-verify': - options['do_verify'] = 'weak' - elif opt == '--fragments': - options['do_fragments'] = True - elif opt == '--verify-run': - options['do_verify'] = 'verify-run' - elif opt == '--linemaps': - options['do_linemaps'] = True - elif opt in ('--asm', '-a'): - options['showasm'] = 'after' - options['do_verify'] = None - elif opt in ('--tree', '-t'): - if 'showast' not in options: - options['showast'] = {} - if val == 'before': - options['showast'][val] = True - elif val == 'after': - options['showast'][val] = True + elif opt == "--verify": + options["do_verify"] = "strong" + elif opt == "--syntax-verify": + options["do_verify"] = "weak" + elif opt == "--fragments": + options["do_fragments"] = True + elif opt == "--verify-run": + options["do_verify"] = "verify-run" + elif opt == "--linemaps": + options["do_linemaps"] = True + elif opt in ("--asm", "-a"): + options["showasm"] = "after" + options["do_verify"] = None + elif opt in ("--tree", "-t"): + if "showast" not in options: + options["showast"] = {} + if val == "before": + options["showast"][val] = True + elif val == "after": + options["showast"][val] = True else: - options['showast']['before'] = True - options['do_verify'] = None - elif opt in ('--tree+', '-T'): - if 'showast' not in options: - options['showast'] = {} - options['showast']['after'] = True - options['showast']['before'] = True - options['do_verify'] = None - elif opt in ('--grammar', '-g'): - options['showgrammar'] = True - elif opt == '-o': + options["showast"]["before"] = True + options["do_verify"] = None + elif opt in ("--tree+", "-T"): + if "showast" not in options: + options["showast"] = {} + options["showast"]["after"] = True + options["showast"]["before"] = True + options["do_verify"] = None + elif opt in ("--grammar", "-g"): + options["showgrammar"] = True + elif opt == "-o": outfile = val - elif opt in ('--timestamp', '-d'): + elif opt in ("--timestamp", "-d"): timestamp = True - elif opt in ('--compile', '-c'): + elif opt in ("--compile", "-c"): source_paths.append(val) - elif opt == '-p': + elif opt == "-p": numproc = int(val) - elif opt in ('--recurse', '-r'): + elif opt in ("--recurse", "-r"): recurse_dirs = True - elif opt == '--encoding': - options['source_encoding'] = val + elif opt == "--encoding": + options["source_encoding"] = val else: print(opt, file=sys.stderr) usage() @@ -164,7 +188,7 @@ def main_bin(): 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'): + if df.endswith(".pyc") or df.endswith(".pyo"): expanded_files.append(os.path.join(root, df)) pyc_paths = expanded_files @@ -175,36 +199,39 @@ def main_bin(): if src_base[-1:] != os.sep: src_base = os.path.dirname(src_base) if src_base: - sb_len = len( os.path.join(src_base, '') ) + sb_len = len(os.path.join(src_base, "")) pyc_paths = [f[sb_len:] for f in pyc_paths] 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 + if outfile == "-": + outfile = None # use stdout elif outfile and os.path.isdir(outfile): - out_base = outfile; outfile = None + out_base = outfile + outfile = None elif outfile and len(pyc_paths) > 1: - out_base = outfile; outfile = None + out_base = outfile + outfile = None if timestamp: print(time.strftime(timestampfmt)) if numproc <= 1: try: - result = main(src_base, out_base, pyc_paths, source_paths, outfile, - **options) - result = [options.get('do_verify', None)] + list(result) + result = main( + src_base, out_base, pyc_paths, source_paths, outfile, **options + ) + result = [options.get("do_verify", None)] + list(result) if len(pyc_paths) > 1: mess = status_msg(*result) - print('# ' + mess) + print("# " + mess) pass except ImportError as e: print(str(e)) sys.exit(2) - except (KeyboardInterrupt): + except KeyboardInterrupt: pass except verify.VerifyCmpError: raise @@ -216,7 +243,7 @@ def main_bin(): except ImportError: from queue import Empty - fqueue = Queue(len(pyc_paths)+numproc) + fqueue = Queue(len(pyc_paths) + numproc) for f in pyc_paths: fqueue.put(f) for i in range(numproc): @@ -226,13 +253,17 @@ def main_bin(): def process_func(): try: - (tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0) + (tot_files, okay_files, failed_files, verify_failed_files) = ( + 0, + 0, + 0, + 0, + ) while 1: f = fqueue.get() if f is None: break - (t, o, f, v) = \ - main(src_base, out_base, [f], [], outfile, **options) + (t, o, f, v) = main(src_base, out_base, [f], [], outfile, **options) tot_files += t okay_files += o failed_files += f @@ -249,7 +280,12 @@ def main_bin(): for p in procs: p.join() try: - (tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0) + (tot_files, okay_files, failed_files, verify_failed_files) = ( + 0, + 0, + 0, + 0, + ) while True: (t, o, f, v) = rqueue.get(False) tot_files += t @@ -258,8 +294,10 @@ def main_bin(): verify_failed_files += v except Empty: pass - print('# decompiled %i files: %i okay, %i failed, %i verify failed' % - (tot_files, okay_files, failed_files, verify_failed_files)) + print( + "# decompiled %i files: %i okay, %i failed, %i verify failed" + % (tot_files, okay_files, failed_files, verify_failed_files) + ) except (KeyboardInterrupt, OSError): pass @@ -268,5 +306,6 @@ def main_bin(): return -if __name__ == '__main__': + +if __name__ == "__main__": main_bin() diff --git a/uncompyle6/main.py b/uncompyle6/main.py index edf29096..72b86010 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2022 Rocky Bernstein +# Copyright (C) 2018-2023 Rocky Bernstein # # 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,24 +13,26 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import datetime +import os +import py_compile +import sys from typing import Any, Tuple -import datetime, py_compile, os, sys from xdis import iscode +from xdis.load import load_module from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str + from uncompyle6.code_fns import check_object_path -from uncompyle6.semantics import pysource -from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG from uncompyle6.parser import ParserError +from uncompyle6.semantics import pysource +from uncompyle6.semantics.fragments import code_deparse as code_deparse_fragments +from uncompyle6.semantics.linemap import deparse_code_with_map +from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG, code_deparse from uncompyle6.version import __version__ # from uncompyle6.linenumbers import line_number_mapping -from uncompyle6.semantics.pysource import code_deparse -from uncompyle6.semantics.fragments import code_deparse as code_deparse_fragments -from uncompyle6.semantics.linemap import deparse_code_with_map - -from xdis.load import load_module def _get_outstream(outfile: str) -> Any: dir = os.path.dirname(outfile) @@ -55,7 +57,7 @@ def decompile( source_encoding=None, code_objects={}, source_size=None, - is_pypy=None, + is_pypy=False, magic_int=None, mapstream=None, do_fragments=False, @@ -145,8 +147,8 @@ def decompile( out, bytecode_version, debug_opts=debug_opts, - is_pypy=is_pypy, compile_mode=compile_mode, + is_pypy=is_pypy, ) pass return deparsed @@ -188,7 +190,7 @@ def decompile_file( filename = check_object_path(filename) code_objects = {} - (version, timestamp, magic_int, co, is_pypy, source_size, sip_hash) = load_module( + version, timestamp, magic_int, co, is_pypy, source_size, _ = load_module( filename, code_objects ) @@ -394,14 +396,14 @@ def main( try: # FIXME: Something is weird with Pypy here sys.stdout.flush() - except: + except Exception: pass if current_outfile: sys.stdout.write("\n") try: # FIXME: Something is weird with Pypy here sys.stdout.flush() - except: + except Exception: pass pass return (tot_files, okay_files, failed_files, verify_failed_files) @@ -417,7 +419,6 @@ if sys.platform.startswith("linux") and os.uname()[2][:2] in ["2.", "3.", "4."]: mi.close() return int(mu) / 1000000 - else: def __memUsage(): diff --git a/uncompyle6/parsers/parse13.py b/uncompyle6/parsers/parse13.py index 593805ee..307af36b 100644 --- a/uncompyle6/parsers/parse13.py +++ b/uncompyle6/parsers/parse13.py @@ -1,11 +1,12 @@ -# Copyright (c) 2018 Rocky Bernstein +# Copyright (c) 2018, 2023 Rocky Bernstein from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG + from uncompyle6.parser import PythonParserSingle from uncompyle6.parsers.parse14 import Python14Parser -class Python13Parser(Python14Parser): +class Python13Parser(Python14Parser): def p_misc13(self, args): """ # Nothing here yet, but will need to add LOAD_GLOBALS @@ -24,7 +25,6 @@ class Python13Parser(Python14Parser): # """) # self.check_reduce['doc_junk'] = 'tokens' - # def reduce_is_invalid(self, rule, ast, tokens, first, last): # invalid = super(Python14Parser, # self).reduce_is_invalid(rule, ast, @@ -35,11 +35,11 @@ class Python13Parser(Python14Parser): # return not isinstance(tokens[first].pattr, str) - class Python13ParserSingle(Python13Parser, PythonParserSingle): pass -if __name__ == '__main__': + +if __name__ == "__main__": # Check grammar p = Python13Parser() p.check_grammar() diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 285b2dae..c30ccf1d 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -411,7 +411,7 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify, name=""): check_jumps[dest1].append((i1, i2, dest2)) else: check_jumps[dest1] = [(i1, i2, dest2)] - except: + except Exception: pass i1 += 1