Issue 6507: accept source strings directly in dis.dis(). Original patch by Daniel Urban
This commit is contained in:
parent
9bf2b3ae6a
commit
5c8b54eb04
|
@ -33,10 +33,13 @@ The :mod:`dis` module defines the following functions and constants:
|
||||||
.. function:: dis(x=None)
|
.. function:: dis(x=None)
|
||||||
|
|
||||||
Disassemble the *x* object. *x* can denote either a module, a
|
Disassemble the *x* object. *x* can denote either a module, a
|
||||||
class, a method, a function, or a code object. For a module, it disassembles
|
class, a method, a function, a code object, a string of source code or a
|
||||||
all functions. For a class, it disassembles all methods. For a single code
|
byte sequence of raw bytecode. For a module, it disassembles all
|
||||||
sequence, it prints one line per bytecode instruction. If no object is
|
functions. For a class, it disassembles all methods. For a code object
|
||||||
provided, it disassembles the last traceback.
|
or sequence of raw bytecode, it prints one line per bytecode instruction.
|
||||||
|
Strings are first compiled to code objects with the :func:`compile`
|
||||||
|
built-in function before being disassembled. If no object is provided,
|
||||||
|
this function disassembles the last traceback.
|
||||||
|
|
||||||
|
|
||||||
.. function:: distb(tb=None)
|
.. function:: distb(tb=None)
|
||||||
|
|
26
Lib/dis.py
26
Lib/dis.py
|
@ -12,6 +12,22 @@ del _opcodes_all
|
||||||
|
|
||||||
_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
|
_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
|
||||||
|
|
||||||
|
def _try_compile(source, name):
|
||||||
|
"""Attempts to compile the given source, first as an expression and
|
||||||
|
then as a statement if the first approach fails.
|
||||||
|
|
||||||
|
Utility function to accept strings in functions that otherwise
|
||||||
|
expect code objects
|
||||||
|
"""
|
||||||
|
# ncoghlan: currently only used by dis(), but plan to add an
|
||||||
|
# equivalent for show_code() as well (but one that returns a
|
||||||
|
# string rather than printing directly to the console)
|
||||||
|
try:
|
||||||
|
c = compile(source, name, 'eval')
|
||||||
|
except SyntaxError:
|
||||||
|
c = compile(source, name, 'exec')
|
||||||
|
return c
|
||||||
|
|
||||||
def dis(x=None):
|
def dis(x=None):
|
||||||
"""Disassemble classes, methods, functions, or code.
|
"""Disassemble classes, methods, functions, or code.
|
||||||
|
|
||||||
|
@ -38,7 +54,9 @@ def dis(x=None):
|
||||||
elif hasattr(x, 'co_code'):
|
elif hasattr(x, 'co_code'):
|
||||||
disassemble(x)
|
disassemble(x)
|
||||||
elif isinstance(x, (bytes, bytearray)):
|
elif isinstance(x, (bytes, bytearray)):
|
||||||
disassemble_string(x)
|
_disassemble_bytes(x)
|
||||||
|
elif isinstance(x, str):
|
||||||
|
_disassemble_str(x)
|
||||||
else:
|
else:
|
||||||
raise TypeError("don't know how to disassemble %s objects" %
|
raise TypeError("don't know how to disassemble %s objects" %
|
||||||
type(x).__name__)
|
type(x).__name__)
|
||||||
|
@ -157,7 +175,7 @@ def disassemble(co, lasti=-1):
|
||||||
print('(' + free[oparg] + ')', end=' ')
|
print('(' + free[oparg] + ')', end=' ')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
def disassemble_string(code, lasti=-1, varnames=None, names=None,
|
def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
|
||||||
constants=None):
|
constants=None):
|
||||||
labels = findlabels(code)
|
labels = findlabels(code)
|
||||||
n = len(code)
|
n = len(code)
|
||||||
|
@ -196,6 +214,10 @@ def disassemble_string(code, lasti=-1, varnames=None, names=None,
|
||||||
print('(' + cmp_op[oparg] + ')', end=' ')
|
print('(' + cmp_op[oparg] + ')', end=' ')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
def _disassemble_str(source):
|
||||||
|
"""Compile the source string, then disassemble the code object."""
|
||||||
|
disassemble(_try_compile(source, '<dis>'))
|
||||||
|
|
||||||
disco = disassemble # XXX For backwards compatibility
|
disco = disassemble # XXX For backwards compatibility
|
||||||
|
|
||||||
def findlabels(code):
|
def findlabels(code):
|
||||||
|
|
|
@ -96,6 +96,46 @@ Disassembly of g:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
expr_str = "x + 1"
|
||||||
|
|
||||||
|
dis_expr_str = """\
|
||||||
|
1 0 LOAD_NAME 0 (x)
|
||||||
|
3 LOAD_CONST 0 (1)
|
||||||
|
6 BINARY_ADD
|
||||||
|
7 RETURN_VALUE
|
||||||
|
"""
|
||||||
|
|
||||||
|
simple_stmt_str = "x = x + 1"
|
||||||
|
|
||||||
|
dis_simple_stmt_str = """\
|
||||||
|
1 0 LOAD_NAME 0 (x)
|
||||||
|
3 LOAD_CONST 0 (1)
|
||||||
|
6 BINARY_ADD
|
||||||
|
7 STORE_NAME 0 (x)
|
||||||
|
10 LOAD_CONST 1 (None)
|
||||||
|
13 RETURN_VALUE
|
||||||
|
"""
|
||||||
|
|
||||||
|
compound_stmt_str = """\
|
||||||
|
x = 0
|
||||||
|
while 1:
|
||||||
|
x += 1"""
|
||||||
|
# Trailing newline has been deliberately omitted
|
||||||
|
|
||||||
|
dis_compound_stmt_str = """\
|
||||||
|
1 0 LOAD_CONST 0 (0)
|
||||||
|
3 STORE_NAME 0 (x)
|
||||||
|
|
||||||
|
2 6 SETUP_LOOP 13 (to 22)
|
||||||
|
|
||||||
|
3 >> 9 LOAD_NAME 0 (x)
|
||||||
|
12 LOAD_CONST 1 (1)
|
||||||
|
15 INPLACE_ADD
|
||||||
|
16 STORE_NAME 0 (x)
|
||||||
|
19 JUMP_ABSOLUTE 9
|
||||||
|
>> 22 LOAD_CONST 2 (None)
|
||||||
|
25 RETURN_VALUE
|
||||||
|
"""
|
||||||
|
|
||||||
class DisTests(unittest.TestCase):
|
class DisTests(unittest.TestCase):
|
||||||
def do_disassembly_test(self, func, expected):
|
def do_disassembly_test(self, func, expected):
|
||||||
|
@ -166,6 +206,11 @@ class DisTests(unittest.TestCase):
|
||||||
from test import dis_module
|
from test import dis_module
|
||||||
self.do_disassembly_test(dis_module, dis_module_expected_results)
|
self.do_disassembly_test(dis_module, dis_module_expected_results)
|
||||||
|
|
||||||
|
def test_disassemble_str(self):
|
||||||
|
self.do_disassembly_test(expr_str, dis_expr_str)
|
||||||
|
self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str)
|
||||||
|
self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str)
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(DisTests)
|
run_unittest(DisTests)
|
||||||
|
|
||||||
|
|
|
@ -797,6 +797,7 @@ Doobee R. Tzeck
|
||||||
Eren Türkay
|
Eren Türkay
|
||||||
Lionel Ulmer
|
Lionel Ulmer
|
||||||
Roger Upole
|
Roger Upole
|
||||||
|
Daniel Urban
|
||||||
Michael Urman
|
Michael Urman
|
||||||
Hector Urtubia
|
Hector Urtubia
|
||||||
Andi Vajda
|
Andi Vajda
|
||||||
|
|
|
@ -468,6 +468,8 @@ C-API
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6507: Accept source strings in dis.dis()
|
||||||
|
|
||||||
- Issue #7829: Clearly document that the dis module is exposing an
|
- Issue #7829: Clearly document that the dis module is exposing an
|
||||||
implementation detail that is not stable between Python VMs or releases.
|
implementation detail that is not stable between Python VMs or releases.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue