{"library":"stevedore","title":"Stevedore (Python Plugin Manager)","type":"library","description":"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]","language":"python","status":"active","last_verified":"Tue May 19","install":{"commands":["pip install stevedore"],"cli":null},"imports":["from stevedore.driver import DriverManager","from stevedore.extension import ExtensionManager","from stevedore.named import NamedExtensionManager","from stevedore.enabled import EnabledExtensionManager"],"auth":{"required":false,"env_vars":[]},"links":{"homepage":"https://docs.openstack.org/stevedore","github":null,"docs":null,"changelog":null,"pypi":"https://pypi.org/project/stevedore/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null},"quickstart":{"code":"import os\nfrom setuptools import setup, find_packages\nfrom stevedore import extension\n\n# 1. Define a plugin interface (e.g., in myapp/plugins/base.py)\n# In a real scenario, this would be in a separate package.\n# For this quickstart, we'll simulate it.\nplugin_base_code = '''\nimport abc\n\nclass FormatterBase(abc.ABC):\n    @abc.abstractmethod\n    def format(self, data):\n        \"\"\"Format the data and return a string.\"\"\"\n        pass\n'''\n\n# 2. Implement a concrete plugin (e.g., in myapp_simple_formatter/formatter.py)\n# In a real scenario, this would be in a separate package.\nplugin_impl_code = '''\nfrom myapp.plugins.base import FormatterBase\n\nclass SimpleFormatter(FormatterBase):\n    def format(self, data):\n        return f\"Simple format: {data['value']}\"\n'''\n\n# Create dummy files for demonstration\nif not os.path.exists('myapp/plugins'):\n    os.makedirs('myapp/plugins')\nwith open('myapp/plugins/base.py', 'w') as f:\n    f.write(plugin_base_code)\nif not os.path.exists('myapp_simple_formatter'):\n    os.makedirs('myapp_simple_formatter')\nwith open('myapp_simple_formatter/formatter.py', 'w') as f:\n    f.write(plugin_impl_code)\nwith open('myapp/__init__.py', 'w') as f: pass\nwith open('myapp_simple_formatter/__init__.py', 'w') as f: pass\n\n# 3. Define entry points in setup.py (or pyproject.toml)\n# For a runnable quickstart, we'll use a dummy setup for the plugin\n# and then manually register it to simulate installation.\n# In a real project, myapp_simple_formatter would have its own setup.py\n# and be installed via pip install -e .\n\n# Simulate plugin registration by creating a pseudo-entry-point\n# This is for quickstart demonstration; usually setuptools handles this via installation.\n# This specific 'hack' for dynamic registration during runtime is not standard Stevedore usage,\n# but it makes the quickstart runnable without a full package installation process.\n\n# We'll use a hack to make the quickstart self-contained and runnable.\n# In a real scenario, 'myapp_simple_formatter' would be an installed package\n# with its entry point declared in its setup.py (or pyproject.toml).\n# To simulate: we directly add the module to sys.modules and define a mock entry_points function.\n\nimport sys\nsys.path.insert(0, os.path.abspath('.'))\n\n# Temporarily import the base and plugin to make them available\nfrom myapp.plugins.base import FormatterBase\nfrom myapp_simple_formatter.formatter import SimpleFormatter\n\n# Mock the entry point discovery for demonstration\ndef mock_entry_points(group=None):\n    if group == 'myapp.formatters':\n        class MockEntryPoint:\n            def __init__(self, name, load_callable):\n                self.name = name\n                self._load_callable = load_callable\n            def load(self):\n                return self._load_callable\n        return {\n            'simple': MockEntryPoint('simple', SimpleFormatter)\n        }\n    return {}\n\n# Replace the real entry_points discovery for this script's scope\n# This is a highly simplified mock for quickstart purposes and not how stevedore usually discovers plugins\n# In practice, entry points are discovered via 'importlib.metadata.entry_points()' after package installation.\nimport stevedore.extension\nstevedore.extension.entry_points = mock_entry_points\n\n\n# 4. Use stevedore in your application to load plugins\ndef main():\n    print(\"Loading formatters...\")\n    mgr = extension.ExtensionManager(\n        namespace='myapp.formatters',\n        invoke_on_load=True\n    )\n\n    if not mgr.extensions:\n        print(\"No formatters found. Ensure plugin packages are installed and define 'myapp.formatters' entry points.\")\n        return\n\n    print(f\"Found {len(mgr.extensions)} formatter(s).\")\n    for ext in mgr.extensions:\n        print(f\"  - {ext.name}: {ext.obj.format({'value': 123})}\")\n\nif __name__ == '__main__':\n    main()\n\n# Clean up dummy files/dirs\nimport shutil\nshutil.rmtree('myapp')\nshutil.rmtree('myapp_simple_formatter')","lang":"python","description":"This quickstart demonstrates how to define a plugin interface and a concrete plugin, then use `stevedore.ExtensionManager` to discover and load it. It simulates `setuptools` entry point registration for a self-contained, runnable example. In a real application, plugins would be installed as separate packages declaring their entry points in `setup.py` or `pyproject.toml`. [1, 3, 5]","tag":null,"tag_description":null,"last_tested":"2026-04-24","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]},"compatibility":{"tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","last_tested":"2026-05-19","installed_version":"5.5.0","pypi_latest":"5.8.0","is_stale":true,"summary":{"python_range":"3.10–3.9","success_rate":100,"avg_install_s":1.5,"avg_import_s":0.12,"wheel_type":"wheel"},"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.13,"mem_mb":4,"disk_size":"18.2M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4,"disk_size":"18.2M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.5,"import_time_s":0.09,"mem_mb":4,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":4,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.15,"mem_mb":4.7,"disk_size":"20.1M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.17,"mem_mb":4.7,"disk_size":"20.1M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.14,"mem_mb":4.7,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.13,"mem_mb":4.7,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.17,"mem_mb":5.3,"disk_size":"12.0M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.16,"mem_mb":5.3,"disk_size":"12.0M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.4,"import_time_s":0.16,"mem_mb":5.3,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.16,"mem_mb":5.3,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.11,"mem_mb":4.3,"disk_size":"11.7M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.3,"disk_size":"11.6M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.4,"import_time_s":0.11,"mem_mb":4.3,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":4.3,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.06,"mem_mb":2.8,"disk_size":"17.7M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.8,"disk_size":"17.7M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.8,"import_time_s":0.06,"mem_mb":2.8,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"stevedore","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":2.8,"disk_size":"18M"}]}}