Plugins through Entry Points

This approach is based on Advertising Behavior from setuptools. A good example of this plug-in behavior can be seen in pytest plugins, where pytest is a test framework that allows other libraries to extend or modify its functionality through the pytest11 entry point.

Understanding the API

Let’s look at an example of listing the console script entry points for all installed Python packages.

"""List console_scripts entry points for all installed packages"""

from importlib import metadata
for ep in metadata.entry_points()['console_scripts']:
    print(f"name='{ep.name}', value='{ep.value}'")

Functionality is provided by the entry_points() function from importlib.metadata library introduced in Python 3.8.

The entry_points() function returns a collection of entry points. Entry points are represented by EntryPoint instances; each EntryPoint has a .name, .group, and .value attributes and a .load() method to resolve the value. There are also .module, .attr, and .extras attributes for getting the components of the .value attribute.

For earlier versions of Python, you could use the pkg_resources package:

"""List console_scripts entry points for all installed packages using pkg_resources"""
import pkg_resources

for ep in pkg_resources.iter_entry_points(group='console_scripts'):
    print(f"name='{ep.name}', module='{ep.module_name}', attr='{ep.attrs}'")

Plugin Example

In this example we will create a script which can be extended via pygems.demoplugin plugins.

The plugin should register entry points in the pygems.demoplugin group:

# setup.cfg

[options.entry_points]
pygems.demoplugin =
    hello-world = pygems.demo.helloworld:hi

Our sample plugin is doing simple print of the “Hi. It is me!” message to the console:

def hi():
    print("Hi. It is me!")

The application or script that needs to use the plugin filters the entry points by group, loads the plugins and executes them.

import pkg_resources

for ep in pkg_resources.iter_entry_points(group='pygems.demoplugin'):
    plugin = ep.load()
    plugin()

Conclusion

Package entry points give us a mechanism for implementing plugin architecture using loosely coupled plugins and consumers.

On the cons side the architecture depends on package entry points advertised by setuptools. If the feature is dropped from Python, plugins will stop working.