--- a/pyscovery.py Tue Apr 16 09:14:41 2013 -0500
+++ b/pyscovery.py Sun May 26 05:19:56 2013 -0500
@@ -30,53 +30,176 @@
-# we use a list since it is a mutable sequence type. Meaning we can add to it
+from threading import Lock + def _real_add_module(self, module, modules=None): + The method that does the real addition of of a module to the search + if not module in modules: + def add_module(self, module): + Adds module to the search path + self._real_add_module(module) + def _real_remove_module(self, module, modules=None): + The method that does the real removal of a module from the search path. + self.modules.remove(module) + def remove_module(self, module): + Removes module from the search paths + self._real_add_module(module) + Gets the search paths for this Loader.
+ def clear_modules(self): + Clears the module search path. + def find(self, cls, recurse, create, *args, **kwargs): + """Find all plugins that are subclasses of cls. + :param cls: The class whose subclasses to find. + :param recurse: Whether or not to recurse into packages. + :param create: return instances rather than just return their class. + :param args: Additional arguments to pass to each constructor. Ignored if + :param kwargs: Additional keyword arguements to pass to each constructor. + Ignored if create is False. + :returns: Generator of subclasses of cls + def _is_package(cls, module): + Returns true if the module's name is __init__, false otherwise + filename = os.path.basename(module.__file__) + base, _ = os.path.splitext(filename) + return base == '__init__' + def _recurse(self, module): + Adds additional modules from a package + dirname = os.path.dirname(module.__file__) + make_module = lambda name: '.'.join((module.__name__, name)) + for name in os.listdir(dirname): + base, _ = os.path.splitext(name) + filename = os.path.join(dirname, name) + if os.path.isdir(filename): + add_module(make_module(base)) + elif os.path.isfile(filename): + if fnmatch.fnmatch(name, '*.py') or \ + fnmatch.fnmatch(name, '*.py[co]'): + add_module(make_module(base)) +_DEFAULT_LOADER = Loader() """Adds a module to search for plugins under
:param module: The module to add to the search paths
- global MODULES # pylint:disable-msg=W0602
+ _DEFAULT_LOADER.add_module(module) - if not module in MODULES:
def remove_module(module):
"""Removes a module to search for plugins under
:param module: The module to remove
- global MODULES # pylint:disable-msg=W0602
+ _DEFAULT_LOADER.remove_module(module)
"""Returns the list of all module to search under
:returns: A list of the current modules used for searching
+ return _DEFAULT_LOADER.get_modules() """Clears all search modules
+ _DEFAULT_LOADER.clear_modules() def find(cls, recurse, create, *args, **kwargs):
@@ -98,28 +221,31 @@
if not inspect.isclass(cls):
- raise TypeError('{} is not a class instance')
+ raise TypeError('{} is not a class instance'.format(cls))
+ modules.extend(MODULES) mod = importlib.import_module(module)
if recurse and _is_package(mod):
for symbol_name in dir(mod):
if symbol_name == cls_name:
symbol = getattr(mod, symbol_name, None)
if not inspect.isclass(symbol):
if inspect.isabstract(symbol):
if not issubclass(symbol, cls):
@@ -136,7 +262,7 @@
filename = os.path.basename(module.__file__)
base, _ = os.path.splitext(filename)
return base == '__init__'
@@ -151,12 +277,12 @@
for name in os.listdir(dirname):
base, _ = os.path.splitext(name)
filename = os.path.join(dirname, name)
if os.path.isdir(filename):
add_module(make_module(base))
elif os.path.isfile(filename):