ANN: unpyc3 - a python bytecode decompiler for Python3
Arnaud Delobelle
arnodel at gmail.com
Wed Sep 14 15:51:37 EDT 2011
On 14 September 2011 11:03, Vincent Vande Vyvre
<vincent.vandevyvre at swing.be> wrote:
> Le 14/09/11 11:31, Arnaud Delobelle a écrit :
[...]
> Could you show me what you do to get this error? Thank you,
> [vincent at myhost unpyc3]$ python
> Python 3.2.1 (default, Jul 11 2011, 12:37:47)
> [GCC 4.6.1] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
>>>> from unpyc3 import decompile
>>>> print (decompile("shredder.pyc"))
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "unpyc3.py", line 110, in decompile
> return dec_module(obj)
> File "unpyc3.py", line 99, in dec_module
> code = Code(code_obj)
> File "unpyc3.py", line 211, in __init__
> for v in code_obj.co_cellvars + code_obj.co_freevars]
> AttributeError: 'NoneType' object has no attribute 'co_cellvars'
>>>> print (decompile("unpyc3.pyc"))
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "unpyc3.py", line 110, in decompile
> return dec_module(obj)
> File "unpyc3.py", line 99, in dec_module
> code = Code(code_obj)
> File "unpyc3.py", line 211, in __init__
> for v in code_obj.co_cellvars + code_obj.co_freevars]
> AttributeError: 'NoneType' object has no attribute 'co_cellvars'
>>>> import os
>>>> os.path.isfile("shredder.pyc")
> True
>>>> os.path.isfile("unpyc3.pyc")
> True
>>>>
>
> it seems the return of marshal.load(stream) is None
I think the reason may be that your unpyc3.pyc and shredder.pyc files
were compiled with a different version of python and the read_code
function returns None because the magic number in the .pyc file is
incorrect because of these two lines:
if magic != imp.get_magic():
return None
I have now changed this so that it loads the file anyway but prints a
warning. I guess this may break badly though.
In Python 3.2, .pyc files are "hidden" in a __pycache__ directory. So
the Python 3.2 specific unpyc3.pyc file for example is probably
located at .../unpyc3/__pycache__/unpyc3-cpython-32.pyc
The easiest way to find the path of the .pyc file if you know the path
of the .py file is probably as follows:
>>> import imp
>>> imp.cache_from_source("unpyc3.py")
'__pycache__/unpyc3.cpython-32.pyc'
Here's an example decompiling the dis module from the standard library:
>>> import dis
>>> dis.__file__
'/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/dis.py'
>>> imp.cache_from_source(dis.__file__)
'/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/__pycache__/dis.cpython-32.pyc'
>>> print(decompile(_))
__doc__ = 'Disassembler of Python byte code into mnemonics.'
import sys
import types
from opcode import *
from opcode import __all__ as _opcodes_all
__all__ = ['code_info', 'dis', 'disassemble', 'distb', 'disco',
'findlinestarts', 'findlabels', 'show_code'] + _opcodes_all
del _opcodes_all
_have_code = types.MethodType, types.FunctionType, types.CodeType, type
def _try_compile(source, name):
try:
c = compile(source, name, 'eval')
except SyntaxError:
c = compile(source, name, 'exec')
return c
[... many more lines ...]
I hope this will work for you,
--
Arnaud
PS: I've also added support for the IMPORT_STAR opcode which I had overlooked.
More information about the Python-list
mailing list