Skip to content

Instantly share code, notes, and snippets.

Created November 10, 2015 17:19
Show Gist options
  • Select an option

  • Save anonymous/35c08092a6eb70cdd723 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/35c08092a6eb70cdd723 to your computer and use it in GitHub Desktop.
Dump .pyc file (Python 3.5 version)
#
# read a .pyc file and pretty-print it
#
# copied from http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html
# and updated to Python 3.5 (Nov 10th 2015)
#
import dis, marshal, struct, sys, time, types, binascii
def show_file(fname):
f = open(fname, "rb")
magic = f.read(4)
moddate = f.read(4)
filesz = f.read(4)
modtime = time.asctime(time.localtime(struct.unpack('=L', moddate)[0]))
filesz = struct.unpack('=L', filesz)
print ("magic %s" % (binascii.hexlify(magic)))
print ("moddate %s (%s)" % (binascii.hexlify(moddate), modtime))
print ("files sz %d" % filesz)
code = marshal.load(f)
show_code(code)
def show_code(code, indent=''):
print ("%scode" % indent)
indent += ' '
print ("%sargcount %d" % (indent, code.co_argcount))
print ("%snlocals %d" % (indent, code.co_nlocals))
print ("%sstacksize %d" % (indent, code.co_stacksize))
print ("%sflags %04x" % (indent, code.co_flags))
show_hex("code", code.co_code, indent=indent)
dis.disassemble(code)
print ("%sconsts" % indent)
for const in code.co_consts:
if type(const) == types.CodeType:
show_code(const, indent+' ')
else:
print (" %s%r" % (indent, 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 ("%sname %r" % (indent, code.co_name))
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))
else:
print ("%s%s" % (indent, label))
for i in range(0, len(h), 60):
print ("%s %s" % (indent, h[i:i+60]))
show_file(sys.argv[1])
@bobozi-cmd
Copy link

python3.6.8 can also use this, but 3.7.8 cannot. It will encount
"""
Traceback (most recent call last):
File "e:\mpy\showfile.py", line 52, in
show_file(filename)
File "e:\mpy\showfile.py", line 13, in show_file
code = marshal.load(f)
ValueError: bad marshal data (unknown type code)
"""

@jon-king-mindbodyonline

Not sure about 3.7, but just tested 3.8 - an additional 4 bytes of header were added. Not sure what, it's all 0s in what I tested.
Inserted other = f.read(4) at line 13 (after magic) and print ("other %s" % (binascii.hexlify(other))) at 18 (after print magic)

@zahlman
Copy link

zahlman commented Feb 22, 2026

The change was indeed made in 3.7. The second 4-byte word of the header is now a type field rather than a modification date; type 0 uses the next two words as modification date and size as before, while types 1 and 3 (in effect; the type field is described as a bitfield) use them as a 64-bit hash (of the corresponding .py source). This is to facilitate reproducible builds. See PEP 552 for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment