mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-11-23 13:09:49 +00:00
319 lines
8.3 KiB
Python
Executable File
319 lines
8.3 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# emacs-mode: -*-python-*-
|
|
|
|
"""
|
|
test_pythonlib.py -- compile, uncompyle, and verify Python libraries
|
|
|
|
Usage-Examples:
|
|
|
|
# decompile, and verify base set of python 2.7 byte-compiled files
|
|
test_pythonlib.py --base-2.7 --verify
|
|
|
|
# Same as above but compile the base set first
|
|
test_pythonlib.py --base-2.7 --verify --compile
|
|
|
|
# Same as above but use a longer set from the python 2.7 library
|
|
test_pythonlib.py --ok-2.7 --verify --compile
|
|
|
|
# Just deompile the longer set of files
|
|
test_pythonlib.py --ok-2.7
|
|
|
|
Adding own test-trees:
|
|
|
|
Step 1) Edit this file and add a new entry to 'test_options', eg.
|
|
test_options['mylib'] = ('/usr/lib/mylib', PYOC, 'mylib')
|
|
Step 2: Run the test:
|
|
test_pythonlib.py --mylib # decompile 'mylib'
|
|
test_pythonlib.py --mylib --verify # decompile verify 'mylib'
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import getopt
|
|
import os
|
|
import py_compile
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
from fnmatch import fnmatch
|
|
|
|
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
|
|
|
from uncompyle6.main import main
|
|
|
|
|
|
def get_srcdir():
|
|
filename = os.path.normcase(os.path.dirname(__file__))
|
|
return os.path.realpath(filename)
|
|
|
|
|
|
src_dir = get_srcdir()
|
|
|
|
|
|
# ----- configure this for your needs
|
|
|
|
lib_prefix = "/usr/lib"
|
|
# lib_prefix = [src_dir, '/usr/lib/', '/usr/local/lib/']
|
|
|
|
target_base = tempfile.mkdtemp(prefix="py-dis-")
|
|
|
|
PY = ("*.py",)
|
|
PYC = ("*.pyc",)
|
|
PYO = ("*.pyo",)
|
|
PYOC = ("*.pyc", "*.pyo")
|
|
|
|
test_options = {
|
|
# name: (src_basedir, pattern, output_base_suffix, python_version)
|
|
"test": ("test", PYC, "test"),
|
|
"ok-2.6": (os.path.join(src_dir, "ok_lib2.6"), PYOC, "ok-2.6", 2.6),
|
|
"ok-2.7": (os.path.join(src_dir, "ok_lib2.7"), PYOC, "ok-2.7", 2.7),
|
|
"ok-3.2": (os.path.join(src_dir, "ok_lib3.2"), PYOC, "ok-3.2", 3.2),
|
|
"base-2.7": (
|
|
os.path.join(src_dir, "base_tests", "python2.7"),
|
|
PYOC,
|
|
"base_2.7",
|
|
2.7,
|
|
),
|
|
}
|
|
|
|
for vers in (2.7, 3.4, 3.5, 3.6):
|
|
pythonlib = "ok_lib%s" % vers
|
|
key = "ok-%s" % vers
|
|
test_options[key] = (os.path.join(src_dir, pythonlib), PYOC, key, vers)
|
|
pass
|
|
|
|
for vers in (
|
|
1.0,
|
|
1.1,
|
|
1.2,
|
|
1.3,
|
|
1.4,
|
|
1.5,
|
|
1.6,
|
|
2.1,
|
|
2.2,
|
|
2.3,
|
|
2.4,
|
|
2.5,
|
|
2.6,
|
|
2.7,
|
|
3.0,
|
|
3.1,
|
|
3.2,
|
|
3.3,
|
|
3.4,
|
|
3.5,
|
|
3.6,
|
|
3.7,
|
|
3.8,
|
|
"pypy3.2",
|
|
"pypy2.7",
|
|
"pypy3.6",
|
|
):
|
|
bytecode = "bytecode_%s" % vers
|
|
key = "bytecode-%s" % vers
|
|
test_options[key] = (bytecode, PYC, bytecode, vers)
|
|
bytecode = "bytecode_%s_run" % vers
|
|
key = "bytecode-%s-run" % vers
|
|
test_options[key] = (bytecode, PYC, bytecode, vers)
|
|
key = "%s" % vers
|
|
pythonlib = "python%s" % vers
|
|
if isinstance(vers, float) and vers >= 3.0:
|
|
pythonlib = os.path.join(pythonlib, "__pycache__")
|
|
test_options[key] = (os.path.join(lib_prefix, pythonlib), PYOC, pythonlib, vers)
|
|
|
|
for vers, vers_dot in ((37, 3.7), (38, 3.8)):
|
|
bytecode = "bytecode_pypy%s_run" % vers
|
|
key = "bytecode-pypy%s" % vers
|
|
test_options[key] = (bytecode, PYC, bytecode, vers_dot)
|
|
key = "bytecode-pypy%s" % vers_dot
|
|
test_options[key] = (bytecode, PYC, bytecode, vers_dot)
|
|
|
|
|
|
# -----
|
|
|
|
|
|
def help():
|
|
print(
|
|
"""Usage-Examples:
|
|
|
|
# compile, decompyle and verify short tests for Python 2.7:
|
|
test_pythonlib.py --bytecode-2.7 --verify --compile
|
|
|
|
# decompile all of Python's installed lib files
|
|
test_pythonlib.py --2.7
|
|
|
|
# decompile and verify known good python 2.7
|
|
test_pythonlib.py --ok-2.7 --verify
|
|
"""
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
def do_tests(src_dir, obj_patterns, target_dir, opts):
|
|
def file_matches(files, root, basenames, patterns):
|
|
files.extend(
|
|
[
|
|
os.path.normpath(os.path.join(root, n))
|
|
for n in basenames
|
|
for pat in patterns
|
|
if fnmatch(n, pat)
|
|
]
|
|
)
|
|
|
|
files = []
|
|
# Change directories so use relative rather than
|
|
# absolute paths. This speeds up things, and allows
|
|
# main() to write to a relative-path destination.
|
|
cwd = os.getcwd()
|
|
os.chdir(src_dir)
|
|
|
|
if opts["do_compile"]:
|
|
compiled_version = opts["compiled_version"]
|
|
if compiled_version and PYTHON_VERSION_TRIPLE != compiled_version:
|
|
print(
|
|
"Not compiling: desired Python version is %s but we are running %s"
|
|
% (compiled_version, PYTHON_VERSION_TRIPLE),
|
|
file=sys.stderr,
|
|
)
|
|
else:
|
|
for root, dirs, basenames in os.walk(src_dir):
|
|
file_matches(files, root, basenames, PY)
|
|
for sfile in files:
|
|
py_compile.compile(sfile)
|
|
pass
|
|
pass
|
|
files = []
|
|
pass
|
|
pass
|
|
|
|
for root, dirs, basenames in os.walk("."):
|
|
# Turn root into a relative path
|
|
dirname = root[2:] # 2 = len('.') + 1
|
|
file_matches(files, dirname, basenames, obj_patterns)
|
|
|
|
if not files:
|
|
print(
|
|
"Didn't come up with any files to test! Try with --compile?",
|
|
file=sys.stderr,
|
|
)
|
|
exit(1)
|
|
|
|
os.chdir(cwd)
|
|
files.sort()
|
|
|
|
if opts["start_with"]:
|
|
try:
|
|
start_with = files.index(opts["start_with"])
|
|
files = files[start_with:]
|
|
print(">>> starting with file", files[0])
|
|
except ValueError:
|
|
pass
|
|
|
|
print(time.ctime())
|
|
print("Source directory: ", src_dir)
|
|
print("Output directory: ", target_dir)
|
|
try:
|
|
_, _, failed_files, failed_verify = main(
|
|
src_dir, target_dir, files, []
|
|
)
|
|
if failed_files != 0:
|
|
sys.exit(2)
|
|
elif failed_verify != 0:
|
|
sys.exit(3)
|
|
|
|
except (KeyboardInterrupt, OSError):
|
|
print()
|
|
sys.exit(1)
|
|
if test_opts["rmtree"]:
|
|
parent_dir = os.path.dirname(target_dir)
|
|
print("Everything good, removing %s" % parent_dir)
|
|
shutil.rmtree(parent_dir)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_dirs = []
|
|
checked_dirs = []
|
|
start_with = None
|
|
|
|
test_options_keys = list(test_options.keys())
|
|
test_options_keys.sort()
|
|
opts, args = getopt.getopt(
|
|
sys.argv[1:],
|
|
"",
|
|
[
|
|
"start-with=",
|
|
"verify",
|
|
"verify-run",
|
|
"syntax-verify",
|
|
"all",
|
|
"compile",
|
|
"coverage",
|
|
"no-rm",
|
|
]
|
|
+ test_options_keys,
|
|
)
|
|
if not opts:
|
|
help()
|
|
|
|
test_opts = {
|
|
"do_compile": False,
|
|
"do_verify": False,
|
|
"start_with": None,
|
|
"rmtree": True,
|
|
"coverage": False,
|
|
}
|
|
|
|
for opt, val in opts:
|
|
if opt == "--verify":
|
|
test_opts["do_verify"] = "strong"
|
|
elif opt == "--syntax-verify":
|
|
test_opts["do_verify"] = "weak"
|
|
elif opt == "--verify-run":
|
|
test_opts["do_verify"] = "verify-run"
|
|
elif opt == "--compile":
|
|
test_opts["do_compile"] = True
|
|
elif opt == "--start-with":
|
|
test_opts["start_with"] = val
|
|
elif opt == "--no-rm":
|
|
test_opts["rmtree"] = False
|
|
elif opt[2:] in test_options_keys:
|
|
test_dirs.append(test_options[opt[2:]])
|
|
elif opt == "--all":
|
|
for val in test_options_keys:
|
|
test_dirs.append(test_options[val])
|
|
elif opt == "--coverage":
|
|
test_opts["coverage"] = True
|
|
else:
|
|
help()
|
|
pass
|
|
pass
|
|
|
|
if test_opts["coverage"]:
|
|
os.environ["SPARK_PARSER_COVERAGE"] = (
|
|
"/tmp/spark-grammar-python-lib%s.cover" % test_dirs[0][-1]
|
|
)
|
|
|
|
last_compile_version = None
|
|
for src_dir, pattern, target_dir, compiled_version in test_dirs:
|
|
if os.path.isdir(src_dir):
|
|
checked_dirs.append([src_dir, pattern, target_dir])
|
|
else:
|
|
print("Can't find directory %s. Skipping" % src_dir, file=sys.stderr)
|
|
continue
|
|
last_compile_version = compiled_version
|
|
pass
|
|
|
|
if not checked_dirs:
|
|
print("No directories found to check", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
test_opts["compiled_version"] = last_compile_version
|
|
|
|
for src_dir, pattern, target_dir in checked_dirs:
|
|
target_dir = os.path.join(target_base, target_dir)
|
|
if os.path.exists(target_dir):
|
|
shutil.rmtree(target_dir, ignore_errors=1)
|
|
do_tests(src_dir, pattern, target_dir, test_opts)
|