FreezeTool: find modules in zip files, allow custom suffixes list

This commit is contained in:
rdb 2017-01-04 19:57:51 +01:00
parent 6b92d349c9
commit 13c41bcf7d
1 changed files with 112 additions and 34 deletions

View File

@ -10,6 +10,7 @@ import platform
import struct
from io import StringIO
import distutils.sysconfig as sysconf
import zipfile
# Temporary (?) try..except to protect against unbuilt p3extend_frozen.
try:
@ -1661,51 +1662,128 @@ class Freezer:
return True
class PandaModuleFinder(modulefinder.ModuleFinder):
""" We subclass ModuleFinder here, to add functionality for
finding the libpandaexpress etc. modules that interrogate
produces. """
def __init__(self, *args, **kw):
"""
:param path: search path to look on, defaults to sys.path
:param suffixes: defaults to imp.get_suffixes()
:param excludes: a list of modules to exclude
:param debug: an integer indicating the level of verbosity
"""
self.suffixes = kw.pop('suffixes', imp.get_suffixes())
modulefinder.ModuleFinder.__init__(self, *args, **kw)
def find_module(self, name, path, *args, **kwargs):
# Make sure we don't open a .whl/.zip file more than once.
self._zip_files = {}
def _open_file(self, path, mode):
""" Opens a module at the given path, which may contain a zip file.
Returns None if the module could not be found. """
if os.path.isfile(path):
return open(path, mode)
# Is there a zip file along the path?
dir, dirname = os.path.split(path)
fn = dirname
while dirname:
if os.path.isfile(dir):
# Okay, this is actually a file. Is it a zip file?
if dir in self._zip_files:
# Yes, and we've previously opened this.
zip = self._zip_files[dir]
elif zipfile.is_zipfile(dir):
zip = zipfile.ZipFile(dir)
self._zip_files[dir] = zip
else:
# It's a different kind of file. Stop looking.
return None
try:
fp = zip.open(fn, 'r')
except KeyError:
return None
if sys.version_info >= (3, 0) and 'b' not in mode:
return TextIOWrapper(fp)
return fp
# Look at the parent directory.
dir, dirname = os.path.split(dir)
fn = os.path.join(dirname, fn)
return None
def find_module(self, name, path=None, parent=None):
""" Finds a module with the indicated name on the given search path
(or self.path if None). Returns a tuple like (fp, path, stuff), where
stuff is a tuple like (suffix, mode, type). """
if imp.is_frozen(name):
# Don't pick up modules that are frozen into p3dpython.
raise ImportError("'%s' is a frozen module" % (name))
try:
return modulefinder.ModuleFinder.find_module(self, name, path, *args, **kwargs)
except ImportError:
# It wasn't found through the normal channels. Maybe it's
# one of ours, or maybe it's frozen?
if path:
# Only if we're not looking on a particular path,
# though.
raise
if parent is not None:
fullname = parent.__name__+'.'+name
else:
fullname = name
if fullname in self.excludes:
raise ImportError(name)
# If no search path is given, look for a built-in module.
if path is None:
if name in sys.builtin_module_names:
return (None, None, ('', '', imp.C_BUILTIN))
path = self.path
# Look for the module on the search path.
for dir_path in path:
basename = os.path.join(dir_path, name.split('.')[-1])
# Look for recognized extensions.
for stuff in self.suffixes:
suffix, mode, type = stuff
fp = self._open_file(basename + suffix, mode)
if fp:
return (fp, basename + suffix, stuff)
# Consider a package, i.e. a directory containing __init__.py.
for suffix, mode, type in self.suffixes:
init = os.path.join(basename, '__init__' + suffix)
if self._open_file(init, mode):
return (None, basename, ('', '', imp.PKG_DIRECTORY))
# It wasn't found through the normal channels. Maybe it's one of
# ours, or maybe it's frozen?
if not path:
# Only if we're not looking on a particular path, though.
if p3extend_frozen and p3extend_frozen.is_frozen_module(name):
# It's a frozen module.
return (None, name, ('', '', imp.PY_FROZEN))
message = "DLL loader cannot find %s." % (name)
raise ImportError(message)
raise ImportError(name)
def load_module(self, fqname, fp, pathname, file_info):
suffix, mode, type = file_info
if type == imp.PY_FROZEN:
# It's a frozen module.
co, isPackage = p3extend_frozen.get_frozen_module_code(pathname)
m = self.add_module(fqname)
m.__file__ = '<frozen>'
if isPackage:
m.__path__ = [pathname]
co = marshal.loads(co)
if self.replace_paths:
co = self.replace_paths_in_code(co)
m.__code__ = co
self.scan_code(co, m)
self.msgout(2, "load_module ->", m)
return m
return modulefinder.ModuleFinder.load_module(self, fqname, fp, pathname, (suffix, mode, type))
def find_all_submodules(self, m):
# Overridden so that we can define our own suffixes.
if not m.__path__:
return
modules = {}
for dir in m.__path__:
try:
names = os.listdir(dir)
except OSError:
self.msg(2, "can't list directory", dir)
continue
for name in names:
mod = None
for suff in self.suffixes:
n = len(suff)
if name[-n:] == suff:
mod = name[:-n]
break
if mod and mod != "__init__":
modules[mod] = mod
return modules.keys()