blob: 0a28e4fb7b8a0108b73035c6aab580a526c27ef8 [file] [log] [blame]
# 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:])