3.0 added support for other plugins besides those which define new checks. It now supports:
- extra checks
- alternative report formatters
To facilitate this, needed a more mature way of managing plugins. Thus, we developed the ~flake8.plugins.manager.PluginManager
which accepts a namespace and will load the plugins for that namespace. A ~flake8.plugins.manager.PluginManager
creates and manages many ~flake8.plugins.manager.Plugin
instances.
A ~flake8.plugins.manager.Plugin
lazily loads the underlying entry-point provided by setuptools. The entry-point will be loaded either by calling ~flake8.plugins.manager.Plugin.load_plugin
or accessing the plugin
attribute. We also use this abstraction to retrieve options that the plugin wishes to register and parse.
The only public method the ~flake8.plugins.manager.PluginManager
provides is ~flake8.plugins.manager.PluginManager.map
. This will accept a function (or other callable) and call it with each plugin as the first parameter.
We build atop the ~flake8.plugins.manager.PluginManager
with the ~flake8.plugins.manager.PluginTypeManager
. It is expected that users of the ~flake8.plugins.manager.PluginTypeManager
will subclass it and specify the namespace
, e.g.,
class ExamplePluginType(flake8.plugin.manager.PluginTypeManager):
namespace = 'example-plugins'
This provides a few extra methods via the ~flake8.plugins.manager.PluginManager
's map
method.
Finally, we create two classes of plugins:
~flake8.plugins.manager.Checkers
~flake8.plugins.manager.ReportFormatters
These are used to interact with each of the types of plugins individually.
Note
Our inspiration for our plugin handling comes from the author's extensive experience with stevedore
.
Finally, has always provided its own plugin shim for Pyflakes. As part of that we carry our own shim in-tree and now store that in flake8.plugins.pyflakes
.
also registers plugins for pep8. Each check in pep8 requires different parameters and it cannot easily be shimmed together like Pyflakes was. As such, plugins have a concept of a "group". If you look at our setup.py
you will see that we register pep8 checks roughly like so:
pep8.<check-name> = pep8:<check-name>
We do this to identify that <check-name>>
is part of a group. This also enables us to special-case how we handle reporting those checks. Instead of reporting each check in the --version
output, we report pep8
and check pep8
the module for a __version__
attribute. We only report it once to avoid confusing users.
flake8.plugins.manager.PluginManager
flake8.plugins.manager.Plugin
flake8.plugins.manager.PluginTypeManager
flake8.plugins.manager.Checkers
flake8.plugins.manager.ReportFormatters