From 0332d0ca5566102b4eba6f04a660ed3f0b7e62bb Mon Sep 17 00:00:00 2001 From: Max Goodman Date: Tue, 7 Feb 2012 12:26:30 -0800 Subject: [PATCH] Fix import loop and move plugins collection into its own class. Loading plugin controller modules at the bottom of controllers/__init__.py led to a circular dependency. Registering controllers via decorator allows controllers/__init__.py to load completely before plugin controllers are loaded. --- r2/r2/config/environment.py | 4 +-- r2/r2/config/middleware.py | 3 ++- r2/r2/config/routing.py | 2 +- r2/r2/controllers/__init__.py | 7 +++--- r2/r2/lib/plugin.py | 47 ++++++++++++++++++++++++++--------- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/r2/r2/config/environment.py b/r2/r2/config/environment.py index 073dc3593..749d26b5d 100644 --- a/r2/r2/config/environment.py +++ b/r2/r2/config/environment.py @@ -33,7 +33,7 @@ from r2.config import routing import r2.lib.app_globals as app_globals from r2.lib import rpc import r2.lib.helpers -from r2.lib.plugin import load_plugins +from r2.lib.plugin import PluginLoader import r2.config as reddit_config from r2.templates import tmpl_dirs @@ -58,7 +58,7 @@ def load_environment(global_conf={}, app_conf={}, setup_globals=True): config['pylons.h'] = r2.lib.helpers - config['r2.plugins'] = load_plugins(getattr(g, 'plugins', [])) + config['r2.plugins'] = PluginLoader().load_plugins(getattr(g, 'plugins', [])) config['routes.map'] = routing.make_map() #override the default response options diff --git a/r2/r2/config/middleware.py b/r2/r2/config/middleware.py index b5e9e48b1..437664dcc 100644 --- a/r2/r2/config/middleware.py +++ b/r2/r2/config/middleware.py @@ -515,6 +515,7 @@ class RedditApp(PylonsBaseWSGIApp): class_name = controller.capitalize() + 'Controller' __import__(self.package_name + '.controllers') + config['r2.plugins'].load_controllers() mycontroller = getattr(sys.modules[full_module_name], class_name) self.controller_classes[controller] = mycontroller return mycontroller @@ -576,7 +577,7 @@ def make_app(global_conf, full_stack=True, **app_conf): static_cascade = [static_app, javascripts_app, app] if config['r2.plugins']: plugin_static_apps = Cascade([StaticURLParser(plugin.static_dir) - for plugin in config['r2.plugins'].itervalues()]) + for plugin in config['r2.plugins']]) static_cascade.insert(0, plugin_static_apps) app = Cascade(static_cascade) diff --git a/r2/r2/config/routing.py b/r2/r2/config/routing.py index 36f5be2ca..8785a11c0 100644 --- a/r2/r2/config/routing.py +++ b/r2/r2/config/routing.py @@ -31,7 +31,7 @@ def make_map(): map = Mapper() mc = map.connect - for plugin in config['r2.plugins'].itervalues(): + for plugin in config['r2.plugins']: plugin.add_routes(mc) admin_routes.add(mc) diff --git a/r2/r2/controllers/__init__.py b/r2/r2/controllers/__init__.py index 641256619..68a93660b 100644 --- a/r2/r2/controllers/__init__.py +++ b/r2/r2/controllers/__init__.py @@ -67,6 +67,7 @@ from admin import AdminController from redirect import RedirectController from ipn import IpnController -from pylons import config -for plugin in config['r2.plugins'].itervalues(): - locals().update(plugin.load_controllers()) +def add_controller(controller): + assert controller.__name__ not in globals() + globals()[controller.__name__] = controller + return controller diff --git a/r2/r2/lib/plugin.py b/r2/r2/lib/plugin.py index 4de55cdc1..706caaa72 100644 --- a/r2/r2/lib/plugin.py +++ b/r2/r2/lib/plugin.py @@ -22,16 +22,39 @@ class Plugin(object): def add_routes(self, mc): pass + def load_controllers(self): + pass -def load_plugins(plugin_names): - plugins = {} - for name in plugin_names: - try: - entry_point = pkg_resources.iter_entry_points('r2.plugin', name).next() - except StopIteration: - config['pylons.g'].log.warning('Unable to locate plugin "%s". Skipping.' % name) - continue - plugin_cls = entry_point.load() - plugin = plugins[name] = plugin_cls() - config['pylons.paths']['templates'].extend(plugin.template_dirs) - return plugins + +class PluginLoader(object): + def __init__(self): + self.plugins = {} + self.controllers_loaded = False + + def __len__(self): + return len(self.plugins) + + def __iter__(self): + return self.plugins.itervalues() + + def __getitem__(self, key): + return self.plugins[key] + + def load_plugins(self, plugin_names): + for name in plugin_names: + try: + entry_point = pkg_resources.iter_entry_points('r2.plugin', name).next() + except StopIteration: + config['pylons.g'].log.warning('Unable to locate plugin "%s". Skipping.' % name) + continue + plugin_cls = entry_point.load() + plugin = self.plugins[name] = plugin_cls() + config['pylons.paths']['templates'].extend(plugin.template_dirs) + return self + + def load_controllers(self): + if self.controllers_loaded: + return + for plugin in self: + plugin.load_controllers() + self.controllers_loaded = True