diff --git a/.pylintrc b/.pylintrc index f005265..1290b8b 100644 --- a/.pylintrc +++ b/.pylintrc @@ -13,6 +13,7 @@ enable=anomalous-backslash-in-string, cyclic-import, dangerous-default-value, disallowed-name, + duplicate-code, empty-docstring, inconsistent-return-statements, invalid-name, diff --git a/src/wuttjamaican/app.py b/src/wuttjamaican/app.py index 8b5f671..4e68a87 100644 --- a/src/wuttjamaican/app.py +++ b/src/wuttjamaican/app.py @@ -1123,6 +1123,7 @@ class GenericHandler: def __init__(self, config): self.config = config self.app = self.config.get_app() + self.modules = {} @property def appname(self): @@ -1139,3 +1140,35 @@ class GenericHandler: Returns the class :term:`spec` string for the handler. """ return f'{cls.__module__}:{cls.__name__}' + + def get_provider_modules(self, module_type): + """ + Returns a list of all available modules of the given type. + + Not all handlers would need such a thing, but notable ones + which do are the :term:`email handler` and :term:`report + handler`. Both can obtain classes (emails or reports) from + arbitrary modules, and this method is used to locate them. + + This will discover all modules exposed by the app + :term:`providers `, which expose an attribute with + name like ``f"{module_type}_modules"``. + + :param module_type: Unique name referring to a particular + "type" of modules to locate, e.g. ``'email'``. + + :returns: List of module objects. + """ + if module_type not in self.modules: + self.modules[module_type] = [] + for provider in self.app.providers.values(): + name = f'{module_type}_modules' + if hasattr(provider, name): + modules = getattr(provider, name) + if modules: + if isinstance(modules, str): + modules = [modules] + for modpath in modules: + module = importlib.import_module(modpath) + self.modules[module_type].append(module) + return self.modules[module_type] diff --git a/src/wuttjamaican/email.py b/src/wuttjamaican/email.py index 227a38d..43bc808 100644 --- a/src/wuttjamaican/email.py +++ b/src/wuttjamaican/email.py @@ -24,7 +24,6 @@ Email Handler """ -import importlib import logging import smtplib from email.mime.multipart import MIMEMultipart @@ -305,20 +304,12 @@ class EmailHandler(GenericHandler): This will discover all email modules exposed by the :term:`app`, and/or its :term:`providers `. - """ - if not hasattr(self, '_email_modules'): - self._email_modules = [] - for provider in self.app.providers.values(): - if hasattr(provider, 'email_modules'): - modules = provider.email_modules - if modules: - if isinstance(modules, str): - modules = [modules] - for module in modules: - module = importlib.import_module(module) - self._email_modules.append(module) - return self._email_modules + Calls + :meth:`~wuttjamaican.app.GenericHandler.get_provider_modules()` + under the hood, for ``email`` module type. + """ + return self.get_provider_modules('email') def get_email_settings(self): """ diff --git a/src/wuttjamaican/reports.py b/src/wuttjamaican/reports.py index 7a55a19..0f84f87 100644 --- a/src/wuttjamaican/reports.py +++ b/src/wuttjamaican/reports.py @@ -24,8 +24,6 @@ Report Utilities """ -import importlib - from wuttjamaican.app import GenericHandler @@ -143,20 +141,12 @@ class ReportHandler(GenericHandler): This will discover all report modules exposed by the :term:`app`, and/or its :term:`providers `. - """ - if not hasattr(self, '_report_modules'): - self._report_modules = [] - for provider in self.app.providers.values(): - if hasattr(provider, 'report_modules'): - modules = provider.report_modules - if modules: - if isinstance(modules, str): - modules = [modules] - for module in modules: - module = importlib.import_module(module) - self._report_modules.append(module) - return self._report_modules + Calls + :meth:`~wuttjamaican.app.GenericHandler.get_provider_modules()` + under the hood, for ``report`` module type. + """ + return self.get_provider_modules('report') def get_reports(self): """ diff --git a/tests/test_app.py b/tests/test_app.py index e05334d..e75b527 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -761,6 +761,9 @@ class TestGenericHandler(ConfigTestCase): kw.setdefault('appname', 'wuttatest') return super().make_config(**kw) + def make_handler(self, **kwargs): + return mod.GenericHandler(self.config, **kwargs) + def test_constructor(self): handler = mod.GenericHandler(self.config) self.assertIs(handler.config, self.config) @@ -769,3 +772,30 @@ class TestGenericHandler(ConfigTestCase): def test_get_spec(self): self.assertEqual(mod.GenericHandler.get_spec(), 'wuttjamaican.app:GenericHandler') + + def test_get_provider_modules(self): + + # no providers, no email modules + with patch.object(self.app, 'providers', new={}): + handler = self.make_handler() + self.assertEqual(handler.get_provider_modules('email'), []) + + # provider may specify modules as list + providers = { + 'wuttatest': MagicMock(email_modules=['wuttjamaican.app']), + } + with patch.object(self.app, 'providers', new=providers): + handler = self.make_handler() + modules = handler.get_provider_modules('email') + self.assertEqual(len(modules), 1) + self.assertIs(modules[0], mod) + + # provider may specify modules as string + providers = { + 'wuttatest': MagicMock(email_modules='wuttjamaican.app'), + } + with patch.object(self.app, 'providers', new=providers): + handler = self.make_handler() + modules = handler.get_provider_modules('email') + self.assertEqual(len(modules), 1) + self.assertIs(modules[0], mod)