diff -r a1235865dd54 Lib/dis.py --- a/Lib/dis.py Sat Apr 09 13:00:17 2011 -0700 +++ b/Lib/dis.py Sat Apr 09 20:19:47 2011 -0400 @@ -2,12 +2,14 @@ import sys import types +from io import StringIO from opcode import * from opcode import __all__ as _opcodes_all -__all__ = ["code_info", "dis", "disassemble", "distb", "disco", - "findlinestarts", "findlabels", "show_code"] + _opcodes_all +__all__ = ["code_info", "dis", "dis_to_str", "disassemble", + "disassemble_to_str", "distb", "disco", "findlinestarts", + "findlabels", "show_code"] + _opcodes_all del _opcodes_all _have_code = (types.MethodType, types.FunctionType, types.CodeType, type) @@ -25,14 +27,14 @@ c = compile(source, name, 'exec') return c -def dis(x=None): +def dis(x=None, file=sys.stdout): """Disassemble classes, methods, functions, or code. With no argument, disassemble the last traceback. """ if x is None: - distb() + distb(file=file) return if hasattr(x, '__func__'): # Method x = x.__func__ @@ -42,23 +44,29 @@ items = sorted(x.__dict__.items()) for name, x1 in items: if isinstance(x1, _have_code): - print("Disassembly of %s:" % name) + file.write("Disassembly of %s:\n" % name) try: - dis(x1) + dis(x1, file=file) except TypeError as msg: - print("Sorry:", msg) - print() + file.write("Sorry: %s\n" % msg) + file.write('\n') elif hasattr(x, 'co_code'): # Code object - disassemble(x) + disassemble(x, file=file) elif isinstance(x, (bytes, bytearray)): # Raw bytecode - _disassemble_bytes(x) + _disassemble_bytes(x, file=file) elif isinstance(x, str): # Source code - _disassemble_str(x) + _disassemble_str(x, file=file) else: raise TypeError("don't know how to disassemble %s objects" % type(x).__name__) -def distb(tb=None): +def dis_to_str(x=None): + """Same as dis but returns disassembly as a string.""" + file = StringIO() + dis(x, file=file) + return file.getvalue() + +def distb(tb=None, file=sys.stdout): """Disassemble a traceback (default: last traceback).""" if tb is None: try: @@ -66,7 +74,7 @@ except AttributeError: raise RuntimeError("no last traceback to disassemble") while tb.tb_next: tb = tb.tb_next - disassemble(tb.tb_frame.f_code, tb.tb_lasti) + disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file) # The inspect module interrogates this dictionary to build its # list of CO_* constants. It is also used by pretty_flags to @@ -144,7 +152,7 @@ """Print details of methods, functions, or code to stdout.""" print(code_info(co)) -def disassemble(co, lasti=-1): +def disassemble(co, lasti=-1, file=sys.stdout): """Disassemble a code object.""" code = co.co_code labels = findlabels(code) @@ -157,17 +165,17 @@ op = code[i] if i in linestarts: if i > 0: - print() - print("%3d" % linestarts[i], end=' ') + file.write('\n') + file.write('%3d ' % linestarts[i]) else: - print(' ', end=' ') + file.write(' ') - if i == lasti: print('-->', end=' ') - else: print(' ', end=' ') - if i in labels: print('>>', end=' ') - else: print(' ', end=' ') - print(repr(i).rjust(4), end=' ') - print(opname[op].ljust(20), end=' ') + if i == lasti: file.write('--> ') + else: file.write(' ') + if i in labels: file.write('>> ') + else: file.write(' ') + file.write(repr(i).rjust(4) + ' ') + file.write(opname[op].ljust(20) + ' ') i = i+1 if op >= HAVE_ARGUMENT: oparg = code[i] + code[i+1]*256 + extended_arg @@ -175,65 +183,71 @@ i = i+2 if op == EXTENDED_ARG: extended_arg = oparg*65536 - print(repr(oparg).rjust(5), end=' ') + file.write(repr(oparg).rjust(5) + ' ') if op in hasconst: - print('(' + repr(co.co_consts[oparg]) + ')', end=' ') + file.write('(' + repr(co.co_consts[oparg]) + ') ') elif op in hasname: - print('(' + co.co_names[oparg] + ')', end=' ') + file.write('(' + co.co_names[oparg] + ') ') elif op in hasjrel: - print('(to ' + repr(i + oparg) + ')', end=' ') + file.write('(to ' + repr(i + oparg) + ') ') elif op in haslocal: - print('(' + co.co_varnames[oparg] + ')', end=' ') + file.write('(' + co.co_varnames[oparg] + ') ') elif op in hascompare: - print('(' + cmp_op[oparg] + ')', end=' ') + file.write('(' + cmp_op[oparg] + ') ') elif op in hasfree: if free is None: free = co.co_cellvars + co.co_freevars - print('(' + free[oparg] + ')', end=' ') - print() + file.write('(' + free[oparg] + ') ') + file.write('\n') + +def disassemble_to_str(co, lasti=-1): + """Same as disassemble but returns disassembly as a string.""" + file = StringIO() + disassemble(co, lasti, file=file) + return file.getvalue() def _disassemble_bytes(code, lasti=-1, varnames=None, names=None, - constants=None): + constants=None, file=sys.stdout): labels = findlabels(code) n = len(code) i = 0 while i < n: op = code[i] - if i == lasti: print('-->', end=' ') - else: print(' ', end=' ') - if i in labels: print('>>', end=' ') - else: print(' ', end=' ') - print(repr(i).rjust(4), end=' ') - print(opname[op].ljust(15), end=' ') + if i == lasti: file.write('--> ') + else: file.write(' ') + if i in labels: file.write('>> ') + else: file.write(' ') + file.write(repr(i).rjust(4) + ' ') + file.write(opname[op].ljust(15) + ' ') i = i+1 if op >= HAVE_ARGUMENT: oparg = code[i] + code[i+1]*256 i = i+2 - print(repr(oparg).rjust(5), end=' ') + file.write(repr(oparg).rjust(5) + ' ') if op in hasconst: if constants: - print('(' + repr(constants[oparg]) + ')', end=' ') + file.write('(' + repr(constants[oparg]) + ') ') else: - print('(%d)'%oparg, end=' ') + file.write('(%d) ' % oparg) elif op in hasname: if names is not None: - print('(' + names[oparg] + ')', end=' ') + file.write('(' + names[oparg] + ') ') else: - print('(%d)'%oparg, end=' ') + file.write('(%d) ' % oparg) elif op in hasjrel: - print('(to ' + repr(i + oparg) + ')', end=' ') + file.write('(to ' + repr(i + oparg) + ') ') elif op in haslocal: if varnames: - print('(' + varnames[oparg] + ')', end=' ') + file.write('(' + varnames[oparg] + ') ') else: - print('(%d)' % oparg, end=' ') + file.write('(%d) ' % oparg) elif op in hascompare: - print('(' + cmp_op[oparg] + ')', end=' ') - print() + file.write('(' + cmp_op[oparg] + ') ') + file.write('\n') -def _disassemble_str(source): +def _disassemble_str(source, file=sys.stdout): """Compile the source string, then disassemble the code object.""" - disassemble(_try_compile(source, '')) + disassemble(_try_compile(source, ''), file=file) disco = disassemble # XXX For backwards compatibility diff -r a1235865dd54 Lib/test/test_dis.py --- a/Lib/test/test_dis.py Sat Apr 09 13:00:17 2011 -0700 +++ b/Lib/test/test_dis.py Sat Apr 09 20:19:47 2011 -0400 @@ -5,7 +5,6 @@ import unittest import sys import dis -import io class _C: def __init__(self, x): @@ -174,18 +173,12 @@ class DisTests(unittest.TestCase): def get_disassembly(self, func, lasti=-1, wrapper=True): - s = io.StringIO() - save_stdout = sys.stdout - sys.stdout = s - try: - if wrapper: - dis.dis(func) - else: - dis.disassemble(func, lasti) - finally: - sys.stdout = save_stdout + if wrapper: + s = dis.dis_to_str(func) + else: + s = dis.disassemble_to_str(func, lasti) # Trim trailing blanks (if any). - return [line.rstrip() for line in s.getvalue().splitlines()] + return [line.rstrip() for line in s.splitlines()] def get_disassemble_as_string(self, func, lasti=-1): return '\n'.join(self.get_disassembly(func, lasti, False)) diff -r a1235865dd54 Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py Sat Apr 09 13:00:17 2011 -0700 +++ b/Lib/test/test_peepholer.py Sat Apr 09 20:19:47 2011 -0400 @@ -1,22 +1,9 @@ -import dis +from dis import dis_to_str as disassemble import re import sys -from io import StringIO import unittest from math import copysign -def disassemble(func): - f = StringIO() - tmp = sys.stdout - sys.stdout = f - try: - dis.dis(func) - finally: - sys.stdout = tmp - result = f.getvalue() - f.close() - return result - def dis_single(line): return disassemble(compile(line, '', 'single'))