tanderson11
tanderson11

Reputation: 127

Recovering .pyc file from python interpreter

Because I am an idiot, I deleted some python files and failed to back them up. Before doing this I opened the python interpreter (ie, ran python) and then used the command import myfile.py.

EDIT: I actually used the command import myfile, which, apparently, is worse.

Is there any way I can recover the .pyc (or better the .py, but that seems impossible) file from the python interpreter session I have open?

Upvotes: 4

Views: 2599

Answers (2)

ecatmur
ecatmur

Reputation: 157414

The byte-code decompiler uncompyle2 can decompile Python 2.x classes, methods, functions and code to source code (note: via Reassembling Python bytecode to the original code?).

This will work well enough for functions:

from StringIO import StringIO
from uncompyle2 import uncompyle
from inspect import *

def decompile_function(f, indent=''):
    s = StringIO()
    uncompyle(2.7, f.func_code, s)
    return '%sdef %s%s:\n%s    %s' % (
        indent,
        f.func_name,
        inspect.formatargspec(*inspect.getargspec(f)),
        indent,
        ('\n    ' + indent).join(''.join(s.buflist).split('\n')))

Unfortunately because classes are already executed it won't be able to recover their structure; you'd need to decompile the methods individually and hope that that's enough:

def decompile_class(c):
    return 'class %s(%s):\n' % (
        c.__name__,
        ','.join(b.__module__ + '.' + b.__name__ for b in c.__bases__)) + \
        '\n'.join(decompile_function(m.im_func, '    ')
                  for n, m in inspect.getmembers(c) if inspect.ismethod(m))

Full solution:

def decompile_module(mod):
    return '\n\n'.join(decompile_function(m) if isfunction(m) else
        decompile_class(m) if isclass(m) else
        '# UNKNOWN: ' + repr((n, m))
        for n, m in inspect.getmembers(mod) if inspect.getmodule(m) is mod)

Upvotes: 4

loopbackbee
loopbackbee

Reputation: 23322

inspect.getsource supports dumping modules, so you can simply

import inspect
inspect.getsource(myfile)

As that doesn't seem to work, you should at least be able to get the disassembled (".pyc) code with

import dis
dis.dis(myfile)

Upvotes: 1

Related Questions