Issue #21947: handle generator-iterator objects in dis
Patch by Clement Rouault.
This commit is contained in:
parent
d0d64cfb59
commit
efd5df9e52
|
@ -48,8 +48,8 @@ compiled code.
|
||||||
|
|
||||||
.. class:: Bytecode(x, *, first_line=None, current_offset=None)
|
.. class:: Bytecode(x, *, first_line=None, current_offset=None)
|
||||||
|
|
||||||
Analyse the bytecode corresponding to a function, method, string of
|
Analyse the bytecode corresponding to a function, generator, method,
|
||||||
source code, or a code object (as returned by :func:`compile`).
|
string of source code, or a code object (as returned by :func:`compile`).
|
||||||
|
|
||||||
This is a convenience wrapper around many of the functions listed below,
|
This is a convenience wrapper around many of the functions listed below,
|
||||||
most notably :func:`get_instructions`, as iterating over a
|
most notably :func:`get_instructions`, as iterating over a
|
||||||
|
@ -112,7 +112,7 @@ object isn't useful:
|
||||||
.. function:: code_info(x)
|
.. function:: code_info(x)
|
||||||
|
|
||||||
Return a formatted multi-line string with detailed code object information
|
Return a formatted multi-line string with detailed code object information
|
||||||
for the supplied function, method, source code string or code object.
|
for the supplied function, generator, method, source code string or code object.
|
||||||
|
|
||||||
Note that the exact contents of code info strings are highly implementation
|
Note that the exact contents of code info strings are highly implementation
|
||||||
dependent and they may change arbitrarily across Python VMs or Python
|
dependent and they may change arbitrarily across Python VMs or Python
|
||||||
|
@ -139,11 +139,11 @@ object isn't useful:
|
||||||
.. function:: dis(x=None, *, file=None)
|
.. function:: dis(x=None, *, file=None)
|
||||||
|
|
||||||
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 code object, a string of source code or a byte sequence
|
method, a function, a generator, a code object, a string of source code or
|
||||||
of raw bytecode. For a module, it disassembles all functions. For a class,
|
a byte sequence of raw bytecode. For a module, it disassembles all functions.
|
||||||
it disassembles all methods. For a code object or sequence of raw bytecode,
|
For a class, it disassembles all methods. For a code object or sequence of
|
||||||
it prints one line per bytecode instruction. Strings are first compiled to
|
raw bytecode, it prints one line per bytecode instruction. Strings are first
|
||||||
code objects with the :func:`compile` built-in function before being
|
compiled to code objects with the :func:`compile` built-in function before being
|
||||||
disassembled. If no object is provided, this function disassembles the last
|
disassembled. If no object is provided, this function disassembles the last
|
||||||
traceback.
|
traceback.
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ def _try_compile(source, name):
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def dis(x=None, *, file=None):
|
def dis(x=None, *, file=None):
|
||||||
"""Disassemble classes, methods, functions, or code.
|
"""Disassemble classes, methods, functions, generators, or code.
|
||||||
|
|
||||||
With no argument, disassemble the last traceback.
|
With no argument, disassemble the last traceback.
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ def dis(x=None, *, file=None):
|
||||||
x = x.__func__
|
x = x.__func__
|
||||||
if hasattr(x, '__code__'): # Function
|
if hasattr(x, '__code__'): # Function
|
||||||
x = x.__code__
|
x = x.__code__
|
||||||
|
if hasattr(x, 'gi_code'): # Generator
|
||||||
|
x = x.gi_code
|
||||||
if hasattr(x, '__dict__'): # Class or module
|
if hasattr(x, '__dict__'): # Class or module
|
||||||
items = sorted(x.__dict__.items())
|
items = sorted(x.__dict__.items())
|
||||||
for name, x1 in items:
|
for name, x1 in items:
|
||||||
|
@ -99,11 +101,13 @@ def pretty_flags(flags):
|
||||||
return ", ".join(names)
|
return ", ".join(names)
|
||||||
|
|
||||||
def _get_code_object(x):
|
def _get_code_object(x):
|
||||||
"""Helper to handle methods, functions, strings and raw code objects"""
|
"""Helper to handle methods, functions, generators, strings and raw code objects"""
|
||||||
if hasattr(x, '__func__'): # Method
|
if hasattr(x, '__func__'): # Method
|
||||||
x = x.__func__
|
x = x.__func__
|
||||||
if hasattr(x, '__code__'): # Function
|
if hasattr(x, '__code__'): # Function
|
||||||
x = x.__code__
|
x = x.__code__
|
||||||
|
if hasattr(x, 'gi_code'): # Generator
|
||||||
|
x = x.gi_code
|
||||||
if isinstance(x, str): # Source code
|
if isinstance(x, str): # Source code
|
||||||
x = _try_compile(x, "<disassembly>")
|
x = _try_compile(x, "<disassembly>")
|
||||||
if hasattr(x, 'co_code'): # Code object
|
if hasattr(x, 'co_code'): # Code object
|
||||||
|
|
|
@ -229,6 +229,9 @@ dis_traceback = """\
|
||||||
TRACEBACK_CODE.co_firstlineno + 4,
|
TRACEBACK_CODE.co_firstlineno + 4,
|
||||||
TRACEBACK_CODE.co_firstlineno + 5)
|
TRACEBACK_CODE.co_firstlineno + 5)
|
||||||
|
|
||||||
|
def _g(x):
|
||||||
|
yield x
|
||||||
|
|
||||||
class DisTests(unittest.TestCase):
|
class DisTests(unittest.TestCase):
|
||||||
|
|
||||||
def get_disassembly(self, func, lasti=-1, wrapper=True):
|
def get_disassembly(self, func, lasti=-1, wrapper=True):
|
||||||
|
@ -314,6 +317,11 @@ class DisTests(unittest.TestCase):
|
||||||
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_generator(self):
|
||||||
|
gen_func_disas = self.get_disassembly(_g) # Disassemble generator function
|
||||||
|
gen_disas = self.get_disassembly(_g(1)) # Disassemble generator itself
|
||||||
|
self.assertEqual(gen_disas, gen_func_disas)
|
||||||
|
|
||||||
def test_dis_none(self):
|
def test_dis_none(self):
|
||||||
try:
|
try:
|
||||||
del sys.last_traceback
|
del sys.last_traceback
|
||||||
|
|
|
@ -1145,6 +1145,7 @@ Guido van Rossum
|
||||||
Just van Rossum
|
Just van Rossum
|
||||||
Hugo van Rossum
|
Hugo van Rossum
|
||||||
Saskia van Rossum
|
Saskia van Rossum
|
||||||
|
Clement Rouault
|
||||||
Donald Wallace Rouse II
|
Donald Wallace Rouse II
|
||||||
Liam Routt
|
Liam Routt
|
||||||
Todd Rovito
|
Todd Rovito
|
||||||
|
|
|
@ -108,6 +108,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #21947: The dis module can now disassemble generator-iterator
|
||||||
|
objects based on their gi_code attribute. Patch by Clement Rouault.
|
||||||
|
|
||||||
- Issue #16133: The asynchat.async_chat.handle_read() method now ignores
|
- Issue #16133: The asynchat.async_chat.handle_read() method now ignores
|
||||||
BlockingIOError exceptions.
|
BlockingIOError exceptions.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue