| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import functools
- import importlib
- from collections import namedtuple
- from importlib import resources
- from typing import Type, Any, List
- # Basic structure for storing information about one plugin
- Plugin = namedtuple("Plugin", ("name", "func"))
- # Dictionary with information about all registered plugins
- _PLUGINS = {}
- # From https://realpython.com/python-import/#example-a-package-of-plugins
- def register(func):
- """Decorator for registering a new plugin"""
- package, _, plugin = func.__module__.rpartition(".")
- pkg_info = _PLUGINS.setdefault(package, {})
- pkg_info[plugin] = Plugin(name=plugin, func=func)
- return func
- def names(package: str) -> List[str]:
- """List all plugins in one package"""
- _import_all(package)
- return sorted(_PLUGINS[package])
- def get(package: str, plugin: str) -> Type[Any]:
- """Get a given plugin"""
- _import(package, plugin)
- return _PLUGINS[package][plugin].func
- def call(package: str, plugin: str, *args, **kwargs) -> Any:
- """Call the given plugin"""
- plugin_func = get(package, plugin)
- return plugin_func(*args, **kwargs)
- def _import(package: str, plugin: str) -> None:
- """Import the given plugin file from a package"""
- importlib.import_module(f"{package}.{plugin}")
- def _import_all(package: str) -> None:
- """Import all plugins in a package"""
- files = resources.contents(package)
- plugins = [f[:-3] for f in files if f.endswith(".py") and f[0] != "_"]
- for plugin in plugins:
- _import(package, plugin)
- def names_factory(package: str):
- """Create a names() function for one package"""
- return functools.partial(names, package)
- def get_factory(package: str):
- """Create a get() function for one package"""
- return functools.partial(get, package)
- def call_factory(package: str):
- """Create a call() function for one package"""
- return functools.partial(call, package)
|