You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
Python packaging - yet again.
Did I ever mention how much Python sucks at packaging?
This commit is contained in:
@@ -30,30 +30,27 @@ classifiers = ['Development Status :: 4 - Beta',
|
|||||||
# The rest in alphabetic order
|
# The rest in alphabetic order
|
||||||
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
||||||
author_email = "rb@dustyfeet.com"
|
author_email = "rb@dustyfeet.com"
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'uncompyle6=bin.uncompile6:main',
|
||||||
|
'pydisassemble=bin.pydisassemble:main',
|
||||||
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.1.1']
|
install_requires = ['spark-parser >= 1.1.1']
|
||||||
license = 'MIT'
|
license = 'MIT'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
modname = 'uncompyle6'
|
modname = 'uncompyle6'
|
||||||
packages = ['uncompyle6', 'uncompyle6.opcodes', 'uncompyle6.semantics', 'uncompyle6.scanners', 'uncompyle6.parsers']
|
packages = ['uncompyle6', 'uncompyle6.opcodes', 'uncompyle6.semantics', 'uncompyle6.scanners',
|
||||||
|
'uncompyle6.parsers']
|
||||||
py_modules = None
|
py_modules = None
|
||||||
short_desc = 'Python byte-code disassembler and source-code converter'
|
short_desc = 'Python byte-code disassembler and source-code converter'
|
||||||
scripts = ['bin/uncompyle6', 'bin/pydisassemble']
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
|
|
||||||
def get_srcdir():
|
|
||||||
filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
return os.path.realpath(filename)
|
|
||||||
|
|
||||||
ns = {}
|
|
||||||
web = 'https://github.com/rocky/python-uncompyle6/'
|
web = 'https://github.com/rocky/python-uncompyle6/'
|
||||||
|
|
||||||
# tracebacks in zip files are funky and not debuggable
|
# tracebacks in zip files are funky and not debuggable
|
||||||
zip_safe = True
|
zip_safe = True
|
||||||
|
|
||||||
|
|
||||||
|
import os.path
|
||||||
def read(*rnames):
|
def read(*rnames):
|
||||||
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
|
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
|
||||||
|
|
||||||
|
@@ -1,88 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Mode: -*- python -*-
|
from uncompyle6.bin.pydisassemble import main
|
||||||
#
|
main()
|
||||||
# Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com>
|
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
import sys, os, getopt
|
|
||||||
|
|
||||||
program = os.path.basename(__file__)
|
|
||||||
|
|
||||||
__doc__ = """
|
|
||||||
Usage:
|
|
||||||
%s [OPTIONS]... FILE
|
|
||||||
%s [--help | -h | -V | --version]
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
%s foo.pyc
|
|
||||||
%s foo.py
|
|
||||||
%s -o foo.pydis foo.pyc
|
|
||||||
%s -o /tmp foo.pyc
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-o <path> output decompiled files to this path:
|
|
||||||
if multiple input files are decompiled, the common prefix
|
|
||||||
is stripped from these names and the remainder appended to
|
|
||||||
<path>
|
|
||||||
--help show this message
|
|
||||||
|
|
||||||
""" % ((program,) * 6)
|
|
||||||
|
|
||||||
|
|
||||||
Usage_short = \
|
|
||||||
"%s [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." % program
|
|
||||||
|
|
||||||
from uncompyle6 import check_python_version
|
|
||||||
from uncompyle6.disas import disassemble_files
|
|
||||||
from uncompyle6.version import VERSION
|
|
||||||
|
|
||||||
check_python_version(program)
|
|
||||||
|
|
||||||
outfile = '-'
|
|
||||||
out_base = None
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
print("No file(s) or directory given", file=sys.stderr)
|
|
||||||
print(Usage_short, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
opts, files = getopt.getopt(sys.argv[1:], 'hVo:', ['help', 'version'])
|
|
||||||
except getopt.GetoptError as e:
|
|
||||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
for opt, val in opts:
|
|
||||||
if opt in ('-h', '--help'):
|
|
||||||
print(__doc__)
|
|
||||||
sys.exit(1)
|
|
||||||
elif opt in ('-V', '--version'):
|
|
||||||
print("%s %s" % (program, VERSION))
|
|
||||||
sys.exit(0)
|
|
||||||
elif opt == '-o':
|
|
||||||
outfile = val
|
|
||||||
else:
|
|
||||||
print(opt)
|
|
||||||
print(Usage_short, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
# argl, commonprefix works on strings, not on path parts,
|
|
||||||
# thus we must handle the case with files in 'some/classes'
|
|
||||||
# and 'some/cmds'
|
|
||||||
src_base = os.path.commonprefix(files)
|
|
||||||
if src_base[-1:] != os.sep:
|
|
||||||
src_base = os.path.dirname(src_base)
|
|
||||||
if src_base:
|
|
||||||
sb_len = len( os.path.join(src_base, '') )
|
|
||||||
files = [f[sb_len:] for f in files]
|
|
||||||
del sb_len
|
|
||||||
|
|
||||||
if outfile == '-':
|
|
||||||
outfile = None # use stdout
|
|
||||||
elif outfile and os.path.isdir(outfile):
|
|
||||||
out_base = outfile; outfile = None
|
|
||||||
elif outfile and len(files) > 1:
|
|
||||||
out_base = outfile; outfile = None
|
|
||||||
|
|
||||||
disassemble_files(src_base, out_base, files, outfile)
|
|
||||||
|
223
bin/uncompyle6
223
bin/uncompyle6
@@ -1,222 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Mode: -*- python -*-
|
from uncompyle6.bin.uncompile import main_bin
|
||||||
#
|
main_bin()
|
||||||
# Copyright (c) 2015-2016 by Rocky Bernstein
|
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
import sys, os, getopt, time
|
|
||||||
|
|
||||||
program = os.path.basename(__file__)
|
|
||||||
|
|
||||||
__doc__ = """
|
|
||||||
Usage:
|
|
||||||
%s [OPTIONS]... [ FILE | DIR]...
|
|
||||||
%s [--help | -h | --V | --version]
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
%s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
|
|
||||||
%s -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
|
|
||||||
%s -o /tmp /usr/lib/python1.5 # decompile whole library
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-o <path> output decompiled files to this path:
|
|
||||||
if multiple input files are decompiled, the common prefix
|
|
||||||
is stripped from these names and the remainder appended to
|
|
||||||
<path>
|
|
||||||
uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc
|
|
||||||
-> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis
|
|
||||||
uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc
|
|
||||||
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
|
||||||
uncompyle6 -o /tmp /usr/lib/python1.5
|
|
||||||
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
|
|
||||||
-c <file> attempts a disassembly after compiling <file>
|
|
||||||
-d print timestamps
|
|
||||||
-p <integer> use <integer> number of processes
|
|
||||||
-r recurse directories looking for .pyc and .pyo files
|
|
||||||
--verify compare generated source with input byte-code
|
|
||||||
(requires -o)
|
|
||||||
--help show this message
|
|
||||||
|
|
||||||
Debugging Options:
|
|
||||||
--asm -a include byte-code (disables --verify)
|
|
||||||
--grammar -g show matching grammar
|
|
||||||
--tree -t include syntax tree (disables --verify)
|
|
||||||
|
|
||||||
Extensions of generated files:
|
|
||||||
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
|
||||||
+ '_unverified' successfully decompile but --verify failed
|
|
||||||
+ '_failed' decompile failed (contact author for enhancement)
|
|
||||||
""" % ((program,) * 5)
|
|
||||||
|
|
||||||
program = os.path.basename(__file__)
|
|
||||||
|
|
||||||
from uncompyle6 import verify, check_python_version
|
|
||||||
from uncompyle6.main import main, status_msg
|
|
||||||
from uncompyle6.version import VERSION
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
print("""usage:
|
|
||||||
%s [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
|
|
||||||
%s [--help | -h | --version | -V]
|
|
||||||
""" % (program, program))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
check_python_version(program)
|
|
||||||
|
|
||||||
showasm = showast = do_verify = recurse_dirs = False
|
|
||||||
numproc = 0
|
|
||||||
outfile = '-'
|
|
||||||
out_base = None
|
|
||||||
codes = []
|
|
||||||
timestamp = False
|
|
||||||
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
|
||||||
|
|
||||||
try:
|
|
||||||
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
|
||||||
'help asm grammar recurse timestamp tree verify version '
|
|
||||||
'showgrammar'.split(' '))
|
|
||||||
except getopt.GetoptError as e:
|
|
||||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
options = {}
|
|
||||||
for opt, val in opts:
|
|
||||||
if opt in ('-h', '--help'):
|
|
||||||
print(__doc__)
|
|
||||||
sys.exit(0)
|
|
||||||
elif opt in ('-V', '--version'):
|
|
||||||
print("%s %s" % (program, VERSION))
|
|
||||||
sys.exit(0)
|
|
||||||
elif opt == '--verify':
|
|
||||||
options['do_verify'] = True
|
|
||||||
elif opt in ('--asm', '-a'):
|
|
||||||
options['showasm'] = True
|
|
||||||
options['do_verify'] = False
|
|
||||||
elif opt in ('--tree', '-t'):
|
|
||||||
options['showast'] = True
|
|
||||||
options['do_verify'] = False
|
|
||||||
elif opt in ('--grammar', '-g'):
|
|
||||||
options['showgrammar'] = True
|
|
||||||
elif opt == '-o':
|
|
||||||
outfile = val
|
|
||||||
elif opt in ('--timestamp', '-d'):
|
|
||||||
timestamp = True
|
|
||||||
elif opt == '-c':
|
|
||||||
codes.append(val)
|
|
||||||
elif opt == '-p':
|
|
||||||
numproc = int(val)
|
|
||||||
elif opt in ('--recurse', '-r'):
|
|
||||||
recurse_dirs = True
|
|
||||||
else:
|
|
||||||
print(opt, file=sys.stderr)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
# expand directory if specified
|
|
||||||
if recurse_dirs:
|
|
||||||
expanded_files = []
|
|
||||||
for f in files:
|
|
||||||
if os.path.isdir(f):
|
|
||||||
for root, _, dir_files in os.walk(f):
|
|
||||||
for df in dir_files:
|
|
||||||
if df.endswith('.pyc') or df.endswith('.pyo'):
|
|
||||||
expanded_files.append(os.path.join(root, df))
|
|
||||||
files = expanded_files
|
|
||||||
|
|
||||||
# argl, commonprefix works on strings, not on path parts,
|
|
||||||
# thus we must handle the case with files in 'some/classes'
|
|
||||||
# and 'some/cmds'
|
|
||||||
src_base = os.path.commonprefix(files)
|
|
||||||
if src_base[-1:] != os.sep:
|
|
||||||
src_base = os.path.dirname(src_base)
|
|
||||||
if src_base:
|
|
||||||
sb_len = len( os.path.join(src_base, '') )
|
|
||||||
files = [f[sb_len:] for f in files]
|
|
||||||
del sb_len
|
|
||||||
|
|
||||||
if not files:
|
|
||||||
print("No files given", file=sys.stderr)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
|
|
||||||
if outfile == '-':
|
|
||||||
outfile = None # use stdout
|
|
||||||
elif outfile and os.path.isdir(outfile):
|
|
||||||
out_base = outfile; outfile = None
|
|
||||||
elif outfile and len(files) > 1:
|
|
||||||
out_base = outfile; outfile = None
|
|
||||||
|
|
||||||
if timestamp:
|
|
||||||
print(time.strftime(timestampfmt))
|
|
||||||
|
|
||||||
if numproc <= 1:
|
|
||||||
try:
|
|
||||||
result = main(src_base, out_base, files, codes, outfile,
|
|
||||||
**options)
|
|
||||||
if len(files) > 1:
|
|
||||||
mess = status_msg(do_verify, *result)
|
|
||||||
print('# ' + mess)
|
|
||||||
pass
|
|
||||||
except (KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except verify.VerifyCmpError:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
from multiprocessing import Process, Queue
|
|
||||||
|
|
||||||
try:
|
|
||||||
from Queue import Empty
|
|
||||||
except ImportError:
|
|
||||||
from Queue import Empty
|
|
||||||
|
|
||||||
fqueue = Queue(len(files)+numproc)
|
|
||||||
for f in files:
|
|
||||||
fqueue.put(f)
|
|
||||||
for i in range(numproc):
|
|
||||||
fqueue.put(None)
|
|
||||||
|
|
||||||
rqueue = Queue(numproc)
|
|
||||||
|
|
||||||
def process_func():
|
|
||||||
try:
|
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
|
||||||
while 1:
|
|
||||||
f = fqueue.get()
|
|
||||||
if f is None:
|
|
||||||
break
|
|
||||||
(t, o, f, v) = \
|
|
||||||
main(src_base, out_base, [f], codes, outfile, **options)
|
|
||||||
tot_files += t
|
|
||||||
okay_files += o
|
|
||||||
failed_files += f
|
|
||||||
verify_failed_files += v
|
|
||||||
except (Empty, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
rqueue.put((tot_files, okay_files, failed_files, verify_failed_files))
|
|
||||||
rqueue.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
procs = [Process(target=process_func) for i in range(numproc)]
|
|
||||||
for p in procs:
|
|
||||||
p.start()
|
|
||||||
for p in procs:
|
|
||||||
p.join()
|
|
||||||
try:
|
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
|
||||||
while True:
|
|
||||||
(t, o, f, v) = rqueue.get(False)
|
|
||||||
tot_files += t
|
|
||||||
okay_files += o
|
|
||||||
failed_files += f
|
|
||||||
verify_failed_files += v
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
print('# decompiled %i files: %i okay, %i failed, %i verify failed' %
|
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files))
|
|
||||||
except (KeyboardInterrupt, OSError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if timestamp:
|
|
||||||
print(time.strftime(timestampfmt))
|
|
||||||
|
4
setup.py
4
setup.py
@@ -5,7 +5,7 @@
|
|||||||
from __pkginfo__ import \
|
from __pkginfo__ import \
|
||||||
author, author_email, install_requires, \
|
author, author_email, install_requires, \
|
||||||
license, long_description, classifiers, \
|
license, long_description, classifiers, \
|
||||||
modname, packages, py_modules, scripts, \
|
modname, packages, py_modules, entry_points, \
|
||||||
short_desc, web, zip_safe
|
short_desc, web, zip_safe
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
@@ -17,6 +17,7 @@ setup(
|
|||||||
author_email = author_email,
|
author_email = author_email,
|
||||||
classifiers = classifiers,
|
classifiers = classifiers,
|
||||||
description = short_desc,
|
description = short_desc,
|
||||||
|
entry_points = entry_points,
|
||||||
install_requires = install_requires,
|
install_requires = install_requires,
|
||||||
license = license,
|
license = license,
|
||||||
long_description = long_description,
|
long_description = long_description,
|
||||||
@@ -26,6 +27,5 @@ setup(
|
|||||||
test_suite = 'nose.collector',
|
test_suite = 'nose.collector',
|
||||||
url = web,
|
url = web,
|
||||||
setup_requires = ['nose>=1.0'],
|
setup_requires = ['nose>=1.0'],
|
||||||
scripts = scripts,
|
|
||||||
version = VERSION,
|
version = VERSION,
|
||||||
zip_safe = zip_safe)
|
zip_safe = zip_safe)
|
||||||
|
9
test/simple_source/bug26/05-ret-or.py
Normal file
9
test/simple_source/bug26/05-ret-or.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Python 2.6
|
||||||
|
# In contrast to Python 2.7 there might be no "COME_FROM" so we add rule:
|
||||||
|
# ret_or ::= expr JUMP_IF_TRUE expr
|
||||||
|
# where Python 2.7 has
|
||||||
|
# ret_or ::= expr JUMP_IF_TRUE expr COME_FROM
|
||||||
|
|
||||||
|
class BufferedIncrementalEncoder(object):
|
||||||
|
def getstate(self):
|
||||||
|
return self.buffer or 0
|
2
test/simple_source/def/03_star_arg.py
Normal file
2
test/simple_source/def/03_star_arg.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
def main(args=None, *, wrap_timer=None):
|
||||||
|
return 5
|
0
uncompyle6/bin/__init__.py
Normal file
0
uncompyle6/bin/__init__.py
Normal file
92
uncompyle6/bin/pydisassemble.py
Executable file
92
uncompyle6/bin/pydisassemble.py
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Mode: -*- python -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com>
|
||||||
|
#
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys, os, getopt
|
||||||
|
|
||||||
|
program = os.path.basename(__file__)
|
||||||
|
|
||||||
|
__doc__ = """
|
||||||
|
Usage:
|
||||||
|
%s [OPTIONS]... FILE
|
||||||
|
%s [--help | -h | -V | --version]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
%s foo.pyc
|
||||||
|
%s foo.py
|
||||||
|
%s -o foo.pydis foo.pyc
|
||||||
|
%s -o /tmp foo.pyc
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-o <path> output decompiled files to this path:
|
||||||
|
if multiple input files are decompiled, the common prefix
|
||||||
|
is stripped from these names and the remainder appended to
|
||||||
|
<path>
|
||||||
|
--help show this message
|
||||||
|
|
||||||
|
""" % ((program,) * 6)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
Usage_short = \
|
||||||
|
"%s [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..." % program
|
||||||
|
|
||||||
|
from uncompyle6 import check_python_version
|
||||||
|
from uncompyle6.disas import disassemble_files
|
||||||
|
from uncompyle6.version import VERSION
|
||||||
|
|
||||||
|
check_python_version(program)
|
||||||
|
|
||||||
|
outfile = '-'
|
||||||
|
out_base = None
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
print("No file(s) or directory given", file=sys.stderr)
|
||||||
|
print(Usage_short, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
opts, files = getopt.getopt(sys.argv[1:], 'hVo:', ['help', 'version'])
|
||||||
|
except getopt.GetoptError as e:
|
||||||
|
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
for opt, val in opts:
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
print(__doc__)
|
||||||
|
sys.exit(1)
|
||||||
|
elif opt in ('-V', '--version'):
|
||||||
|
print("%s %s" % (program, VERSION))
|
||||||
|
sys.exit(0)
|
||||||
|
elif opt == '-o':
|
||||||
|
outfile = val
|
||||||
|
else:
|
||||||
|
print(opt)
|
||||||
|
print(Usage_short, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# argl, commonprefix works on strings, not on path parts,
|
||||||
|
# thus we must handle the case with files in 'some/classes'
|
||||||
|
# and 'some/cmds'
|
||||||
|
src_base = os.path.commonprefix(files)
|
||||||
|
if src_base[-1:] != os.sep:
|
||||||
|
src_base = os.path.dirname(src_base)
|
||||||
|
if src_base:
|
||||||
|
sb_len = len( os.path.join(src_base, '') )
|
||||||
|
files = [f[sb_len:] for f in files]
|
||||||
|
del sb_len
|
||||||
|
|
||||||
|
if outfile == '-':
|
||||||
|
outfile = None # use stdout
|
||||||
|
elif outfile and os.path.isdir(outfile):
|
||||||
|
out_base = outfile; outfile = None
|
||||||
|
elif outfile and len(files) > 1:
|
||||||
|
out_base = outfile; outfile = None
|
||||||
|
|
||||||
|
disassemble_files(src_base, out_base, files, outfile)
|
||||||
|
return
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
228
uncompyle6/bin/uncompile.py
Executable file
228
uncompyle6/bin/uncompile.py
Executable file
@@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Mode: -*- python -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015-2016 by Rocky Bernstein
|
||||||
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
|
#
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys, os, getopt, time
|
||||||
|
|
||||||
|
program = os.path.basename(__file__)
|
||||||
|
|
||||||
|
__doc__ = """
|
||||||
|
Usage:
|
||||||
|
%s [OPTIONS]... [ FILE | DIR]...
|
||||||
|
%s [--help | -h | --V | --version]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
%s foo.pyc bar.pyc # decompile foo.pyc, bar.pyc to stdout
|
||||||
|
%s -o . foo.pyc bar.pyc # decompile to ./foo.pyc_dis and ./bar.pyc_dis
|
||||||
|
%s -o /tmp /usr/lib/python1.5 # decompile whole library
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-o <path> output decompiled files to this path:
|
||||||
|
if multiple input files are decompiled, the common prefix
|
||||||
|
is stripped from these names and the remainder appended to
|
||||||
|
<path>
|
||||||
|
uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc
|
||||||
|
-> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis
|
||||||
|
uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc
|
||||||
|
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
|
||||||
|
uncompyle6 -o /tmp /usr/lib/python1.5
|
||||||
|
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
|
||||||
|
-c <file> attempts a disassembly after compiling <file>
|
||||||
|
-d print timestamps
|
||||||
|
-p <integer> use <integer> number of processes
|
||||||
|
-r recurse directories looking for .pyc and .pyo files
|
||||||
|
--verify compare generated source with input byte-code
|
||||||
|
(requires -o)
|
||||||
|
--help show this message
|
||||||
|
|
||||||
|
Debugging Options:
|
||||||
|
--asm -a include byte-code (disables --verify)
|
||||||
|
--grammar -g show matching grammar
|
||||||
|
--tree -t include syntax tree (disables --verify)
|
||||||
|
|
||||||
|
Extensions of generated files:
|
||||||
|
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
||||||
|
+ '_unverified' successfully decompile but --verify failed
|
||||||
|
+ '_failed' decompile failed (contact author for enhancement)
|
||||||
|
""" % ((program,) * 5)
|
||||||
|
|
||||||
|
program = os.path.basename(__file__)
|
||||||
|
|
||||||
|
from uncompyle6 import verify, check_python_version
|
||||||
|
from uncompyle6.main import main, status_msg
|
||||||
|
from uncompyle6.version import VERSION
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print("""usage:
|
||||||
|
%s [--verify] [--asm] [--tree] [--grammar] [-o <path>] FILE|DIR...
|
||||||
|
%s [--help | -h | --version | -V]
|
||||||
|
""" % (program, program))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main_bin():
|
||||||
|
check_python_version(program)
|
||||||
|
|
||||||
|
showasm = showast = do_verify = recurse_dirs = False
|
||||||
|
numproc = 0
|
||||||
|
outfile = '-'
|
||||||
|
out_base = None
|
||||||
|
codes = []
|
||||||
|
timestamp = False
|
||||||
|
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
||||||
|
|
||||||
|
try:
|
||||||
|
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
|
||||||
|
'help asm grammar recurse timestamp tree verify version '
|
||||||
|
'showgrammar'.split(' '))
|
||||||
|
except getopt.GetoptError as e:
|
||||||
|
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
options = {}
|
||||||
|
for opt, val in opts:
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
print(__doc__)
|
||||||
|
sys.exit(0)
|
||||||
|
elif opt in ('-V', '--version'):
|
||||||
|
print("%s %s" % (program, VERSION))
|
||||||
|
sys.exit(0)
|
||||||
|
elif opt == '--verify':
|
||||||
|
options['do_verify'] = True
|
||||||
|
elif opt in ('--asm', '-a'):
|
||||||
|
options['showasm'] = True
|
||||||
|
options['do_verify'] = False
|
||||||
|
elif opt in ('--tree', '-t'):
|
||||||
|
options['showast'] = True
|
||||||
|
options['do_verify'] = False
|
||||||
|
elif opt in ('--grammar', '-g'):
|
||||||
|
options['showgrammar'] = True
|
||||||
|
elif opt == '-o':
|
||||||
|
outfile = val
|
||||||
|
elif opt in ('--timestamp', '-d'):
|
||||||
|
timestamp = True
|
||||||
|
elif opt == '-c':
|
||||||
|
codes.append(val)
|
||||||
|
elif opt == '-p':
|
||||||
|
numproc = int(val)
|
||||||
|
elif opt in ('--recurse', '-r'):
|
||||||
|
recurse_dirs = True
|
||||||
|
else:
|
||||||
|
print(opt, file=sys.stderr)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
# expand directory if specified
|
||||||
|
if recurse_dirs:
|
||||||
|
expanded_files = []
|
||||||
|
for f in files:
|
||||||
|
if os.path.isdir(f):
|
||||||
|
for root, _, dir_files in os.walk(f):
|
||||||
|
for df in dir_files:
|
||||||
|
if df.endswith('.pyc') or df.endswith('.pyo'):
|
||||||
|
expanded_files.append(os.path.join(root, df))
|
||||||
|
files = expanded_files
|
||||||
|
|
||||||
|
# argl, commonprefix works on strings, not on path parts,
|
||||||
|
# thus we must handle the case with files in 'some/classes'
|
||||||
|
# and 'some/cmds'
|
||||||
|
src_base = os.path.commonprefix(files)
|
||||||
|
if src_base[-1:] != os.sep:
|
||||||
|
src_base = os.path.dirname(src_base)
|
||||||
|
if src_base:
|
||||||
|
sb_len = len( os.path.join(src_base, '') )
|
||||||
|
files = [f[sb_len:] for f in files]
|
||||||
|
del sb_len
|
||||||
|
|
||||||
|
if not files:
|
||||||
|
print("No files given", file=sys.stderr)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
|
||||||
|
if outfile == '-':
|
||||||
|
outfile = None # use stdout
|
||||||
|
elif outfile and os.path.isdir(outfile):
|
||||||
|
out_base = outfile; outfile = None
|
||||||
|
elif outfile and len(files) > 1:
|
||||||
|
out_base = outfile; outfile = None
|
||||||
|
|
||||||
|
if timestamp:
|
||||||
|
print(time.strftime(timestampfmt))
|
||||||
|
|
||||||
|
if numproc <= 1:
|
||||||
|
try:
|
||||||
|
result = main(src_base, out_base, files, codes, outfile,
|
||||||
|
**options)
|
||||||
|
if len(files) > 1:
|
||||||
|
mess = status_msg(do_verify, *result)
|
||||||
|
print('# ' + mess)
|
||||||
|
pass
|
||||||
|
except (KeyboardInterrupt):
|
||||||
|
pass
|
||||||
|
except verify.VerifyCmpError:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
from multiprocessing import Process, Queue
|
||||||
|
|
||||||
|
try:
|
||||||
|
from Queue import Empty
|
||||||
|
except ImportError:
|
||||||
|
from Queue import Empty
|
||||||
|
|
||||||
|
fqueue = Queue(len(files)+numproc)
|
||||||
|
for f in files:
|
||||||
|
fqueue.put(f)
|
||||||
|
for i in range(numproc):
|
||||||
|
fqueue.put(None)
|
||||||
|
|
||||||
|
rqueue = Queue(numproc)
|
||||||
|
|
||||||
|
def process_func():
|
||||||
|
try:
|
||||||
|
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
||||||
|
while 1:
|
||||||
|
f = fqueue.get()
|
||||||
|
if f is None:
|
||||||
|
break
|
||||||
|
(t, o, f, v) = \
|
||||||
|
main(src_base, out_base, [f], codes, outfile, **options)
|
||||||
|
tot_files += t
|
||||||
|
okay_files += o
|
||||||
|
failed_files += f
|
||||||
|
verify_failed_files += v
|
||||||
|
except (Empty, KeyboardInterrupt):
|
||||||
|
pass
|
||||||
|
rqueue.put((tot_files, okay_files, failed_files, verify_failed_files))
|
||||||
|
rqueue.close()
|
||||||
|
|
||||||
|
try:
|
||||||
|
procs = [Process(target=process_func) for i in range(numproc)]
|
||||||
|
for p in procs:
|
||||||
|
p.start()
|
||||||
|
for p in procs:
|
||||||
|
p.join()
|
||||||
|
try:
|
||||||
|
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
||||||
|
while True:
|
||||||
|
(t, o, f, v) = rqueue.get(False)
|
||||||
|
tot_files += t
|
||||||
|
okay_files += o
|
||||||
|
failed_files += f
|
||||||
|
verify_failed_files += v
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
print('# decompiled %i files: %i okay, %i failed, %i verify failed' %
|
||||||
|
(tot_files, okay_files, failed_files, verify_failed_files))
|
||||||
|
except (KeyboardInterrupt, OSError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if timestamp:
|
||||||
|
print(time.strftime(timestampfmt))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main_bin()
|
Reference in New Issue
Block a user