# Simple Python Plugin Manager __Note:__ In order for this example to work, you need place `__init__.py` into `plugins/example/` where `plugins.py`, `example.py` and the `plugins` directory are in the same directory. __Note:__ This implementation requires Python 2.7 or higher. ## Expected Output ``` $ python plugins.py INFO:root:plugin "test" loaded hello bob {'name': 'bob johnson'} INFO:root:plugin "test" unloaded ``` ## How To Use Using the `PluginManager` class is easy: ```python import plugins # create a plugin manager plugin_manager = plugins.PluginManager('./plugins') ``` In the above example, we're saying that plugin modules are stored in the `./plugins` directory. Now, assume that you've placed the example `__init__.py` file in `./plugins/example/__init__.py`. Then, in order to load the plugin, you use the plugin manager's `load_plugin` function: ```python plugin_manager.load_plugin('example') ``` Similarly, you can use the `unload_plugin` to unload the plugin if you so desire. In the example `__init__.py` file, we're expecting to be able to extend the main application at two different hooks: `action_hello` and `filter_hello` (more on hooks below). This means that somewhere in your application, you need to use the plugin manager's `execute_action_hook` and `execute_filter_hook` functions: ```python # executes action_hello(hook_params) in ./plugins/*/__init__.py (if loaded) plugin_manager.execute_action_hook('hello', {'name': 'bob'}) # executes filter_hello(hook_params) in ./plugins/*/__init__.py (if loaded) result = plugin_manager.execute_filter_hook('hello', {'name': 'bob'}) print result ``` ## Hooks Hooks are basically places in _your_ application where you allow plugins to extend your application. This plugin manager supports two different kinds of hooks, action hooks and filter hooks. These hooks should be documented for your plugin developers. ### Action Hooks Action hooks can be thought of as places in your code where you would like plugins to be able to execute arbitrary code (perform actions), possibly using a `dict` that your application provides to them. In the example `__init__.py` file, an action hook called `hello` is registered by defining an `action_hello` function. The example application passed the following dictionary to all plugins that register the hook: `{'name': 'bob'}`. __Note:__ In order to ensure that actions occur in the order you need them to, the loaded plugins are executed in the same order in which they are loaded. ### Filter Hooks Filter hooks are places in you code where you would llike plugins to be able to take a `dict`, modifiy it, and return it. An interesting use case for this might be a plugin that replaces bbcode or smilies with HTML image tags. In the example `__init__.py` file, a filter hook called `hello` is registered by defining a `filter_hello` function. Note, the `PluginManager` class checks that the dictionary returned by the plugins contains the same set of keys as when the `execute_filter_hook` function was called. For example, since the dictionary passed to the `execute_filter_hook` function in the example application contains a single key called `name`, then an exception would be raised if the `filter_hello` function in the example `__init__.py` file did not return a dictionary that key in it. __Note:__ In order to ensure that filtering of the dictionary occurs in the order you need it to, the loaded plugins are executed in the same order in which they are loaded. ## Main Module By default, this implementation expects that the main module for each plugin is `__init__`. You can change this by using the optional `main_module` parameter in the `PluginManager` constructor. For example, if you wanted `plugin.py` in each plugin folder to be a plugin's main module, then you could do the following: ```python plugin_manager = plugins.PluginManager('./plugins', 'plugin') ``` ## Logging By defauly, this implementation uses it's own logger from `logging`. If you would like for the `PluginManager` class to you use your own logger, you can specify one using the optional `log` parameter in the `PluginManager` constructor.