Stevedore (Python Plugin Manager)
raw JSON → 5.7.0 verified Tue May 12 auth: no python install: verified
Stevedore is a Python library designed to simplify the management of dynamic plugins for Python applications. It builds on top of `setuptools` entry points, providing a standardized and less repetitive way to discover and load extensions at runtime. The library abstracts away much of the boilerplate associated with `__import__` or `importlib` for plugin systems. [2, 5]
pip install stevedore Common errors
error No entry points found for group 'my_plugin_group' ↓
cause The `entry_points` in the plugin's `setup.py` or `pyproject.toml` do not define any entry points under the specified group name, or the plugin package is not installed in the environment.
fix
Ensure the plugin package's
setup.py (or pyproject.toml) correctly defines entry_points under the specified group and that the plugin package is installed (e.g., pip install -e . for development or pip install my-plugin-package). error ModuleNotFoundError: No module named 'my_plugin_package.plugins' ↓
cause The `entry_points` definition in the plugin's `setup.py` or `pyproject.toml` refers to a module path or class name that does not exist or is misspelled within the plugin package.
fix
Verify that the module path and class name specified in the
entry_points definition (e.g., in setup.py or pyproject.toml) are correct and that the corresponding Python file and class exist within the plugin package. error TypeError: __init__() missing 1 required positional argument: 'config_object' ↓
cause When `ExtensionManager` is initialized with `invoke_on_load=True`, it attempts to instantiate plugin classes, but the provided `invoke_args` or `invoke_kwargs` do not match the plugin's `__init__` method signature.
fix
Pass the required arguments to the plugin's constructor via
invoke_args or invoke_kwargs when initializing ExtensionManager (e.g., manager = ExtensionManager('group', invoke_on_load=True, invoke_kwargs={'config_object': my_config})). Warnings
gotcha Be aware that another tool also named 'Stevedore' exists for Docker image building and container orchestration. Ensure you are using the correct Python plugin management library, often identified by its OpenStack origin. [1, 7, 8, 10, 12] ↓
fix Always import classes from `stevedore.extension`, `stevedore.driver`, etc., and verify documentation from `docs.openstack.org/stevedore` or PyPI.
gotcha Incorrectly defining entry points in `setup.py` or `pyproject.toml`, or referencing non-existent callables for your plugins, can lead to `ImportError` at runtime that is difficult to debug at packaging time. [15] ↓
fix Thoroughly test your plugin packages after installation. Ensure the entry point string ('module.path:callable_name') precisely matches the module and the callable object within it. Use `entry_point_inspector` for debugging.
gotcha While powerful, using a large number of `setuptools` entry points (and thus `stevedore` plugins) can potentially contribute to slower application startup times due to the discovery and loading process. [9] ↓
fix For performance-critical applications with many plugins, consider lazy loading mechanisms or optimizing plugin discovery if startup time becomes an issue. Profile your application to identify bottlenecks.
gotcha Stevedore's namespaces, while resembling Python package paths (e.g., `a.b.c`), do not directly correspond to Python package structures. They are logical identifiers for groups of plugins. [8] ↓
fix Choose descriptive and unique namespaces for your plugin groups. Understand that a plugin in namespace `foo.bar` can reside in any Python package that declares an entry point for that namespace, not necessarily a package named `foo.bar`.
deprecated Support for older Python versions (e.g., Python 3.8 and earlier) has been dropped in recent Stevedore releases. [6] ↓
fix Ensure your project is running on a supported Python version (>= 3.10 as of 5.7.0). Consult the `stevedore` changelog for specific version compatibility details. [2]
breaking The Stevedore library, especially when defining plugins via entry points, fundamentally relies on `setuptools`. If `setuptools` is not installed in the environment, the library (or tools expecting its entry points) may fail with a `ModuleNotFoundError` for `setuptools` itself. ↓
fix Ensure `setuptools` is installed in your Python environment. For example, include it in your `requirements.txt` or `pyproject.toml` dependencies, or install it directly via `pip install setuptools`.
Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.13s 18.2M
3.10 alpine (musl) - - 0.13s 18.2M
3.10 slim (glibc) wheel 1.5s 0.09s 19M
3.10 slim (glibc) - - 0.08s 19M
3.11 alpine (musl) wheel - 0.16s 20.1M
3.11 alpine (musl) - - 0.17s 20.1M
3.11 slim (glibc) wheel 1.6s 0.14s 21M
3.11 slim (glibc) - - 0.13s 21M
3.12 alpine (musl) wheel - 0.18s 12.0M
3.12 alpine (musl) - - 0.16s 12.0M
3.12 slim (glibc) wheel 1.5s 0.16s 12M
3.12 slim (glibc) - - 0.16s 12M
3.13 alpine (musl) wheel - 0.11s 11.7M
3.13 alpine (musl) - - 0.11s 11.6M
3.13 slim (glibc) wheel 1.5s 0.11s 12M
3.13 slim (glibc) - - 0.11s 12M
3.9 alpine (musl) wheel - 0.06s 17.7M
3.9 alpine (musl) - - 0.07s 17.7M
3.9 slim (glibc) wheel 1.8s 0.06s 18M
3.9 slim (glibc) - - 0.06s 18M
Imports
- DriverManager
from stevedore.driver import DriverManager - ExtensionManager
from stevedore.extension import ExtensionManager - NamedExtensionManager
from stevedore.named import NamedExtensionManager - EnabledExtensionManager
from stevedore.enabled import EnabledExtensionManager
Quickstart last tested: 2026-04-24
import os
from setuptools import setup, find_packages
from stevedore import extension
# 1. Define a plugin interface (e.g., in myapp/plugins/base.py)
# In a real scenario, this would be in a separate package.
# For this quickstart, we'll simulate it.
plugin_base_code = '''
import abc
class FormatterBase(abc.ABC):
@abc.abstractmethod
def format(self, data):
"""Format the data and return a string."""
pass
'''
# 2. Implement a concrete plugin (e.g., in myapp_simple_formatter/formatter.py)
# In a real scenario, this would be in a separate package.
plugin_impl_code = '''
from myapp.plugins.base import FormatterBase
class SimpleFormatter(FormatterBase):
def format(self, data):
return f"Simple format: {data['value']}"
'''
# Create dummy files for demonstration
if not os.path.exists('myapp/plugins'):
os.makedirs('myapp/plugins')
with open('myapp/plugins/base.py', 'w') as f:
f.write(plugin_base_code)
if not os.path.exists('myapp_simple_formatter'):
os.makedirs('myapp_simple_formatter')
with open('myapp_simple_formatter/formatter.py', 'w') as f:
f.write(plugin_impl_code)
with open('myapp/__init__.py', 'w') as f: pass
with open('myapp_simple_formatter/__init__.py', 'w') as f: pass
# 3. Define entry points in setup.py (or pyproject.toml)
# For a runnable quickstart, we'll use a dummy setup for the plugin
# and then manually register it to simulate installation.
# In a real project, myapp_simple_formatter would have its own setup.py
# and be installed via pip install -e .
# Simulate plugin registration by creating a pseudo-entry-point
# This is for quickstart demonstration; usually setuptools handles this via installation.
# This specific 'hack' for dynamic registration during runtime is not standard Stevedore usage,
# but it makes the quickstart runnable without a full package installation process.
# We'll use a hack to make the quickstart self-contained and runnable.
# In a real scenario, 'myapp_simple_formatter' would be an installed package
# with its entry point declared in its setup.py (or pyproject.toml).
# To simulate: we directly add the module to sys.modules and define a mock entry_points function.
import sys
sys.path.insert(0, os.path.abspath('.'))
# Temporarily import the base and plugin to make them available
from myapp.plugins.base import FormatterBase
from myapp_simple_formatter.formatter import SimpleFormatter
# Mock the entry point discovery for demonstration
def mock_entry_points(group=None):
if group == 'myapp.formatters':
class MockEntryPoint:
def __init__(self, name, load_callable):
self.name = name
self._load_callable = load_callable
def load(self):
return self._load_callable
return {
'simple': MockEntryPoint('simple', SimpleFormatter)
}
return {}
# Replace the real entry_points discovery for this script's scope
# This is a highly simplified mock for quickstart purposes and not how stevedore usually discovers plugins
# In practice, entry points are discovered via 'importlib.metadata.entry_points()' after package installation.
import stevedore.extension
stevedore.extension.entry_points = mock_entry_points
# 4. Use stevedore in your application to load plugins
def main():
print("Loading formatters...")
mgr = extension.ExtensionManager(
namespace='myapp.formatters',
invoke_on_load=True
)
if not mgr.extensions:
print("No formatters found. Ensure plugin packages are installed and define 'myapp.formatters' entry points.")
return
print(f"Found {len(mgr.extensions)} formatter(s).")
for ext in mgr.extensions:
print(f" - {ext.name}: {ext.obj.format({'value': 123})}")
if __name__ == '__main__':
main()
# Clean up dummy files/dirs
import shutil
shutil.rmtree('myapp')
shutil.rmtree('myapp_simple_formatter')