Plugins can exist inside your existing packages or in special namespace packages, which exist only to house plugins.
The only requirement is that any package containing plugins be
designated a “namespace package”, which is currently performed
in Python via the
pkgutil.extend_path utility, seen below.
This allows the namespace to be provided in multiple places on
import looks, and all the
contents will be combined.
Use a namespace package
This allows multiple packages installed on your system to share this name, so they may come from different installed projects and all combine to provide a larger set of plugins.
# logfilter/__init__.py from pkgutil import extend_path __path__ = extend_path(__path__, __name__)
# logfilter/hide_extra.py from logfilter import Skip def filter(log_entry): level = log_entry.split(':', 1) if level != 'EXTRA': return log_entry else: raise Skip()
Using the plugin¶
In our log tool, we might load all the modules in the
namespace, and then use them all to process each entry in our logs.
We don’t need to know all the filters ahead of time, and other packages
can be installed on a user’s system providing additional modules
in the namespace, which we never even knew about.
from straight.plugin import load class Skip(Exception): pass plugins = load('logfilter') def filter_entry(log_entry): for plugin in plugins: try: log_entry = plugin.filter(log_entry) except Skip: pass return log_entry
If you are writing plugins inside your own project to use, they’ll be distributed like any other modules in your package. There is no extra work to do here.
However, if you want to release and distribute plugins on their own, you’ll need to tell your setup.py about your namespace package.
setup( # ... namespace_packages = ['logfilter.plugins'] )
This will make sure when your plugins are installed alongside the original project, both are importable, even though they came from their own distributions.
You can read more about this at the Distribute documentation on namespace packages.