Python 2.6 compatability via ericfrederich's patch. DRY version-checking code

This commit is contained in:
rocky
2015-12-17 20:48:54 -05:00
parent a309a77ea7
commit 2fc2d6c699
14 changed files with 72 additions and 56 deletions

View File

@@ -23,10 +23,14 @@ test check: pytest check-long
check-long: pytest check-long: pytest
$(MAKE) -C test check-2.7 $(MAKE) -C test check-2.7
#: Run tests #: Run quick tests
check-short: pytest check-short: pytest
$(MAKE) -C test check-short-2.7 $(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 that disassembly exactly matches Python lib's dis
check-disasm: check-disasm:

View File

@@ -3,14 +3,19 @@
# #
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com> # Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
# #
""" from __future__ import print_function
Usage: pydisassemble [OPTIONS]... FILE import sys, os, getopt
program = os.path.basename(__file__)
__doc__ = """
Usage: %s [OPTIONS]... FILE
Examples: Examples:
pydisassemble foo.pyc %s foo.pyc
pydisassemble foo.py %s foo.py
pydisassemble -o foo.pydis foo.pyc %s -o foo.pydis foo.pyc
pydisassemble -o /tmp foo.pyc %s -o /tmp foo.pyc
Options: Options:
-o <path> output decompiled files to this path: -o <path> output decompiled files to this path:
@@ -19,21 +24,16 @@ Options:
<path> <path>
--help show this message --help show this message
""" """ % ((program,) * 5)
from __future__ import print_function
Usage_short = \ Usage_short = \
"pydissassemble [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." "%s [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." % program
import sys, os, getopt
import os.path
from uncompyle6 import check_python_version
from uncompyle6.disas import disassemble_files from uncompyle6.disas import disassemble_files
if sys.version[:3] != '2.7' and sys.version[:3] != '3.4': check_python_version(program)
print('Error: pydisassemble requires Python 2.7 or 3.4.', file=sys.stderr)
sys.exit(-1)
outfile = '-' outfile = '-'
out_base = None out_base = None

View File

@@ -41,18 +41,17 @@ Extensions of generated files:
""" """
from __future__ import print_function from __future__ import print_function
import sys, os, getopt
program = os.path.basename(__file__)
Usage_short = \ Usage_short = \
"uncompyle6 [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." "%s [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." % program
import sys, os, getopt from uncompyle6 import main, status_msg, verify, check_python_version
import os.path
from uncompyle6 import main, status_msg, verify
import time import time
if sys.version[:3] != '2.7' and sys.version[:3] != '3.4': check_python_version(program)
print('Error: uncompyle6 requires Python 2.7 or 3.4.', file=sys.stderr)
sys.exit(-1)
showasm = showast = do_verify = recurse_dirs = False showasm = showast = do_verify = recurse_dirs = False
numproc = 0 numproc = 0

View File

@@ -53,7 +53,6 @@ tests['2.2'] = ['divide_future', 'divide_no_future', 'iterators',
tests['2.3'] = tests['2.2'] tests['2.3'] = tests['2.2']
tests['2.5'] = tests['2.3'] tests['2.5'] = tests['2.3']
tests['2.6'] = tests['2.5']
# tests['2.7'] = ['mine'] + tests['2.6'] # tests['2.7'] = ['mine'] + tests['2.6']
tests['2.7'] = [ tests['2.7'] = [
'simple-source/branching/ifelse', 'simple-source/branching/ifelse',
@@ -61,6 +60,7 @@ tests['2.7'] = [
# 'simple-source/call_arguments/keyword', # 'simple-source/call_arguments/keyword',
# 'simple-source/call_arguments/positional' # 'simple-source/call_arguments/positional'
] ]
tests['2.6'] = tests['2.7']
def file_matches(files, root, basenames, patterns): def file_matches(files, root, basenames, patterns):
files.extend( files.extend(

View File

@@ -6,7 +6,7 @@
from __future__ import print_function from __future__ import print_function
import dis, os.path, sys import dis, os.path
try: try:
from StringIO import StringIO from StringIO import StringIO
@@ -16,17 +16,16 @@ except ImportError:
program = os.path.basename(__file__) program = os.path.basename(__file__)
__doc__ = """ __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 import uncompyle6
from uncompyle6 import PYTHON_VERSION_STR, check_python_version
from uncompyle6.disas import disco from uncompyle6.disas import disco
version = sys.version[:3]
def inst_fmt(inst): def inst_fmt(inst):
if inst.starts_line: if inst.starts_line:
return '\n%4d %6s\t%-17s %r' % (inst.starts_line, inst.offset, inst.opname, 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): def compare_ok(version, co):
out = StringIO() out = StringIO()
if version == 2.7: if version in (2.6, 2.7):
dis.disco(co) dis.disco(co)
return return True
bytecode = dis.Bytecode(co) bytecode = dis.Bytecode(co)
disco(version, co, out) disco(version, co, out)
@@ -61,10 +60,7 @@ def compare_ok(version, co):
i += 1 i += 1
return True return True
if version != '2.7' and version != '3.4': check_python_version(program)
print('Error: {0} requires Python 2.7 or 3.4.'.format(program),
file=sys.stderr)
sys.exit(-1)
# if len(sys.argv) != 2: # if len(sys.argv) != 2:
# print(usage_short, file=sys.stderr) # print(usage_short, file=sys.stderr)
@@ -85,7 +81,7 @@ files=[
] ]
for base in 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) version, co = uncompyle6.load_module(filename)
ok = True ok = True
if type(co) == list: if type(co) == list:

View File

@@ -33,7 +33,7 @@ from __future__ import print_function
import os, marshal, sys, types 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)) PYTHON3 = (sys.version_info >= (3, 0))
import uncompyle6 import uncompyle6
@@ -43,6 +43,21 @@ import uncompyle6.marsh
from uncompyle6 import walker, verify, magics from uncompyle6 import walker, verify, magics
sys.setrecursionlimit(5000) 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'] __all__ = ['uncompyle_file', 'main']
def _load_file(filename): def _load_file(filename):

View File

@@ -18,13 +18,15 @@ want to run on Python 2.7.
from __future__ import print_function from __future__ import print_function
import importlib, inspect, os, sys import inspect, os, sys
import uncompyle6 import uncompyle6
from uncompyle6.scanner import get_scanner from uncompyle6.scanner import get_scanner
def check_object_path(path): def check_object_path(path):
if path.endswith(".py"): if path.endswith(".py"):
if uncompyle6.PYTHON3: if uncompyle6.PYTHON3:
import importlib
path = importlib.util.cache_from_source(path) path = importlib.util.cache_from_source(path)
return path return path
if not path.endswith(".pyc") and not path.endswith(".pyo"): if not path.endswith(".pyc") and not path.endswith(".pyo"):

View File

@@ -47,7 +47,7 @@ def updateGlobal():
globals().update({'PJIT': opmap['JUMP_IF_TRUE']}) globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']})
globals().update({'JF': opmap['JUMP_FORWARD']}) 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)}) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code # Instruction opcodes for compiled code

View File

@@ -47,7 +47,7 @@ def updateGlobal():
globals().update({'PJIT': opmap['JUMP_IF_TRUE']}) globals().update({'PJIT': opmap['JUMP_IF_TRUE']})
globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']})
globals().update({'JF': opmap['JUMP_FORWARD']}) 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)}) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code # Instruction opcodes for compiled code

View File

@@ -43,7 +43,7 @@ def updateGlobal():
globals().update({'PJIT': opmap['POP_JUMP_IF_TRUE']}) globals().update({'PJIT': opmap['POP_JUMP_IF_TRUE']})
globals().update({'JA': opmap['JUMP_ABSOLUTE']}) globals().update({'JA': opmap['JUMP_ABSOLUTE']})
globals().update({'JF': opmap['JUMP_FORWARD']}) 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)}) globals().update({'JUMP_OPs': map(lambda op: opname[op], hasjrel + hasjabs)})
# Instruction opcodes for compiled code # Instruction opcodes for compiled code

8
uncompyle6/scanners/scanner25.py Normal file → Executable file
View File

@@ -520,7 +520,7 @@ class Scanner25(scan.Scanner):
start = 0 start = 0
end = len(code) end = len(code)
stmt_opcodes = { stmt_opcodes = set([
SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP,
SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT,
POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF,
@@ -529,15 +529,15 @@ class Scanner25(scan.Scanner):
RETURN_VALUE, RAISE_VARARGS, POP_TOP, RETURN_VALUE, RAISE_VARARGS, POP_TOP,
PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO, PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO,
JUMP_ABSOLUTE, EXEC_STMT JUMP_ABSOLUTE, EXEC_STMT
} ])
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] 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_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} ])
prelim = self.all_instr(start, end, stmt_opcodes) prelim = self.all_instr(start, end, stmt_opcodes)

8
uncompyle6/scanners/scanner26.py Normal file → Executable file
View File

@@ -511,7 +511,7 @@ class Scanner26(scan.Scanner):
start = 0 start = 0
end = len(code) end = len(code)
stmt_opcodes = { stmt_opcodes = set([
SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP,
SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT,
POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF,
@@ -520,15 +520,15 @@ class Scanner26(scan.Scanner):
RETURN_VALUE, RAISE_VARARGS, POP_TOP, RETURN_VALUE, RAISE_VARARGS, POP_TOP,
PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO, PRINT_EXPR, PRINT_ITEM, PRINT_NEWLINE, PRINT_ITEM_TO, PRINT_NEWLINE_TO,
JUMP_ABSOLUTE, EXEC_STMT, JUMP_ABSOLUTE, EXEC_STMT,
} ])
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] 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_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} ])
prelim = self.all_instr(start, end, stmt_opcodes) prelim = self.all_instr(start, end, stmt_opcodes)

8
uncompyle6/scanners/scanner27.py Normal file → Executable file
View File

@@ -223,7 +223,7 @@ class Scanner27(scan.Scanner):
start = 0 start = 0
end = len(code) end = len(code)
stmt_opcodes = { stmt_opcodes = set([
SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP,
SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_WITH, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_WITH,
POP_BLOCK, STORE_FAST, DELETE_FAST, STORE_DEREF, 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, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
DELETE_SLICE_0, DELETE_SLICE_1, DELETE_SLICE_2, DELETE_SLICE_3, DELETE_SLICE_0, DELETE_SLICE_1, DELETE_SLICE_2, DELETE_SLICE_3,
JUMP_ABSOLUTE, EXEC_STMT, JUMP_ABSOLUTE, EXEC_STMT,
} ])
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] 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_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} ])
prelim = self.all_instr(start, end, stmt_opcodes) prelim = self.all_instr(start, end, stmt_opcodes)

View File

@@ -332,8 +332,8 @@ class Token(scanner.Token):
return 0 return 0
if JUMP_OPs and t in JUMP_OPs: if JUMP_OPs and t in JUMP_OPs:
# ignore offset # ignore offset
return cmp(t, o.type) return t == o.type
return cmp(t, o.type) or cmp(self.pattr, o.pattr) return (t == o.type) or self.pattr == o.pattr
def __repr__(self): def __repr__(self):
return '%s %s (%s)' % (str(self.type), str(self.attr), return '%s %s (%s)' % (str(self.type), str(self.attr),