Plux Dynamic Code Loading Framework
Plux is a dynamic code loading framework for building pluggable Python distributions. It facilitates the discovery and loading of plugins defined via Python entry points, streamlining the process of creating extensible applications. The current version is 1.16.0, and the library maintains an active release cadence with several updates per year.
Warnings
- breaking Prior to v1.10.0, Plux used `stevedore` for entry point resolution. This dependency was removed in v1.10.0, along with a complete rewrite of the resolution procedure. Projects relying on `stevedore`-specific behaviors or directly interacting with it through Plux will break.
- gotcha From v1.14.0 onwards, Plux has added explicit support for `hatchling` and `setuptools` build backends, including new `entrypoint build modes` and configuration options. Incompatible build system configurations or reliance on outdated entry point definition styles may lead to plugins not being discovered.
- gotcha Introduced in v1.11.0, `plux.runtime.filter.global_plugin_filter` allows filtering plugins by namespace patterns. If filters are inadvertently applied or misconfigured, expected plugins may not be discovered without clear error messages, leading to silent failures.
Install
-
pip install plux -
pip install plux[hatchling] -
pip install plux[setuptools]
Imports
- PluginManager
from plux.manager import PluginManager
- global_plugin_filter
from plux.runtime.filter import global_plugin_filter
Quickstart
import sys
from plux.manager import PluginManager
# --- In a real project, you would define your plugin entry point in pyproject.toml ---
# For example, in 'my_project/pyproject.toml':
#
# [project.entry-points."my.plugins"]
# my_example_plugin = "my_project.plugins:MyExamplePlugin"
#
# And have a 'my_project/plugins.py' file:
# class MyExamplePlugin:
# def run(self):
# return "MyExamplePlugin is running!"
#
# Then install your project in editable mode: `pip install -e .`
#
# --- This quickstart assumes such a plugin is discoverable ---
# Instantiate the PluginManager for a specific namespace
# Replace 'my.plugins' with your actual entry point group name
manager = PluginManager("my.plugins")
print(f"Searching for plugins in namespace 'my.plugins'...")
found_plugins = list(manager.discover())
if not found_plugins:
print("No plugins discovered. Ensure a plugin is defined via entry points and installed.")
print("Refer to the comments in this quickstart for typical setup steps.")
else:
print(f"Discovered {len(found_plugins)} plugin(s):")
for name, plugin_class in found_plugins:
print(f" - Name: {name}, Class: {plugin_class.__name__}")
try:
plugin_instance = plugin_class()
if hasattr(plugin_instance, 'run'):
result = plugin_instance.run()
print(f" Instance result: {result}")
except Exception as e:
print(f" Could not instantiate or run plugin {name}: {e}")