summaryrefslogtreecommitdiff
path: root/src/mailman/utilities/modules.py
diff options
context:
space:
mode:
authorBarry Warsaw2012-12-28 16:35:08 -0500
committerBarry Warsaw2012-12-28 16:35:08 -0500
commit582d6e486f9693a2ce082071b747eec468df19b6 (patch)
treec25dcc945f161c6d44154c20de72793702be313e /src/mailman/utilities/modules.py
parent2b663ac20e7898167cf242d3628f8cf0feeab12f (diff)
downloadmailman-582d6e486f9693a2ce082071b747eec468df19b6.tar.gz
mailman-582d6e486f9693a2ce082071b747eec468df19b6.tar.zst
mailman-582d6e486f9693a2ce082071b747eec468df19b6.zip
Diffstat (limited to 'src/mailman/utilities/modules.py')
-rw-r--r--src/mailman/utilities/modules.py53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/mailman/utilities/modules.py b/src/mailman/utilities/modules.py
index d8b788054..4ba549f99 100644
--- a/src/mailman/utilities/modules.py
+++ b/src/mailman/utilities/modules.py
@@ -22,12 +22,17 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'call_name',
+ 'find_components',
'find_name',
+ 'scan_module',
]
+import os
import sys
+from pkg_resources import resource_listdir
+
def find_name(dotted_name):
@@ -43,6 +48,7 @@ def find_name(dotted_name):
return getattr(sys.modules[package_path], object_name)
+
def call_name(dotted_name, *args, **kws):
"""Imports and calls the named object in package space.
@@ -57,3 +63,50 @@ def call_name(dotted_name, *args, **kws):
"""
named_callable = find_name(dotted_name)
return named_callable(*args, **kws)
+
+
+
+def scan_module(module, interface):
+ """Return all the items in a module that conform to an interface.
+
+ :param module: A module object. The module's `__all__` will be scanned.
+ :type module: module
+ :param interface: The interface that returned objects must conform to.
+ :type interface: `Interface`
+ :return: The sequence of matching components.
+ :rtype: objects implementing `interface`
+ """
+ missing = object()
+ for name in module.__all__:
+ component = getattr(module, name, missing)
+ assert component is not missing, (
+ '%s has bad __all__: %s' % (module, name))
+ if interface.implementedBy(component):
+ yield component
+
+
+
+def find_components(package, interface):
+ """Find components which conform to a given interface.
+
+ Search all the modules in a given package, returning an iterator over all
+ objects found that conform to the given interface.
+
+ :param package: The package path to search.
+ :type package: string
+ :param interface: The interface that returned objects must conform to.
+ :type interface: `Interface`
+ :return: The sequence of matching components.
+ :rtype: objects implementing `interface`
+ """
+ for filename in resource_listdir(package, ''):
+ basename, extension = os.path.splitext(filename)
+ if extension != '.py':
+ continue
+ module_name = '{0}.{1}'.format(package, basename)
+ __import__(module_name, fromlist='*')
+ module = sys.modules[module_name]
+ if not hasattr(module, '__all__'):
+ continue
+ for component in scan_module(module, interface):
+ yield component