Tidy a little bit

This commit is contained in:
rocky
2015-12-16 01:52:11 -05:00
parent 8c94acfca0
commit 9fecb48744
14 changed files with 74 additions and 36 deletions

View File

@@ -23,6 +23,10 @@ test check: pytest check-short
check-short: pytest check-short: pytest
$(MAKE) -C test $@ $(MAKE) -C test $@
#: check that disassembly exactly matches Python lib's dis
check-disasm:
$(MAKE) -C test check-disasm
#: Run tests #: Run tests
pytest: pytest:
$(MAKE) -C pytest check $(MAKE) -C pytest check

1
pytest/testdata/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/*.got

View File

@@ -16,6 +16,10 @@ check: check-short check-2.7-ok
## This leads me to believe the problem is an ## This leads me to believe the problem is an
## initialization bug? ## initialization bug?
#: Check deparsing only, but from a different Python version
check-disasm:
$(PYTHON) dis-compare.py
#: Check deparsing only, but from a different Python version #: Check deparsing only, but from a different Python version
check-bytecode: check-bytecode:
$(PYTHON) test_pythonlib.py --bytecode-2.5 $(PYTHON) test_pythonlib.py --bytecode-2.5

BIN
test/bytecode_2.7/if.pyc Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -55,8 +55,10 @@ tests['2.5'] = tests['2.3']
tests['2.6'] = tests['2.5'] 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'] = [
'source_3.4/call_arguments/keyword', 'source_3.4/branching/ifelse',
'source_3.4/call_arguments/positional' 'source_3.4/branching/if'
# 'source_3.4/call_arguments/keyword',
# 'source_3.4/call_arguments/positional'
] ]
tests['3.4'] = [ tests['3.4'] = [

View File

@@ -61,7 +61,7 @@ try:
except ImportError: except ImportError:
from io import StringIO from io import StringIO
import sys, inspect, types, re import sys, inspect, re
# FIXME: remove uncompyle dups # FIXME: remove uncompyle dups
@@ -464,7 +464,7 @@ class Traverser(walker.Walker, object):
self.prec = 27 self.prec = 27
code = node[-5].attr code = node[-5].attr
assert isinstance(code, types.CodeType) assert inspect.iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1115,7 +1115,7 @@ class Traverser(walker.Walker, object):
pass pass
def deparse(version, co, out=StringIO(), showasm=0, showast=0): def deparse(version, co, out=StringIO(), showasm=0, showast=0):
assert isinstance(co, types.CodeType) assert inspect.iscode(co)
# store final output stream for case of error # store final output stream for case of error
__real_out = out or sys.stdout __real_out = out or sys.stdout
try: try:

View File

@@ -1,29 +1,41 @@
# Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2015 by Rocky Bernstein
""" """
CPython magic- and version- independent disassembly routines CPython magic- and version- independent disassembly routines
Copyright (c) 1999 John Aycock There are two reasons we can't use Python's built-in routines
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> from dis. First, the bytecode we are extracting may be from a different
Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org> version of Python (different magic number) than the version of Python
Copyright (c) 2015 by Rocky Bernstein that is doing the extraction.
This is needed when the bytecode extracted is from Second, we need structured instruction information for the
a different version than the currently-running Python. (de)-parsing step. Python 3.4 and up provides this, but we still do
want to run on Python 2.7.
When the two are the same, you can simply use Python's built-in disassemble
""" """
from __future__ import print_function from __future__ import print_function
import os, sys, types import importlib, inspect, os, sys
import uncompyle6 import uncompyle6
def check_object_path(path):
if path.endswith(".py"):
if uncompyle6.PYTHON3:
path = importlib.util.cache_from_source(path)
return path
if not path.endswith(".pyc") and not path.endswith(".pyo"):
raise ValueError("path must point to a .py or .pyc file")
return path
def disco(version, co, out=None): def disco(version, co, out=None):
""" """
diassembles and deparses a given code block 'co' diassembles and deparses a given code block 'co'
""" """
assert isinstance(co, types.CodeType) assert inspect.iscode(co)
# store final output stream for case of error # store final output stream for case of error
real_out = out or sys.stdout real_out = out or sys.stdout
@@ -59,7 +71,11 @@ def disco(version, co, out=None):
def disassemble_file(filename, outstream=None): def disassemble_file(filename, outstream=None):
""" """
disassemble Python byte-code file (.pyc) disassemble Python byte-code file (.pyc)
If given a Python source file (".py") file, we'll
try to find the corresponding compiled object.
""" """
filename = check_object_path(filename)
version, co = uncompyle6.load_module(filename) version, co = uncompyle6.load_module(filename)
if type(co) == list: if type(co) == list:
for con in co: for con in co:
@@ -144,8 +160,12 @@ def _test():
"""Simple test program to disassemble a file.""" """Simple test program to disassemble a file."""
argc = len(sys.argv) argc = len(sys.argv)
if argc != 2: if argc != 2:
if argc == 1 and uncompyle6.PYTHON3:
fn = __file__
else:
sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__) sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__)
sys.exit(2) sys.exit(2)
else:
fn = sys.argv[1] fn = sys.argv[1]
disassemble_file(fn) disassemble_file(fn)

View File

@@ -1,11 +1,6 @@
""" """
CPython magic- and version- independent marshal routines CPython magic- and version- independent marshal routines
Copyright (c) 1999 John Aycock
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
Copyright (c) 2015 by Rocky Bernstein
This is needed when the bytecode extracted is from This is needed when the bytecode extracted is from
a different version than the currently-running Python. a different version than the currently-running Python.
@@ -13,6 +8,11 @@ When the two are the same, you can simply use Python's built-in marshal.loads()
to produce a code object to produce a code object
""" """
# Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2015 by Rocky Bernstein
from __future__ import print_function from __future__ import print_function
import imp, sys, types import imp, sys, types

View File

@@ -20,9 +20,11 @@ __all__ = ['Token', 'Scanner', 'Code']
import sys import sys
# FIXME: DRY
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
intern = sys.intern intern = sys.intern
L65536 = 65536 L65536 = 65536
def cmp(a, b): def cmp(a, b):
return (a > b) - (a < b) return (a > b) - (a < b)
else: else:

View File

@@ -13,7 +13,7 @@ Python 3 and other versions of Python. Also, we save token
information for later use in deparsing. information for later use in deparsing.
""" """
import types import inspect
from collections import namedtuple from collections import namedtuple
from array import array from array import array
@@ -152,7 +152,7 @@ class Scanner25(scan.Scanner):
continue continue
if op in hasconst: if op in hasconst:
const = co.co_consts[oparg] const = co.co_consts[oparg]
if isinstance(const, types.CodeType): if inspect.iscode(const):
oparg = const oparg = const
if const.co_name == '<lambda>': if const.co_name == '<lambda>':
assert op_name == 'LOAD_CONST' assert op_name == 'LOAD_CONST'

View File

@@ -13,7 +13,7 @@ other versions of Python. Also, we save token information for later
use in deparsing. use in deparsing.
""" """
import types import inspect
from collections import namedtuple from collections import namedtuple
from array import array from array import array
@@ -147,7 +147,7 @@ class Scanner26(scan.Scanner):
continue continue
if op in hasconst: if op in hasconst:
const = co.co_consts[oparg] const = co.co_consts[oparg]
if isinstance(const, types.CodeType): if inspect.iscode(const):
oparg = const oparg = const
if const.co_name == '<lambda>': if const.co_name == '<lambda>':
assert op_name == 'LOAD_CONST' assert op_name == 'LOAD_CONST'

View File

@@ -13,7 +13,7 @@ for later use in deparsing.
from __future__ import print_function from __future__ import print_function
import dis, types import dis, inspect
from collections import namedtuple from collections import namedtuple
from array import array from array import array
@@ -136,7 +136,7 @@ class Scanner27(scan.Scanner):
continue continue
if op in hasconst: if op in hasconst:
const = co.co_consts[oparg] const = co.co_consts[oparg]
if isinstance(const, types.CodeType): if inspect.iscode(const):
oparg = const oparg = const
if const.co_name == '<lambda>': if const.co_name == '<lambda>':
assert op_name == 'LOAD_CONST' assert op_name == 'LOAD_CONST'

View File

@@ -1,18 +1,23 @@
from __future__ import print_function
# #
# (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# #
# byte-code verifier for uncompyle # byte-code verifier for uncompyle
# #
import dis, operator, sys, types from __future__ import print_function
import dis, inspect, operator, sys, types
import uncompyle6 import uncompyle6
import uncompyle6.scanner as scanner import uncompyle6.scanner as scanner
# FIXME: DRY
if (sys.version_info >= (3, 0)): if (sys.version_info >= (3, 0)):
truediv = operator.truediv truediv = operator.truediv
def cmp(a, b):
return (a > b) - (a < b)
from functools import reduce
else: else:
truediv = operator.div truediv = operator.div
@@ -127,8 +132,8 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''):
This is the main part of this module. This is the main part of this module.
""" """
# print code_obj1, type(code_obj2) # print code_obj1, type(code_obj2)
assert isinstance(code_obj1, types.CodeType) assert inspect.iscode(code_obj1)
assert isinstance(code_obj2, types.CodeType) assert inspect.iscode(code_obj2)
# print dir(code_obj1) # print dir(code_obj1)
if isinstance(code_obj1, object): if isinstance(code_obj1, object):
# new style classes (Python 2.2) # new style classes (Python 2.2)