Ultimamente he estado jugando con
decompyle. Necesitaba obtener código que estaba generado con python 2.3, con lo cual por ese lado no tenía ningun problema.
El problema es que no disponía ni siquiera del código fuente, los módulos estaban embebidos en el interprete. ¿Ingenioso verdad? ¿Que hacer ante esto? Pues fácil. A tirar de introspección y a generar el código de los
CodeObject encontrados.
Para generar el código sin tener que tocar decompyle, usé la siguiente función:
def decompile(codeObject):
"""
Método que realiza la decompilación
"""
# decompyle, funciona volcando a un archivo o a stdout.
# Para no modificar el código de decompyle, hemos hecho la ñapa
# de usar un fichero temporal.
code = None
fout = None
tmpFile = None
try:
try:
to_avoid = ['# local variables:','# tab-width:','# emacs-mode:'] # Esto lo genera decompile
tmpHandle,tmpFile = tempfile.mkstemp()
os.close(tmpHandle)
fout = open(tmpFile,"w+")
decompyle.decompyle("2.3", codeObject, fout, 0, 0)
fout.seek(0,0)
lines = []
for line in fout:
skip = False
for item in to_avoid:
if line.find(item) != -1:
skip = True
break
if not skip: lines.append(line)
code = "".join(lines)
except:
pass
finally:
# En python 2.3 el finally no se puede mezclar con un un 'try' normal
if fout is not None: fout.close()
if tmpFile is not None: os.remove(tmpFile)
return code
Mediante una lista de módulos a decompilar, y usando el módulo
inspect, podemos llegar al código de las funciones, métodos.
El resto de código tendremos que generarlo nosotros (*1). Y aún así nunca podremos llegar a generar el código original, pero bueno... en plan de tener algo de documentación, pues bien está...
¿porque digo esto último? Porque al ir tirando de una lista de módulos que se van cargando, vamos a ir haciendo introspección de sus atributos: tipos basicos, módulos, clases....
En principio, el script que yo hice va dirigido por módulos, es decir, no va profundizando en los módulos, ya que no te puedes fiar, ya que los import, te van a generar un elemento en el espacio de nombres del módulo que estas analizando.
Otro ejemplo lo tenemos con las clases. Si tienemos un import tal que 'from mimodulo import clasecita', nos vamos a encontrar que 'clasecita' en el contexto de decompilación actual y vamos a intentar obtener su código, cuando dicha clase realmente está definida en otro módulo.
(*1) Toda la estructura de ficheros, clases, funciones, ... hay que generarla a pelo.