Plugin Handling

Plugin Management

Flake8 3.0 added support for two other plugins besides those which define new checks. It now supports:

  • extra checks
  • alternative report formatters
  • listeners to auto-correct violations of checks

To facilitate this, Flake8 needed a more mature way of managing plugins. Thus, we developed the PluginManager which accepts a namespace and will load the plugins for that namespace. A PluginManager creates and manages many Plugin instances.

A Plugin lazily loads the underlying entry-point provided by setuptools. The entry-point will be loaded either by calling 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 PluginManager provides is map(). This will accept a function (or other callable) and call it with each plugin as the first parameter.

We build atop the PluginManager with the PluginTypeManager. It is expected that users of the 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 PluginManager‘s map method.

Finally, we create three classes of plugins:

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.

Notifying Listener Plugins

One of the interesting challenges with allowing plugins to be notified each time an error or warning is emitted by a checker is finding listeners quickly and efficiently. It makes sense to allow a listener to listen for a certain class of warnings or just a specific warning. Hence, we need to allow all plugins that listen to a specific warning or class to be notified. For example, someone might register a listener for E1 and another for E111 if E111 is triggered by the code, both listeners should be notified. If E112 is returned, then only E1 (and any other listeners) would be notified.

To implement this goal, we needed an object to store listeners in that would allow for efficient look up - a Trie (or Prefix Tree). Given that none of the existing packages on PyPI allowed for storing data on each node of the trie, it was left up to write our own as Trie. On top of that we layer our Notifier class.

Now when Flake8 receives an error or warning, we can easily call the notify() method and let plugins act on that knowledge.

Default Plugins

Finally, Flake8 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.

Flake8 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.

API Documentation

class flake8.plugins.manager.PluginManager(namespace, verify_requirements=False)

Find and manage plugins consistently.

__init__(namespace, verify_requirements=False)

Initialize the manager.

Parameters:
  • namespace (str) – Namespace of the plugins to manage, e.g., ‘flake8.extension’.
  • verify_requirements (bool) – Whether or not to make setuptools verify that the requirements for the plugin are satisfied.
map(func, *args, **kwargs)

Call func with the plugin and *args and **kwargs after.

This yields the return value from func for each plugin.

Parameters:
  • func (collections.Callable) –

    Function to call with each plugin. Signature should at least be:

    def myfunc(plugin):
         pass
    

    Any extra positional or keyword arguments specified with map will be passed along to this function after the plugin. The plugin passed is a Plugin.

  • args – Positional arguments to pass to func after each plugin.
  • kwargs – Keyword arguments to pass to func after each plugin.
versions()

Generate the versions of plugins.

Returns:Tuples of the plugin_name and version
Return type:tuple
class flake8.plugins.manager.Plugin(name, entry_point)

Wrap an EntryPoint from setuptools and other logic.

__init__(name, entry_point)

“Initialize our Plugin.

Parameters:
  • name (str) – Name of the entry-point as it was registered with setuptools.
  • entry_point (setuptools.EntryPoint) – EntryPoint returned by setuptools.
disable(optmanager)

Add the plugin name to the default ignore list.

enable(optmanager)

Remove plugin name from the default ignore list.

execute(*args, **kwargs)

Call the plugin with *args and **kwargs.

group()

Find and parse the group the plugin is in.

is_in_a_group()

Determine if this plugin is in a group.

Returns:True if the plugin is in a group, otherwise False.
Return type:bool
load_plugin(verify_requirements=False)

Retrieve the plugin for this entry-point.

This loads the plugin, stores it on the instance and then returns it. It does not reload it after the first time, it merely returns the cached plugin.

Parameters:verify_requirements (bool) – Whether or not to make setuptools verify that the requirements for the plugin are satisfied.
Returns:Nothing
off_by_default

Return whether the plugin is ignored by default.

parameter_names

List of argument names that need to be passed to the plugin.

parameters

List of arguments that need to be passed to the plugin.

plugin

The loaded (and cached) plugin associated with the entry-point.

This property implicitly loads the plugin and then caches it.

plugin_name

Return the name of the plugin.

provide_options(optmanager, options, extra_args)

Pass the parsed options and extra arguments to the plugin.

register_options(optmanager)

Register the plugin’s command-line options on the OptionManager.

Parameters:optmanager (flake8.options.manager.OptionManager) – Instantiated OptionManager to register options on.
Returns:Nothing
version

Return the version of the plugin.

class flake8.plugins.manager.PluginTypeManager

Parent class for most of the specific plugin types.

get(name, default=None)

Retrieve the plugin referred to by name or return the default.

Parameters:
  • name (str) – Name of the plugin to retrieve.
  • default – Default value to return.
Returns:

Plugin object referred to by name, if it exists.

Return type:

Plugin

load_plugins()

Load all plugins of this type that are managed by this manager.

names

Proxy attribute to underlying manager.

plugins

Proxy attribute to underlying manager.

provide_options(optmanager, options, extra_args)

Provide parsed options and extra arguments to the plugins.

register_options(optmanager)

Register all of the checkers’ options to the OptionManager.

register_plugin_versions(optmanager)

Register the plugins and their versions with the OptionManager.

class flake8.plugins.manager.Checkers

All of the checkers registered through entry-ponits.

ast_plugins

List of plugins that expect the AST tree.

checks_expecting(argument_name)

Retrieve checks that expect an argument with the specified name.

Find all checker plugins that are expecting a specific argument.

logical_line_plugins

List of plugins that expect the logical lines.

physical_line_plugins

List of plugins that expect the physical lines.

register_options(optmanager)

Register all of the checkers’ options to the OptionManager.

This also ensures that plugins that are not part of a group and are enabled by default are enabled on the option manager.

class flake8.plugins.manager.Listeners

All of the listeners registered through entry-points.

build_notifier()

Build a Notifier for our Listeners.

Returns:Object to notify our listeners of certain error codes and warnings.
Return type:Notifier
class flake8.plugins.manager.ReportFormatters

All of the report formatters registered through entry-points.

class flake8.plugins.notifier.Notifier

Object that tracks and notifies listener objects.

class flake8.plugins._trie.Trie

The object that manages the trie nodes.