Start using our replacement for inspect.iscode

This commit is contained in:
rocky
2015-12-30 18:43:22 -05:00
parent 5bbe2c4a45
commit 2e91de8355
10 changed files with 90 additions and 64 deletions

53
uncompyle6/code.py Normal file
View File

@@ -0,0 +1,53 @@
import inspect
class Code3:
"""Class for a Python3 code object used when a Python interpreter less than 3 is
working on Python3 bytecode
"""
def __init__(self, co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags, co_code,
co_consts, co_names, co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, co_freevars, co_cellvars):
self.co_argcount = co_argcount
self.co_kwonlyargcount = co_kwonlyargcount
self.co_nlocals = co_nlocals
self.co_stacksize = co_stacksize
self.co_flags = co_flags
self.co_code = co_code
self.co_consts = co_consts
self.co_names = co_names
self.co_varnames = co_varnames
self.co_filename = co_filename
self.co_name = co_name
self.co_firstlineno = co_firstlineno
self.co_lnotab = co_lnotab
self.co_freevars = co_freevars
self.co_cellvars = co_cellvars
class Code2:
"""Class for a Python2 code object used when a Python interpreter less than 3 is
working on Python3 bytecode
"""
def __init__(self, co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags, co_code,
co_consts, co_names, co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, co_freevars, co_cellvars):
self.co_argcount = co_argcount
self.co_kwonlyargcount = co_kwonlyargcount
self.co_nlocals = co_nlocals
self.co_stacksize = co_stacksize
self.co_flags = co_flags
self.co_code = co_code
self.co_consts = co_consts
self.co_names = co_names
self.co_varnames = co_varnames
self.co_filename = co_filename
self.co_name = co_name
self.co_firstlineno = co_firstlineno
self.co_lnotab = co_lnotab
self.co_freevars = co_freevars
self.co_cellvars = co_cellvars
def iscode(obj):
"""A replacement for inspect.iscode() which we can't used because we may be
using a different version of Python than the version of Python used
in creating the byte-compiled objects. Here, he code types may mismatch.
"""
return inspect.iscode(obj) or isinstance(obj, Code3)

View File

@@ -1,7 +1,7 @@
# 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 # Copyright (c) 2015 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
""" """
CPython magic- and version- independent disassembly routines CPython magic- and version- independent disassembly routines
@@ -21,15 +21,16 @@ from __future__ import print_function
import inspect, os, sys import inspect, os, sys
import uncompyle6 import uncompyle6
from uncompyle6.scanner import get_scanner from uncompyle6.code import iscode
from uncompyle6.load import check_object_path, load_module from uncompyle6.load import check_object_path, load_module
from uncompyle6.scanner import get_scanner
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 hasattr(co, 'co_name') assert 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

View File

@@ -1,8 +1,9 @@
from __future__ import print_function from __future__ import print_function
import datetime, inspect, os, sys import datetime, inspect, os, sys
from uncompyle6.disas import check_object_path
from uncompyle6 import verify, PYTHON_VERSION from uncompyle6 import verify, PYTHON_VERSION
from uncompyle6.code import iscode
from uncompyle6.disas import check_object_path
from uncompyle6.semantics import pysource from uncompyle6.semantics import pysource
from uncompyle6.load import load_module from uncompyle6.load import load_module
@@ -13,7 +14,7 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
disassembles and deparses a given code block 'co' disassembles and deparses a given code block 'co'
""" """
assert hasattr(co, 'co_name') assert 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

View File

@@ -20,6 +20,7 @@ from struct import unpack
import uncompyle6.scanners.scanner3 as scan3 import uncompyle6.scanners.scanner3 as scan3
from uncompyle6.magics import PYTHON_MAGIC_INT from uncompyle6.magics import PYTHON_MAGIC_INT
from uncompyle6.code import Code3
internStrings = [] internStrings = []
internObjects = [] internObjects = []
@@ -132,7 +133,7 @@ def load_code_type(fp, magic_int, bytes_for_s=False, code_objects={}):
co_filename = str(co_filename) co_filename = str(co_filename)
co_name = str(co_name) co_name = str(co_name)
if 3020 < magic_int <= 20121: if 3020 < magic_int <= 20121:
code = scan3.Code3(co_argcount, kwonlyargcount, code = Code3(co_argcount, kwonlyargcount,
co_nlocals, co_stacksize, co_flags, co_code, co_nlocals, co_stacksize, co_flags, co_code,
co_consts, co_names, co_varnames, co_filename, co_name, co_consts, co_names, co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, co_freevars, co_cellvars) co_firstlineno, co_lnotab, co_freevars, co_cellvars)

View File

@@ -1,7 +1,7 @@
# 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 # Copyright (c) 2015 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
""" """
Python 2.7 bytecode scanner/deparser Python 2.7 bytecode scanner/deparser
@@ -17,6 +17,7 @@ import dis, inspect
from collections import namedtuple from collections import namedtuple
from array import array from array import array
from uncompyle6.code import iscode
from uncompyle6.opcodes.opcode_27 import * # NOQA from uncompyle6.opcodes.opcode_27 import * # NOQA
import uncompyle6.scanner as scan import uncompyle6.scanner as scan
@@ -138,11 +139,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]
# We can't use inspect.iscode() because we may be if iscode(const):
# using a different version of Python than the
# one that this was byte-compiled on. So the code
# types may mismatch.
if hasattr(const, 'co_name'):
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,6 +13,7 @@ import dis
from collections import namedtuple from collections import namedtuple
from array import array from array import array
from uncompyle6.code import iscode
from uncompyle6.scanner import Token from uncompyle6.scanner import Token
from uncompyle6 import PYTHON_VERSION, PYTHON3 from uncompyle6 import PYTHON_VERSION, PYTHON3
@@ -24,30 +25,6 @@ globals().update(op3.opmap)
import uncompyle6.scanner as scan import uncompyle6.scanner as scan
class Code3:
"""Class for a Python3 code object used when a Python interpreter less than 3 is
working on Python3 bytecode
"""
def __init__(self, co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags, co_code,
co_consts, co_names, co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, co_freevars, co_cellvars):
self.co_argcount = co_argcount
self.co_kwonlyargcount = co_kwonlyargcount
self.co_nlocals = co_nlocals
self.co_stacksize = co_stacksize
self.co_flags = co_flags
self.co_code = co_code
self.co_consts = co_consts
self.co_names = co_names
self.co_varnames = co_varnames
self.co_filename = co_filename
self.co_name = co_name
self.co_firstlineno = co_firstlineno
self.co_lnotab = co_lnotab
self.co_freevars = co_freevars
self.co_cellvars = co_cellvars
class Scanner3(scan.Scanner): class Scanner3(scan.Scanner):
def __init__(self): def __init__(self):
@@ -145,11 +122,7 @@ class Scanner3(scan.Scanner):
if not PYTHON3 and isinstance(const, str): if not PYTHON3 and isinstance(const, str):
if const in code_objects: if const in code_objects:
const = code_objects[const] const = code_objects[const]
# Not sure if'we can inspect.iscode() because we may be if iscode(const):
# using a different version of Python than the
# one that this was byte-compiled on. Is probably okay,
# but we'll use hasattr instead here.
if hasattr(const, 'co_name'):
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

@@ -15,6 +15,7 @@ from array import array
import uncompyle6.scanners.scanner3 as scan3 import uncompyle6.scanners.scanner3 as scan3
from uncompyle6 import PYTHON_VERSION from uncompyle6 import PYTHON_VERSION
from uncompyle6.code import iscode
from uncompyle6.scanner import Token from uncompyle6.scanner import Token
# Get all the opcodes into globals # Get all the opcodes into globals
@@ -92,13 +93,9 @@ class Scanner34(scan3.Scanner3):
pattr = inst.argrepr pattr = inst.argrepr
opname = inst.opname opname = inst.opname
# For constants, the pattr is the same as attr. Using pattr adds
# an extra level of quotes which messes other things up, like getting
# keyword attribute names in a call. I suspect there will be things
# other than LOAD_CONST, but we'll start out with just this for now.
if opname in ['LOAD_CONST']: if opname in ['LOAD_CONST']:
const = inst.argval const = inst.argval
if hasattr(const, 'co_name'): if iscode(const):
if const.co_name == '<lambda>': if const.co_name == '<lambda>':
opname = 'LOAD_LAMBDA' opname = 'LOAD_LAMBDA'
elif const.co_name == '<genexpr>': elif const.co_name == '<genexpr>':

View File

@@ -29,6 +29,7 @@ from __future__ import print_function
import inspect, re, sys import inspect, re, sys
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
from uncompyle6.code import iscode
from uncompyle6.semantics import pysource from uncompyle6.semantics import pysource
from uncompyle6.parser import get_python_parser from uncompyle6.parser import get_python_parser
from uncompyle6 import parser from uncompyle6 import parser
@@ -482,7 +483,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
self.prec = 27 self.prec = 27
code = node[-5].attr code = node[-5].attr
assert hasattr(co, 'co_name') assert iscode(co)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -525,8 +526,8 @@ class FragmentsWalker(pysource.SourceWalker, object):
self.prec = 27 self.prec = 27
code = node[code_index].attr code = node[code_index].attr
assert hasattr(code, 'co_name') assert iscode(code)
## Or Code3 # Or Code3
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1246,7 +1247,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
showgrammar=False): showgrammar=False):
assert hasattr(co, 'co_name') assert iscode(co)
# store final output stream for case of error # store final output stream for case of error
scanner = get_scanner(version) scanner = get_scanner(version)

View File

@@ -67,6 +67,7 @@ from __future__ import print_function
import inspect, sys, re import inspect, sys, re
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
from uncompyle6.code import iscode
from uncompyle6.parser import get_python_parser from uncompyle6.parser import get_python_parser
from uncompyle6.parsers.astnode import AST from uncompyle6.parsers.astnode import AST
from uncompyle6.parsers.spark import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.spark import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
@@ -980,7 +981,7 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = 27 self.prec = 27
code = node[code_index].attr code = node[code_index].attr
assert hasattr(code, 'co_name') assert iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
ast = self.build_ast(code._tokens, code._customize) ast = self.build_ast(code._tokens, code._customize)
self.customize(code._customize) self.customize(code._customize)
@@ -1025,7 +1026,7 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = 27 self.prec = 27
code = node[code_index].attr code = node[code_index].attr
assert hasattr(code, 'co_name') assert iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1448,7 +1449,7 @@ class SourceWalker(GenericASTTraversal, object):
defparams = node[:node[-1].attr] defparams = node[:node[-1].attr]
code = node[code_index].attr code = node[code_index].attr
assert hasattr(code, 'co_name') assert iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1515,7 +1516,7 @@ class SourceWalker(GenericASTTraversal, object):
def build_class(self, code): def build_class(self, code):
"""Dump class definition, doc string and class body.""" """Dump class definition, doc string and class body."""
assert hasattr(code, 'co_name') assert iscode(code)
self.classes.append(self.currentclass) self.classes.append(self.currentclass)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1626,7 +1627,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
disassembles and deparses a given code block 'co' disassembles and deparses a given code block 'co'
""" """
assert hasattr(co, 'co_name') assert iscode(co)
# store final output stream for case of error # store final output stream for case of error
scanner = get_scanner(version) scanner = get_scanner(version)

View File

@@ -13,6 +13,7 @@ import dis, inspect, operator
import uncompyle6 import uncompyle6
import uncompyle6.scanner as scanner import uncompyle6.scanner as scanner
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
from uncompyle6.code import iscode
from uncompyle6.magics import PYTHON_MAGIC_INT from uncompyle6.magics import PYTHON_MAGIC_INT
from uncompyle6.load import load_file, load_module from uncompyle6.load import load_file, load_module
@@ -138,8 +139,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 code_obj1, hasattr('co_name') assert iscode(code_obj1)
assert code_obj2, hasattr('co_name') assert 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)