diff --git a/direct/src/showutil/FreezeTool.py b/direct/src/showutil/FreezeTool.py index c82bfe25eb..fb346b1610 100644 --- a/direct/src/showutil/FreezeTool.py +++ b/direct/src/showutil/FreezeTool.py @@ -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__ = '' - 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()