Difference Between Poetry Plugins and Entry Points#
Overview#
If you've read that "Poetry supports arbitrary plugins which work similarly to setuptools entry points" and found it confusing, you're not alone. The term "plugin" in Poetry is overloaded with two distinct meanings:
[tool.poetry.plugins]section - Declares standard Python entry points in your package (the same as setuptools entry points)- Poetry's plugin system - Extends Poetry itself with new commands or functionality
The key insight: Poetry plugins (meaning #2) use entry points (meaning #1) to register themselves. The [tool.poetry.plugins] section is not exclusively for Poetry plugins—it's for declaring any entry points your package exposes.
Key Distinction#
Entry Points via [tool.poetry.plugins]#
When you use [tool.poetry.plugins], you're declaring standard Python entry points:
- This section declares setuptools-style entry points
- Entry points are discoverable by any tool using
importlib.metadata - They follow the PEP 621 standard
- Use this when you want OTHER applications or tools to discover your package's functionality
Poetry's Plugin System#
Poetry also has its own plugin system for extending Poetry itself:
- Poetry plugins extend Poetry with new commands or functionality
- They register themselves using entry points in the
poetry.pluginorpoetry.application.plugingroups - Use this when you want to add functionality TO Poetry (not your own application)
How They Relate#
Poetry plugins ARE registered using entry points, but the confusion arises because:
- The
[tool.poetry.plugins]section is for YOUR package to expose entry points - Poetry's own plugins use that same mechanism to register with Poetry
The Conversion Process#
During package building, Poetry reads plugin declarations and writes them as standard entry points:
- Poetry-core's Factory reads both
[project.entry-points]and[tool.poetry.plugins]sections - They are stored in the package's
entry_pointsproperty - During wheel building, they're written to
entry_points.txtin the wheel's.dist-infodirectory
Important: There is no actual "conversion" - Poetry simply passes through the plugin definitions in the standard setuptools format.
Configuration Examples#
Declaring Entry Points in Your Package#
Use entry points when you want other applications or tools to discover your package's functionality. This is useful for plugin systems, command-line tools, and framework extensions.
# Recommended: Using project.entry-points (PEP 621)
[project.entry-points."my_app.plugins"]
my_plugin = "my_package.module:PluginClass"
# Deprecated but still supported: Using tool.poetry.plugins
[tool.poetry.plugins."my_app.plugins"]
my_plugin = "my_package.module:PluginClass"
The format is: entry_point_name = "module.path:object"
"my_app.plugins"is the entry point group (you define this for your plugin system)my_pluginis the name of this specific entry point"my_package.module:PluginClass"points to the Python object to load
Console Scripts Shortcut#
[tool.poetry.scripts] is a shortcut for [tool.poetry.plugins."console_scripts"]. Both create command-line executables that are installed when your package is installed.
# These are equivalent:
[tool.poetry.scripts]
mycommand = "mypackage.mymodule:my_function"
[tool.poetry.plugins."console_scripts"]
mycommand = "mypackage.mymodule:my_function"
When users install your package, they can run mycommand from the command line, which will execute my_function() from mypackage.mymodule.
Creating a Poetry Plugin#
To extend Poetry itself (not your application), declare an entry point in the poetry.application.plugin or poetry.plugin group:
[project.entry-points."poetry.application.plugin"]
my-poetry-command = "my_poetry_plugin:MyApplicationPlugin"
This registers a plugin that Poetry will load when it starts. See the Poetry plugins documentation for details on implementing plugin classes.
Using Entry Points to Load Plugins in Your Application#
Once you've declared entry points in your package, other applications can discover and load them using Python's standard importlib.metadata module.
Basic Example#
from importlib.metadata import entry_points
# Discover all entry points in the "main_app.plugins" group
for entry_point in entry_points(group="main_app.plugins"):
if entry_point.name in ["plugin_name"]:
# Load the entry point (imports and returns the object)
entry_point.load()
Practical Example: Registry Pattern with Auto-Discovery#
A common use case is the Registry design pattern, where plugins need to be imported so their decorators can register classes. Here's a complete example:
Plugin package's pyproject.toml:
[tool.poetry.plugins."main_app.plugins"]
my_plugin = "my_plugin_package.plugin_module"
Main application's __init__.py:
from importlib.metadata import entry_points
# Auto-discover and load all registered plugins
for entry_point in entry_points(group="main_app.plugins"):
# Loading the entry point imports the module,
# which triggers decorator-based registration
entry_point.load()
Plugin module (my_plugin_package/plugin_module.py):
from main_app.registry import register
@register
class MyPluginClass:
"""This class is automatically registered when the module is imported"""
pass
This pattern allows plugins to be automatically discovered and loaded at application startup without hardcoding their imports.
Summary Table#
| Feature | [tool.poetry.plugins] | Poetry's Plugin System |
|---|---|---|
| Purpose | Declare entry points in YOUR package | Extend Poetry itself |
| Discoverable by | Any tool using importlib.metadata | Poetry |
| Entry point group | Any arbitrary group | poetry.plugin or poetry.application.plugin |
| Syntax | [tool.poetry.plugins."group"] or [project.entry-points."group"] | Same, but specific groups |
Additional Notes#
- The
tool.poetry.pluginssyntax is deprecated in favor ofproject.entry-points - Entry points are fully compatible with setuptools
- Run
poetry installafter adding or modifying entry points to make them available