Switch plugin loading to pkgutil.

This should work with all PEP-302 loaders that implement iter_modules.
Unfortunatly, PyInstaller (which I plan to use for Windows releases)
does not support it, so we don't get around a special case. Anyways,
this should help for #22.
This commit is contained in:
Tobias Gruetzmacher 2016-03-20 15:13:24 +01:00
parent 065184f1db
commit cfcfcc2468
2 changed files with 24 additions and 41 deletions

View file

@ -1,5 +1,7 @@
# -*- coding: iso-8859-1 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2016 Tobias Gruetzmacher
""" """
Functions to load plugin modules. Functions to load plugin modules.
@ -7,55 +9,37 @@ Example usage:
modules = loader.get_modules('plugins') modules = loader.get_modules('plugins')
plugins = loader.get_plugins(modules, PluginClass) plugins = loader.get_plugins(modules, PluginClass)
""" """
import os
import sys from __future__ import absolute_import, division, print_function
import zipfile import pkgutil
import importlib import importlib
from .output import out from .output import out
def is_frozen ():
"""Return True if running inside a py2exe- or py2app-generated
executable."""
return hasattr(sys, "frozen")
def get_modules(folder): def get_modules(folder):
"""Find all valid modules in the given folder which must be in """Find (and import) all valid modules in the given submodule of this file.
in the same directory as this loader.py module. A valid module
has a .py extension, and is importable.
@return: all loaded valid modules @return: all loaded valid modules
@rtype: iterator of module @rtype: iterator of module
""" """
if is_frozen(): mod = importlib.import_module(".." + folder, __name__)
# find modules in library.zip filename prefix = mod.__name__ + "."
zipname = os.path.dirname(os.path.dirname(__file__)) modules = [m[1] for m in pkgutil.iter_modules(mod.__path__, prefix)]
parentmodule = os.path.basename(os.path.dirname(__file__))
with zipfile.ZipFile(zipname, 'r') as f: # special handling for PyInstaller
prefix = "%s/%s/" % (parentmodule, folder) importers = map(pkgutil.get_importer, mod.__path__)
modnames = [os.path.splitext(n[len(prefix):])[0] toc = set()
for n in f.namelist() for i in importers:
if n.startswith(prefix) and "__init__" not in n] if hasattr(i, 'toc'):
else: toc |= i.toc
dirname = os.path.join(os.path.dirname(__file__), folder) for elm in toc:
modnames = get_importable_modules(dirname) if elm.startswith(prefix):
for modname in modnames: modules.append(elm)
for name in modules:
try: try:
name ="..%s.%s" % (folder, modname) yield importlib.import_module(name)
yield importlib.import_module(name, __name__)
except ImportError as msg: except ImportError as msg:
out.error("could not load module %s: %s" % (modname, msg)) out.error("could not load module %s: %s" % (name, msg))
def get_importable_modules(folder):
"""Find all module files in the given folder that end with '.py' and
don't start with an underscore.
@return module names
@rtype: iterator of string
"""
for fname in os.listdir(folder):
if fname.endswith('.py') and not fname.startswith('_'):
yield fname[:-3]
def get_plugins(modules, classobj): def get_plugins(modules, classobj):

View file

@ -1 +0,0 @@
# -*- coding: iso-8859-1 -*-