{"id":6410,"library":"pluginlib","title":"Pluginlib","description":"Pluginlib is a framework for creating, managing, and importing plugins within Python applications. It provides utilities for dynamically discovering and loading classes that inherit from a specified base plugin class, often found via filesystem paths or entry points. The current version is 0.10.0, with releases occurring periodically to add features, improve compatibility, and address issues.","status":"active","version":"0.10.0","language":"en","source_language":"en","source_url":"https://github.com/Rockhopper-Technologies/pluginlib","tags":["plugin","extension","loader","dynamic loading","framework"],"install":[{"cmd":"pip install pluginlib","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Used for robust version parsing (introduced in 0.10.0).","package":"packaging"},{"reason":"Backport for importlib.metadata functionality on Python versions < 3.10, used for querying entrypoints.","package":"importlib-metadata","optional":true}],"imports":[{"symbol":"Plugin","correct":"from pluginlib import Plugin"},{"symbol":"PluginLoader","correct":"from pluginlib import PluginLoader"}],"quickstart":{"code":"import os\nimport tempfile\nimport shutil\nfrom pluginlib import Plugin, PluginLoader\n\n# --- Setup: Create a temporary directory and a dummy plugin file ---\n# This simulates having a 'plugins' directory with 'my_plugin.py'\ntemp_dir = tempfile.TemporaryDirectory()\nplugin_root_dir = temp_dir.name\nplugin_dir_path = os.path.join(plugin_root_dir, \"plugins\")\nos.makedirs(plugin_dir_path, exist_ok=True)\n\nplugin_file_path = os.path.join(plugin_dir_path, \"my_plugin.py\")\nwith open(plugin_file_path, \"w\") as f:\n    f.write(\"\"\"\nfrom pluginlib import Plugin\n\nclass MyPlugin(Plugin):\n    version = \"1.0.0\"\n    def execute(self) -> str:\n        return \"Hello from MyPlugin!\"\n\"\"\")\n# --- End Setup ---\n\ntry:\n    # Initialize the PluginLoader to search in our temporary 'plugins' directory\n    # We specify the exact plugin module name and its base class\n    with PluginLoader(\n        [plugin_root_dir], # Search path includes the root of our plugins dir\n        plugin_name=\"my_plugin\", # The name of the module (my_plugin.py)\n        plugin_class=\"Plugin\" # The base class for our plugins\n    ) as loader:\n        # Access the loaded plugins. 'plugins' is a nested dictionary:\n        # {module_name: {plugin_class_name: instance}}\n        loaded_plugins = loader.plugins\n        \n        if \"my_plugin\" in loaded_plugins and \"MyPlugin\" in loaded_plugins[\"my_plugin\"]:\n            my_plugin_instance = loaded_plugins[\"my_plugin\"][\"MyPlugin\"]\n            result = my_plugin_instance.execute()\n            print(f\"Successfully loaded and executed plugin: {result}\")\n            print(f\"Plugin version: {my_plugin_instance.version}\")\n        else:\n            print(\"Error: MyPlugin could not be found or loaded.\")\n\nfinally:\n    # --- Teardown: Clean up the temporary directory ---\n    temp_dir.cleanup()\n    # --- End Teardown ---","lang":"python","description":"This quickstart demonstrates how to define a simple plugin and use Pluginlib's `PluginLoader` to discover and instantiate it. It creates a temporary file structure to make the example self-contained and runnable, then cleans it up. The loader searches a specified path for modules, identifies classes inheriting from `pluginlib.Plugin`, and allows you to interact with their instances."},"warnings":[{"fix":"Ensure your project uses Python 3.6+ to be compatible with recent versions of pluginlib.","message":"Pluginlib dropped support for Python 2.6 and older Python 3 versions.","severity":"breaking","affected_versions":"0.9.0 and later"},{"fix":"Avoid deep nesting of plugins within namespace packages if you expect recursive discovery, or ensure each plugin module is directly discoverable by the specified paths.","message":"When loading plugins from namespace packages, pluginlib explicitly states that these packages are NOT searched recursively for imports. This means sub-modules within a namespace package won't be automatically discovered.","severity":"gotcha","affected_versions":"0.10.0 and later"},{"fix":"Update code that processes the output of `plugins_all` to correctly handle `OrderedDict` or convert it if strict dictionary behavior is required.","message":"The return type of `PluginLoader.plugins_all()` at its lowest level changed from a regular dictionary to an `OrderedDict`. Code relying on `dict` iteration order or direct indexing might be affected.","severity":"breaking","affected_versions":"0.7.0 and later"},{"fix":"Ensure consistent `async` definitions between parent abstract methods and child implementations to avoid `TypeError` or unexpected behavior.","message":"If an abstract method in a base `Plugin` class is defined as a coroutine (async), any overriding method in a child plugin class must also be defined as a coroutine.","severity":"gotcha","affected_versions":"0.7.0 and later"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z"}