Issue #26733: Disassembling a class now disassembles class and static methods.
Patch by Xiang Zhang.
This commit is contained in:
parent
21ce717eaf
commit
585c93daea
|
@ -139,11 +139,11 @@ operation is being performed, so the intermediate analysis object isn't useful:
|
||||||
Disassemble the *x* object. *x* can denote either a module, a class, a
|
Disassemble the *x* object. *x* can denote either a module, a class, a
|
||||||
method, a function, a generator, a code object, a string of source code or
|
method, a function, a generator, a code object, a string of source code or
|
||||||
a byte sequence of raw bytecode. For a module, it disassembles all functions.
|
a byte sequence of raw bytecode. For a module, it disassembles all functions.
|
||||||
For a class, it disassembles all methods. For a code object or sequence of
|
For a class, it disassembles all methods (including class and static methods).
|
||||||
raw bytecode, it prints one line per bytecode instruction. Strings are first
|
For a code object or sequence of raw bytecode, it prints one line per bytecode
|
||||||
compiled to code objects with the :func:`compile` built-in function before being
|
instruction. Strings are first compiled to code objects with the :func:`compile`
|
||||||
disassembled. If no object is provided, this function disassembles the last
|
built-in function before being disassembled. If no object is provided, this
|
||||||
traceback.
|
function disassembles the last traceback.
|
||||||
|
|
||||||
The disassembly is written as text to the supplied *file* argument if
|
The disassembly is written as text to the supplied *file* argument if
|
||||||
provided and to ``sys.stdout`` otherwise.
|
provided and to ``sys.stdout`` otherwise.
|
||||||
|
|
|
@ -13,7 +13,8 @@ __all__ = ["code_info", "dis", "disassemble", "distb", "disco",
|
||||||
"get_instructions", "Instruction", "Bytecode"] + _opcodes_all
|
"get_instructions", "Instruction", "Bytecode"] + _opcodes_all
|
||||||
del _opcodes_all
|
del _opcodes_all
|
||||||
|
|
||||||
_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
|
_have_code = (types.MethodType, types.FunctionType, types.CodeType,
|
||||||
|
classmethod, staticmethod, type)
|
||||||
|
|
||||||
def _try_compile(source, name):
|
def _try_compile(source, name):
|
||||||
"""Attempts to compile the given source, first as an expression and
|
"""Attempts to compile the given source, first as an expression and
|
||||||
|
|
|
@ -30,6 +30,14 @@ class _C:
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
self.x = x == 1
|
self.x = x == 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sm(x):
|
||||||
|
x = x == 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cm(cls, x):
|
||||||
|
cls.x = x == 1
|
||||||
|
|
||||||
dis_c_instance_method = """\
|
dis_c_instance_method = """\
|
||||||
%3d 0 LOAD_FAST 1 (x)
|
%3d 0 LOAD_FAST 1 (x)
|
||||||
3 LOAD_CONST 1 (1)
|
3 LOAD_CONST 1 (1)
|
||||||
|
@ -50,6 +58,37 @@ dis_c_instance_method_bytes = """\
|
||||||
18 RETURN_VALUE
|
18 RETURN_VALUE
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
dis_c_class_method = """\
|
||||||
|
%3d 0 LOAD_FAST 1 (x)
|
||||||
|
3 LOAD_CONST 1 (1)
|
||||||
|
6 COMPARE_OP 2 (==)
|
||||||
|
9 LOAD_FAST 0 (cls)
|
||||||
|
12 STORE_ATTR 0 (x)
|
||||||
|
15 LOAD_CONST 0 (None)
|
||||||
|
18 RETURN_VALUE
|
||||||
|
""" % (_C.cm.__code__.co_firstlineno + 2,)
|
||||||
|
|
||||||
|
dis_c_static_method = """\
|
||||||
|
%3d 0 LOAD_FAST 0 (x)
|
||||||
|
3 LOAD_CONST 1 (1)
|
||||||
|
6 COMPARE_OP 2 (==)
|
||||||
|
9 STORE_FAST 0 (x)
|
||||||
|
12 LOAD_CONST 0 (None)
|
||||||
|
15 RETURN_VALUE
|
||||||
|
""" % (_C.sm.__code__.co_firstlineno + 2,)
|
||||||
|
|
||||||
|
# Class disassembling info has an extra newline at end.
|
||||||
|
dis_c = """\
|
||||||
|
Disassembly of %s:
|
||||||
|
%s
|
||||||
|
Disassembly of %s:
|
||||||
|
%s
|
||||||
|
Disassembly of %s:
|
||||||
|
%s
|
||||||
|
""" % (_C.__init__.__name__, dis_c_instance_method,
|
||||||
|
_C.cm.__name__, dis_c_class_method,
|
||||||
|
_C.sm.__name__, dis_c_static_method)
|
||||||
|
|
||||||
def _f(a):
|
def _f(a):
|
||||||
print(a)
|
print(a)
|
||||||
return 1
|
return 1
|
||||||
|
@ -311,13 +350,22 @@ class DisTests(unittest.TestCase):
|
||||||
def test_disassemble_bytes(self):
|
def test_disassemble_bytes(self):
|
||||||
self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
|
self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code)
|
||||||
|
|
||||||
def test_disassemble_method(self):
|
def test_disassemble_class(self):
|
||||||
|
self.do_disassembly_test(_C, dis_c)
|
||||||
|
|
||||||
|
def test_disassemble_instance_method(self):
|
||||||
self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
|
self.do_disassembly_test(_C(1).__init__, dis_c_instance_method)
|
||||||
|
|
||||||
def test_disassemble_method_bytes(self):
|
def test_disassemble_instance_method_bytes(self):
|
||||||
method_bytecode = _C(1).__init__.__code__.co_code
|
method_bytecode = _C(1).__init__.__code__.co_code
|
||||||
self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
|
self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes)
|
||||||
|
|
||||||
|
def test_disassemble_static_method(self):
|
||||||
|
self.do_disassembly_test(_C.sm, dis_c_static_method)
|
||||||
|
|
||||||
|
def test_disassemble_class_method(self):
|
||||||
|
self.do_disassembly_test(_C.cm, dis_c_class_method)
|
||||||
|
|
||||||
def test_disassemble_generator(self):
|
def test_disassemble_generator(self):
|
||||||
gen_func_disas = self.get_disassembly(_g) # Disassemble generator function
|
gen_func_disas = self.get_disassembly(_g) # Disassemble generator function
|
||||||
gen_disas = self.get_disassembly(_g(1)) # Disassemble generator itself
|
gen_disas = self.get_disassembly(_g(1)) # Disassemble generator itself
|
||||||
|
|
|
@ -107,6 +107,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #26733: Disassembling a class now disassembles class and static methods.
|
||||||
|
Patch by Xiang Zhang.
|
||||||
|
|
||||||
- Issue #26801: Fix error handling in :func:`shutil.get_terminal_size`, catch
|
- Issue #26801: Fix error handling in :func:`shutil.get_terminal_size`, catch
|
||||||
:exc:`AttributeError` instead of :exc:`NameError`. Patch written by Emanuel
|
:exc:`AttributeError` instead of :exc:`NameError`. Patch written by Emanuel
|
||||||
Barry.
|
Barry.
|
||||||
|
|
Loading…
Reference in New Issue