pronoun-o-matic/plugin.py

63 lines
1.8 KiB
Python
Raw Normal View History

2022-06-04 22:18:32 +02:00
from abc import abstractclassmethod, abstractmethod
from functools import cache
2022-06-05 21:50:45 +02:00
from importlib.metadata import entry_points
import logging
from typing import Any, Callable, List
from pronoun_update import PronounUpdate
2022-06-04 22:18:32 +02:00
class Plugin:
2022-06-05 21:50:45 +02:00
def __init__(self, config: dict[str, str]):
logging.info(f"Loading plugin {self.name()}")
self._load_from_config(config)
2022-06-04 22:18:32 +02:00
@abstractmethod
2022-06-05 21:50:45 +02:00
def _load_from_config(self, config: dict[str, Any]) -> None:
2022-06-04 22:18:32 +02:00
pass
2022-06-05 21:50:45 +02:00
@classmethod
2022-06-04 22:18:32 +02:00
@abstractmethod
2022-06-05 21:50:45 +02:00
def name(cls) -> str:
2022-06-04 22:18:32 +02:00
pass
@abstractmethod
2022-06-05 21:50:45 +02:00
def update_bio(self, update_pronouns: PronounUpdate) -> None:
2022-06-04 22:18:32 +02:00
pass
@cache
def load_plugins() -> dict[str, type[Plugin]]:
plugins: dict[str, type[Plugin]] = {}
# Ignore the following two lines due to incorrect type definition for entry_points
# See: https://github.com/python/typeshed/pull/7331
for plugin in entry_points(group="pronounomatic.plugins"): # type: ignore
pl = plugin.load() # type: ignore
assert issubclass(pl, Plugin)
plugins[pl.name()] = pl
return plugins
class InvalidPluginDefinitionException(Exception):
pass
def load_plugins_for_config(config: list[dict[str, Any]]) -> List[Plugin]:
plugins = []
plugin_classes = load_plugins()
for plugin_def in config:
if not plugin_def["name"]:
raise InvalidPluginDefinitionException("Missing plugin_name field")
plugin_name = plugin_def["name"]
if not plugin_name in load_plugins():
raise InvalidPluginDefinitionException(
f"No plugin with name {plugin_name} loaded"
)
plugin_cls = plugin_classes[plugin_name]
plugin = plugin_cls(plugin_def)
plugins.append(plugin)
return plugins