Skip to content

Extensions

Asterios Raptis edited this page Mar 27, 2026 · 1 revision

Extensions

PluginForge supports an extension point pattern for querying active plugins by interface, inspired by PF4J's extension system.

Concept

While pluggy hooks use a fire-and-forget call pattern (call_hook("on_save", ...)), extension points let you query and interact with plugins directly:

Hooks: pm.call_hook("on_save", document=doc) -> list of results
Extensions: pm.get_extensions(ExportFormat) -> list of plugin instances

Defining Extension Points

An extension point is any Python class or ABC:

fromabcimportABC, abstractmethodclassExportFormat(ABC):
"""Extension point for document export formats."""@abstractmethoddefexport(self, document: dict, output_path: str) ->str:
"""Export a document and return the output file path."""
...
@abstractmethoddefsupported_extensions(self) ->list[str]:
"""Return supported file extensions."""
...

Implementing Extensions

Plugins implement extension points by inheriting from both BasePlugin and the extension point:

frompluginforgeimportBasePluginclassEpubExport(BasePlugin, ExportFormat):
name="epub_export"version="1.0.0"defexport(self, document: dict, output_path: str) ->str:
# ... epub export logic ...returnf"{output_path}.epub"defsupported_extensions(self) ->list[str]:
return [".epub"]
classPdfExport(BasePlugin, ExportFormat):
name="pdf_export"version="1.0.0"defexport(self, document: dict, output_path: str) ->str:
# ... pdf export logic ...returnf"{output_path}.pdf"defsupported_extensions(self) ->list[str]:
return [".pdf"]

Querying Extensions

Use get_extensions() to find all active plugins implementing an extension point:

pm=PluginManager("config/app.yaml")
pm.register_plugins([EpubExport, PdfExport, AnalyticsPlugin])
# Only returns plugins that implement ExportFormatexporters=pm.get_extensions(ExportFormat)
# [<EpubExport>, <PdfExport>]# Use them directlyforexporterinexporters:
path=exporter.export(document, "/tmp/output")
print(f"Exported to {path}")
# Get all supported formatsall_extensions= []
forexporterinexporters:
all_extensions.extend(exporter.supported_extensions())
# [".epub", ".pdf"]

Extension Points vs. Hooks

AspectHooksExtensions
PatternFire-and-forgetQuery and interact
ReturnsList of resultsList of plugin instances
Use caseEvents, notificationsCapabilities, strategies
Example"Document was saved""Which export formats exist?"

Use hooks when you want to notify plugins about events. Use extensions when you want to discover capabilities and interact with specific plugins.

Combining with Hooks

A plugin can be both an extension and a hook implementer:

classEpubExport(BasePlugin, ExportFormat):
name="epub_export"# Extension point implementationdefexport(self, document: dict, output_path: str) ->str:
returnself._do_export(document, output_path)
defsupported_extensions(self) ->list[str]:
return [".epub"]
# Hook implementation@hookimpldefon_document_save(self, document: dict) ->None:
# Auto-export on save if configuredifself.config.get("auto_export"):
self.export(document, self.config["output_dir"])

Clone this wiki locally