Files
python-uncompyle6/uncompyle6/load.py

118 lines
4.2 KiB
Python

# Copyright (c) 2015 by Rocky Bernstein
# Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
from __future__ import print_function
import imp, marshal, os, py_compile, sys, tempfile
from struct import unpack
import uncompyle6.marsh
from uncompyle6 import PYTHON3
from uncompyle6 import magics
def check_object_path(path):
if path.endswith(".py"):
try:
import importlib
return importlib.util.cache_from_source(path,
optimization='')
except:
try:
import imp
imp.cache_from_source(path, debug_override=False)
except:
pass
pass
basename = os.path.basename(path)[0:-3]
spath = path if PYTHON3 else path.decode('utf-8')
path = tempfile.mkstemp(prefix=basename + '-',
suffix='.pyc', text=False)[1]
py_compile.compile(spath, cfile=path, doraise=True)
if not path.endswith(".pyc") and not path.endswith(".pyo"):
raise ValueError("path %s must point to a .py or .pyc file\n" %
path)
return path
def load_file(filename):
"""
load a Python source file and compile it to byte-code
_load_file(filename: string): code_object
filename: name of file containing Python source code
(normally a .py)
code_object: code_object compiled from this source code
This function does NOT write any file!
"""
with open(filename, 'rb') as fp:
source = fp.read().decode('utf-8') + '\n'
try:
co = compile(source, filename, 'exec', dont_inherit=True)
except SyntaxError:
print('>>Syntax error in %s\n' % filename, file= sys.stderr)
raise
pass
return co
def load_module(filename, code_objects={}):
"""
load a module without importing it.
load_module(filename: string): version, magic_int, code_object
filename: name of file containing Python byte-code object
(normally a .pyc)
code_object: code_object from this file
version: Python major/minor value e.g. 2.7. or 3.4
magic_int: more specific than version. The actual byte code version of the
code object
"""
with open(filename, 'rb') as fp:
magic = fp.read(4)
try:
version = float(magics.versions[magic])
except KeyError:
if len(magic) >= 2:
raise ImportError("Unknown magic number %s in %s" %
(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.5):
raise ImportError("This is a Python %s file! Only "
"Python 2.5 to 2.7 and 3.2 to 3.5 files are supported."
% version)
# print version
ts = fp.read(4)
timestamp = unpack("I", ts)[0]
magic_int = magics.magic2int(magic)
my_magic_int = magics.magic2int(imp.get_magic())
# Note: a higher magic number doesn't necessarily mean a later
# release. At Python 3.0 the magic number decreased
# significantly. Hence the range below. Also note inclusion of
# the size info, occurred within a Python major/minor
# release. Hence the test on the magic value rather than
# PYTHON_VERSION, although PYTHON_VERSION would probably work.
if 3200 <= magic_int < 20121:
fp.read(4) # size mod 2**32
if my_magic_int == magic_int:
bytecode = fp.read()
co = marshal.loads(bytecode)
else:
co = uncompyle6.marsh.load_code(fp, magic_int, code_objects)
pass
return version, timestamp, magic_int, co
if __name__ == '__main__':
co = load_file(__file__)
obj_path = check_object_path(__file__)
version, timestamp, magic_int, co2 = load_module(obj_path)
print("version", version, "magic int", magic_int)
import datetime
print(datetime.datetime.fromtimestamp(timestamp))
if version < 3.5:
assert co == co2