| # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
| # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
| |
| import binascii |
| import dis |
| import marshal |
| import struct |
| import sys |
| import time |
| import types |
| |
| |
| def show_pyc_file(fname): |
| f = open(fname, "rb") |
| magic = f.read(4) |
| moddate = f.read(4) |
| modtime = time.asctime(time.localtime(struct.unpack('<L', moddate)[0])) |
| print("magic %s" % (binascii.hexlify(magic))) |
| print("moddate %s (%s)" % (binascii.hexlify(moddate), modtime)) |
| if sys.version_info >= (3, 3): |
| # 3.3 added another long to the header (size). |
| size = f.read(4) |
| print("pysize %s (%d)" % (binascii.hexlify(size), struct.unpack('<L', size)[0])) |
| code = marshal.load(f) |
| show_code(code) |
| |
| def show_py_file(fname): |
| text = open(fname).read().replace('\r\n', '\n') |
| show_py_text(text, fname=fname) |
| |
| def show_py_text(text, fname="<string>"): |
| code = compile(text, fname, "exec") |
| show_code(code) |
| |
| CO_FLAGS = [ |
| ('CO_OPTIMIZED', 0x00001), |
| ('CO_NEWLOCALS', 0x00002), |
| ('CO_VARARGS', 0x00004), |
| ('CO_VARKEYWORDS', 0x00008), |
| ('CO_NESTED', 0x00010), |
| ('CO_GENERATOR', 0x00020), |
| ('CO_NOFREE', 0x00040), |
| ('CO_COROUTINE', 0x00080), |
| ('CO_ITERABLE_COROUTINE', 0x00100), |
| ('CO_ASYNC_GENERATOR', 0x00200), |
| ('CO_GENERATOR_ALLOWED', 0x01000), |
| ('CO_FUTURE_DIVISION', 0x02000), |
| ('CO_FUTURE_ABSOLUTE_IMPORT', 0x04000), |
| ('CO_FUTURE_WITH_STATEMENT', 0x08000), |
| ('CO_FUTURE_PRINT_FUNCTION', 0x10000), |
| ('CO_FUTURE_UNICODE_LITERALS', 0x20000), |
| ('CO_FUTURE_BARRY_AS_BDFL', 0x40000), |
| ('CO_FUTURE_GENERATOR_STOP', 0x80000), |
| ] |
| |
| def show_code(code, indent='', number=None): |
| label = "" |
| if number is not None: |
| label = "%d: " % number |
| print("%s%scode" % (indent, label)) |
| indent += ' ' |
| print("%sname %r" % (indent, code.co_name)) |
| print("%sargcount %d" % (indent, code.co_argcount)) |
| print("%snlocals %d" % (indent, code.co_nlocals)) |
| print("%sstacksize %d" % (indent, code.co_stacksize)) |
| print("%sflags %04x: %s" % (indent, code.co_flags, flag_words(code.co_flags, CO_FLAGS))) |
| show_hex("code", code.co_code, indent=indent) |
| dis.disassemble(code) |
| print("%sconsts" % indent) |
| for i, const in enumerate(code.co_consts): |
| if type(const) == types.CodeType: |
| show_code(const, indent+' ', number=i) |
| else: |
| print(" %s%d: %r" % (indent, i, const)) |
| print("%snames %r" % (indent, code.co_names)) |
| print("%svarnames %r" % (indent, code.co_varnames)) |
| print("%sfreevars %r" % (indent, code.co_freevars)) |
| print("%scellvars %r" % (indent, code.co_cellvars)) |
| print("%sfilename %r" % (indent, code.co_filename)) |
| print("%sfirstlineno %d" % (indent, code.co_firstlineno)) |
| show_hex("lnotab", code.co_lnotab, indent=indent) |
| |
| def show_hex(label, h, indent): |
| h = binascii.hexlify(h) |
| if len(h) < 60: |
| print("%s%s %s" % (indent, label, h.decode('ascii'))) |
| else: |
| print("%s%s" % (indent, label)) |
| for i in range(0, len(h), 60): |
| print("%s %s" % (indent, h[i:i+60].decode('ascii'))) |
| |
| def flag_words(flags, flag_defs): |
| words = [] |
| for word, flag in flag_defs: |
| if flag & flags: |
| words.append(word) |
| return ", ".join(words) |
| |
| def show_file(fname): |
| if fname.endswith('pyc'): |
| show_pyc_file(fname) |
| elif fname.endswith('py'): |
| show_py_file(fname) |
| else: |
| print("Odd file:", fname) |
| |
| def main(args): |
| if args[0] == '-c': |
| show_py_text(" ".join(args[1:]).replace(";", "\n")) |
| else: |
| for a in args: |
| show_file(a) |
| |
| if __name__ == '__main__': |
| main(sys.argv[1:]) |