diff --git a/Makefile b/Makefile index 1a5b711c..0e2daacf 100644 --- a/Makefile +++ b/Makefile @@ -23,10 +23,14 @@ test check: pytest check-long check-long: pytest $(MAKE) -C test check-2.7 -#: Run tests +#: Run quick tests check-short: pytest $(MAKE) -C test check-short-2.7 +#: Run quick tests +check-3.4: pytest + $(MAKE) -C test check-3.4 + #: check that disassembly exactly matches Python lib's dis check-disasm: diff --git a/bin/pydisassemble b/bin/pydisassemble index 2e93e7fb..9a9ff649 100755 --- a/bin/pydisassemble +++ b/bin/pydisassemble @@ -3,14 +3,19 @@ # # Copyright (c) 2015 by Rocky Bernstein # -""" -Usage: pydisassemble [OPTIONS]... FILE +from __future__ import print_function +import sys, os, getopt + +program = os.path.basename(__file__) + +__doc__ = """ +Usage: %s [OPTIONS]... FILE Examples: - pydisassemble foo.pyc - pydisassemble foo.py - pydisassemble -o foo.pydis foo.pyc - pydisassemble -o /tmp foo.pyc + %s foo.pyc + %s foo.py + %s -o foo.pydis foo.pyc + %s -o /tmp foo.pyc Options: -o output decompiled files to this path: @@ -19,21 +24,16 @@ Options: --help show this message -""" +""" % ((program,) * 5) -from __future__ import print_function Usage_short = \ -"pydissassemble [--help] [--verify] [--showasm] [--showast] [-o ] FILE|DIR..." - -import sys, os, getopt -import os.path +"%s [--help] [--verify] [--showasm] [--showast] [-o ] FILE|DIR..." % program +from uncompyle6 import check_python_version from uncompyle6.disas import disassemble_files -if sys.version[:3] != '2.7' and sys.version[:3] != '3.4': - print('Error: pydisassemble requires Python 2.7 or 3.4.', file=sys.stderr) - sys.exit(-1) +check_python_version(program) outfile = '-' out_base = None diff --git a/bin/uncompyle6 b/bin/uncompyle6 index f4b59383..c162d341 100755 --- a/bin/uncompyle6 +++ b/bin/uncompyle6 @@ -41,18 +41,17 @@ Extensions of generated files: """ from __future__ import print_function +import sys, os, getopt + +program = os.path.basename(__file__) Usage_short = \ -"uncompyle6 [--help] [--verify] [--showasm] [--showast] [-o ] FILE|DIR..." +"%s [--help] [--verify] [--showasm] [--showast] [-o ] FILE|DIR..." % program -import sys, os, getopt -import os.path -from uncompyle6 import main, status_msg, verify +from uncompyle6 import main, status_msg, verify, check_python_version import time -if sys.version[:3] != '2.7' and sys.version[:3] != '3.4': - print('Error: uncompyle6 requires Python 2.7 or 3.4.', file=sys.stderr) - sys.exit(-1) +check_python_version(program) showasm = showast = do_verify = recurse_dirs = False numproc = 0 diff --git a/test/bytecompile-tests b/test/bytecompile-tests index 15b6d4d2..67c8800a 100755 --- a/test/bytecompile-tests +++ b/test/bytecompile-tests @@ -53,7 +53,6 @@ tests['2.2'] = ['divide_future', 'divide_no_future', 'iterators', tests['2.3'] = tests['2.2'] tests['2.5'] = tests['2.3'] -tests['2.6'] = tests['2.5'] # tests['2.7'] = ['mine'] + tests['2.6'] tests['2.7'] = [ 'simple-source/branching/ifelse', @@ -61,6 +60,7 @@ tests['2.7'] = [ # 'simple-source/call_arguments/keyword', # 'simple-source/call_arguments/positional' ] +tests['2.6'] = tests['2.7'] def file_matches(files, root, basenames, patterns): files.extend( diff --git a/test/dis-compare.py b/test/dis-compare.py index bdbb8694..3dc85716 100755 --- a/test/dis-compare.py +++ b/test/dis-compare.py @@ -6,7 +6,7 @@ from __future__ import print_function -import dis, os.path, sys +import dis, os.path try: from StringIO import StringIO @@ -16,17 +16,16 @@ except ImportError: program = os.path.basename(__file__) __doc__ = """ -Usage: {0} [OPTIONS]... FILE +Usage: %s [OPTIONS]... FILE -""".format(program) +""" % program -usage_short = "Usage: {0} [OPTIONS]... FILE".format(program) +usage_short = "Usage: %s [OPTIONS]... FILE" % program import uncompyle6 +from uncompyle6 import PYTHON_VERSION_STR, check_python_version from uncompyle6.disas import disco -version = sys.version[:3] - def inst_fmt(inst): if inst.starts_line: return '\n%4d %6s\t%-17s %r' % (inst.starts_line, inst.offset, inst.opname, @@ -39,9 +38,9 @@ def inst_fmt(inst): def compare_ok(version, co): out = StringIO() - if version == 2.7: + if version in (2.6, 2.7): dis.disco(co) - return + return True bytecode = dis.Bytecode(co) disco(version, co, out) @@ -61,10 +60,7 @@ def compare_ok(version, co): i += 1 return True -if version != '2.7' and version != '3.4': - print('Error: {0} requires Python 2.7 or 3.4.'.format(program), - file=sys.stderr) - sys.exit(-1) +check_python_version(program) # if len(sys.argv) != 2: # print(usage_short, file=sys.stderr) @@ -85,7 +81,7 @@ files=[ ] for base in files: - filename = "bytecode_%s/%s.pyc" % (version, base) + filename = "bytecode_%s/%s.pyc" % (PYTHON_VERSION_STR, base) version, co = uncompyle6.load_module(filename) ok = True if type(co) == list: diff --git a/uncompyle6/__init__.py b/uncompyle6/__init__.py index 3cf95394..7e5c80f4 100644 --- a/uncompyle6/__init__.py +++ b/uncompyle6/__init__.py @@ -33,7 +33,7 @@ from __future__ import print_function import os, marshal, sys, types -PYTHON_VERSION = sys.version_info.major + (sys.version_info.minor / 10.0) +# set before importing scanner PYTHON3 = (sys.version_info >= (3, 0)) import uncompyle6 @@ -43,6 +43,21 @@ import uncompyle6.marsh from uncompyle6 import walker, verify, magics sys.setrecursionlimit(5000) + +# We do this crazy way to support Python 2.6 which +# doesn't support version_major, and has a bug in +# floating point so we can't divide 26 by 10 and get +# 2.6 +PYTHON_VERSION = sys.version_info[0]+ (sys.version_info[1] / 10.0) +PYTHON_VERSION_STR = "%s.%s" % (sys.version_info[0], sys.version_info[1]) + +def check_python_version(program): + if not (sys.version_info[0:2] in ((2,6), (2,7), (3,4))): + print('Error: %s requires %s Python 2.6, 2.7 or 3.4' % program, + file=sys.stderr) + sys.exit(-1) + return + __all__ = ['uncompyle_file', 'main'] def _load_file(filename): diff --git a/uncompyle6/disas.py b/uncompyle6/disas.py index cb8766c9..dc945f84 100644 --- a/uncompyle6/disas.py +++ b/uncompyle6/disas.py @@ -18,13 +18,15 @@ want to run on Python 2.7. from __future__ import print_function -import importlib, inspect, os, sys +import inspect, os, sys + import uncompyle6 from uncompyle6.scanner import get_scanner def check_object_path(path): if path.endswith(".py"): if uncompyle6.PYTHON3: + import importlib path = importlib.util.cache_from_source(path) return path if not path.endswith(".pyc") and not path.endswith(".pyo"): diff --git a/uncompyle6/opcodes/opcode_25.py b/uncompyle6/opcodes/opcode_25.py index 3a8bf589..038fedf3 100755 --- a/uncompyle6/opcodes/opcode_25.py +++ b/uncompyle6/opcodes/opcode_25.py @@ -47,7 +47,7 @@ def updateGlobal(): globals().update({'PJIT': opmap['JUMP_IF_TRUE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JF': opmap['JUMP_FORWARD']}) - globals().update({k.replace('+', '_'): v for (k, v) in opmap.items()}) + globals().update(dict([(k.replace('+','_'),v) for (k,v) in opmap.items()])) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)}) # Instruction opcodes for compiled code diff --git a/uncompyle6/opcodes/opcode_26.py b/uncompyle6/opcodes/opcode_26.py index 06a6cb5d..e50d6451 100755 --- a/uncompyle6/opcodes/opcode_26.py +++ b/uncompyle6/opcodes/opcode_26.py @@ -47,7 +47,7 @@ def updateGlobal(): globals().update({'PJIT': opmap['JUMP_IF_TRUE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JF': opmap['JUMP_FORWARD']}) - globals().update({k.replace('+', '_'): v for (k, v) in opmap.items()}) + globals().update(dict([(k.replace('+','_'),v) for (k,v) in opmap.items()])) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)}) # Instruction opcodes for compiled code diff --git a/uncompyle6/opcodes/opcode_27.py b/uncompyle6/opcodes/opcode_27.py index 696646c2..87aa5a23 100755 --- a/uncompyle6/opcodes/opcode_27.py +++ b/uncompyle6/opcodes/opcode_27.py @@ -43,7 +43,7 @@ def updateGlobal(): globals().update({'PJIT': opmap['POP_JUMP_IF_TRUE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JF': opmap['JUMP_FORWARD']}) - globals().update({k.replace('+', '_'): v for (k, v) in opmap.items()}) + globals().update(dict([(k.replace('+','_'),v) for (k,v) in opmap.items()])) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)}) # Instruction opcodes for compiled code diff --git a/uncompyle6/scanners/scanner25.py b/uncompyle6/scanners/scanner25.py old mode 100644 new mode 100755 index 7cb17dfe..fb4da77e --- a/uncompyle6/scanners/scanner25.py +++ b/uncompyle6/scanners/scanner25.py @@ -520,7 +520,7 @@ class Scanner25(scan.Scanner): start = 0 end = len(code) - stmt_opcodes = { + stmt_opcodes = set([ SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, @@ -529,15 +529,15 @@ class Scanner25(scan.Scanner): RETURN_VALUE, RAISE_VARARGS, POP_TOP, PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO, JUMP_ABSOLUTE, EXEC_STMT - } + ]) stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] - designator_ops = { + designator_ops = set([ STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SUBSCR, UNPACK_SEQUENCE, JA - } + ]) prelim = self.all_instr(start, end, stmt_opcodes) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py old mode 100644 new mode 100755 index b87126b6..ea8f8bed --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -511,7 +511,7 @@ class Scanner26(scan.Scanner): start = 0 end = len(code) - stmt_opcodes = { + stmt_opcodes = set([ SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, @@ -520,15 +520,15 @@ class Scanner26(scan.Scanner): RETURN_VALUE, RAISE_VARARGS, POP_TOP, PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO, JUMP_ABSOLUTE, EXEC_STMT, - } + ]) stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] - designator_ops = { + designator_ops = set([ STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SUBSCR, UNPACK_SEQUENCE, JA - } + ]) prelim = self.all_instr(start, end, stmt_opcodes) diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py old mode 100644 new mode 100755 index 4635ebf0..b0fde918 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -223,7 +223,7 @@ class Scanner27(scan.Scanner): start = 0 end = len(code) - stmt_opcodes = { + stmt_opcodes = set([ SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_WITH, POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, @@ -234,15 +234,15 @@ class Scanner27(scan.Scanner): STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, DELETE_SLICE_0, DELETE_SLICE_1, DELETE_SLICE_2, DELETE_SLICE_3, JUMP_ABSOLUTE, EXEC_STMT, - } + ]) stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] - designator_ops = { + designator_ops = set([ STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SUBSCR, UNPACK_SEQUENCE, JA - } + ]) prelim = self.all_instr(start, end, stmt_opcodes) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 0874179f..247122a1 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -332,8 +332,8 @@ class Token(scanner.Token): return 0 if JUMP_OPs and t in JUMP_OPs: # ignore offset - return cmp(t, o.type) - return cmp(t, o.type) or cmp(self.pattr, o.pattr) + return t == o.type + return (t == o.type) or self.pattr == o.pattr def __repr__(self): return '%s %s (%s)' % (str(self.type), str(self.attr),