You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
parse2.py, pysource.py: add buildclass nonterminal to structure tree
better and make more similar to Python3 load.py: handle magic errors better main.py: correct use when passing a .py instead of a .pyc better and a message err when file not found. pysource.py: fix up main docstring; code moved from main.py
This commit is contained in:
Binary file not shown.
@@ -8,8 +8,8 @@
|
|||||||
# classdef ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS designator
|
# classdef ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS designator
|
||||||
# mkfunc ::= LOAD_CONST MAKE_FUNCTION_0
|
# mkfunc ::= LOAD_CONST MAKE_FUNCTION_0
|
||||||
|
|
||||||
class A:
|
# class A:
|
||||||
pass
|
|
||||||
|
|
||||||
# class B(Exception):
|
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
class B(Exception):
|
||||||
|
pass
|
||||||
|
@@ -70,8 +70,12 @@ def load_module(filename):
|
|||||||
try:
|
try:
|
||||||
version = float(magics.versions[magic])
|
version = float(magics.versions[magic])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
if len(magic) >= 2:
|
||||||
raise ImportError("Unknown magic number %s in %s" %
|
raise ImportError("Unknown magic number %s in %s" %
|
||||||
(ord(magic[0])+256*ord(magic[1]), filename))
|
(ord(magic[0])+256*ord(magic[1]), filename))
|
||||||
|
else:
|
||||||
|
raise ImportError("Bad magic number: '%s'" % magic)
|
||||||
|
|
||||||
if not (2.5 <= version <= 2.7) and not (3.2 <= version <= 3.4):
|
if not (2.5 <= version <= 2.7) and not (3.2 <= version <= 3.4):
|
||||||
raise ImportError("This is a Python %s file! Only "
|
raise ImportError("This is a Python %s file! Only "
|
||||||
"Python 2.5 to 2.7 and 3.2 to 3.4 files are supported."
|
"Python 2.5 to 2.7 and 3.2 to 3.4 files are supported."
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os, sys
|
import inspect, os, sys
|
||||||
|
|
||||||
from uncompyle6.disas import check_object_path
|
from uncompyle6.disas import check_object_path
|
||||||
from uncompyle6 import verify
|
from uncompyle6 import verify
|
||||||
@@ -13,6 +13,8 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
|
|||||||
disassembles and deparses a given code block 'co'
|
disassembles and deparses a given code block 'co'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
assert inspect.iscode(co)
|
||||||
|
|
||||||
# store final output stream for case of error
|
# store final output stream for case of error
|
||||||
real_out = out or sys.stdout
|
real_out = out or sys.stdout
|
||||||
print('# Python %s' % version, file=real_out)
|
print('# Python %s' % version, file=real_out)
|
||||||
@@ -21,28 +23,18 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
|
|||||||
file=real_out)
|
file=real_out)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
deparsed = pysource.deparse_code(version, co, out, showasm, showast, showgrammar)
|
pysource.deparse_code(version, co, out, showasm, showast, showgrammar)
|
||||||
except pysource.ParserError as e : # parser failed, dump disassembly
|
except pysource.ParserError as e : # parser failed, dump disassembly
|
||||||
print(e, file=real_out)
|
print(e, file=real_out)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# FIXME: remove duplicate code from deparse_code
|
|
||||||
try:
|
|
||||||
if deparsed.ast[0][0] == pysource.ASSIGN_DOC_STRING(co.co_consts[0]):
|
|
||||||
deparsed.print_docstring('', co.co_consts[0])
|
|
||||||
del deparsed.ast[0]
|
|
||||||
if deparsed.ast[-1] == pysource.RETURN_NONE:
|
|
||||||
deparsed.ast.pop() # remove last node
|
|
||||||
# todo: if empty, add 'pass'
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def uncompyle_file(filename, outstream=None, showasm=False, showast=False,
|
def uncompyle_file(filename, outstream=None, showasm=False, showast=False,
|
||||||
showgrammar=False):
|
showgrammar=False):
|
||||||
"""
|
"""
|
||||||
decompile Python byte-code file (.pyc)
|
decompile Python byte-code file (.pyc)
|
||||||
"""
|
"""
|
||||||
check_object_path(filename)
|
|
||||||
|
filename = check_object_path(filename)
|
||||||
version, magic_int, co = load_module(filename)
|
version, magic_int, co = load_module(filename)
|
||||||
if type(co) == list:
|
if type(co) == list:
|
||||||
for con in co:
|
for con in co:
|
||||||
@@ -119,7 +111,7 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
else:
|
else:
|
||||||
sys.stderr.write("\n# %s" % sys.exc_info()[1])
|
sys.stderr.write("\n# %s" % sys.exc_info()[1])
|
||||||
sys.stderr.write("\n# Can't uncompile %s\n" % infile)
|
sys.stderr.write("\n# Can't uncompile %s\n" % infile)
|
||||||
else: # uncompile successfull
|
else: # uncompile successful
|
||||||
if outfile:
|
if outfile:
|
||||||
outstream.close()
|
outstream.close()
|
||||||
if do_verify:
|
if do_verify:
|
||||||
@@ -137,6 +129,13 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
if not outfile:
|
if not outfile:
|
||||||
print("### Error Verifiying %s" % filename, file=sys.stderr)
|
print("### Error Verifiying %s" % filename, file=sys.stderr)
|
||||||
print(e, file=sys.stderr)
|
print(e, file=sys.stderr)
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
elif do_verify:
|
||||||
|
print("\n### uncompile successful, but no file to compare against",
|
||||||
|
file=sys.stderr)
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
okay_files += 1
|
okay_files += 1
|
||||||
if not outfile:
|
if not outfile:
|
||||||
|
@@ -351,8 +351,10 @@ class Python2Parser(PythonParser):
|
|||||||
|
|
||||||
kwarg ::= LOAD_CONST expr
|
kwarg ::= LOAD_CONST expr
|
||||||
|
|
||||||
classdef ::= LOAD_CONST expr mkfunc
|
classdef ::= buildclass designator
|
||||||
CALL_FUNCTION_0 BUILD_CLASS designator
|
|
||||||
|
buildclass ::= LOAD_CONST expr mkfunc
|
||||||
|
CALL_FUNCTION_0 BUILD_CLASS
|
||||||
|
|
||||||
stmt ::= classdefdeco
|
stmt ::= classdefdeco
|
||||||
classdefdeco ::= classdefdeco1 designator
|
classdefdeco ::= classdefdeco1 designator
|
||||||
|
@@ -1054,22 +1054,25 @@ class Walker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
cclass = self.currentclass
|
cclass = self.currentclass
|
||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
self.currentclass = str(node[1][1].pattr)
|
buildclass = node[1]
|
||||||
|
self.currentclass = str(buildclass[1].pattr)
|
||||||
else:
|
else:
|
||||||
self.currentclass = str(node[0].pattr)
|
buildclass = node[0]
|
||||||
|
self.currentclass = str(buildclass[0].pattr)
|
||||||
|
|
||||||
self.write('\n\n')
|
self.write('\n\n')
|
||||||
self.write(self.indent, 'class ', self.currentclass)
|
self.write(self.indent, 'class ', self.currentclass)
|
||||||
self.print_super_classes(node)
|
|
||||||
|
self.print_super_classes(buildclass)
|
||||||
self.print_(':')
|
self.print_(':')
|
||||||
|
|
||||||
# class body
|
# class body
|
||||||
self.indentMore()
|
self.indentMore()
|
||||||
|
|
||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
self.build_class(node[1][0].attr)
|
self.build_class(buildclass[0].attr)
|
||||||
else:
|
else:
|
||||||
self.build_class(node[2][-2].attr)
|
self.build_class(buildclass[-3][0].attr)
|
||||||
self.indentLess()
|
self.indentLess()
|
||||||
|
|
||||||
self.currentclass = cclass
|
self.currentclass = cclass
|
||||||
@@ -1568,9 +1571,19 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
|
|||||||
|
|
||||||
del tokens # save memory
|
del tokens # save memory
|
||||||
|
|
||||||
# convert leading '__doc__ = "..." into doc string
|
|
||||||
deparsed.mod_globs = find_globals(deparsed.ast, set())
|
deparsed.mod_globs = find_globals(deparsed.ast, set())
|
||||||
|
|
||||||
|
# convert leading '__doc__ = "..." into doc string
|
||||||
|
try:
|
||||||
|
if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0]):
|
||||||
|
deparsed.print_docstring('', co.co_consts[0])
|
||||||
|
del deparsed.ast[0]
|
||||||
|
if deparsed.ast[-1] == RETURN_NONE:
|
||||||
|
deparsed.ast.pop() # remove last node
|
||||||
|
# todo: if empty, add 'pass'
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# What we've been waiting for: Generate source from AST!
|
# What we've been waiting for: Generate source from AST!
|
||||||
deparsed.gen_source(deparsed.ast, customize)
|
deparsed.gen_source(deparsed.ast, customize)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user