From b19df54cb4369197ca8d0661bdcbc74198cb742b Mon Sep 17 00:00:00 2001 From: "Meinel, Michael" Date: Mon, 26 Feb 2024 16:53:01 +0100 Subject: [PATCH] First draft of automatic generation of Pydantic settings classes from plugins --- src/hermes/commands/cli.py | 26 ++++++++++++++++++++++ src/hermes/commands/deposit/invenio_rdm.py | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/hermes/commands/cli.py b/src/hermes/commands/cli.py index dc345058..9b9d7e17 100644 --- a/src/hermes/commands/cli.py +++ b/src/hermes/commands/cli.py @@ -12,6 +12,10 @@ import pathlib from importlib import metadata +from pydantic import BaseModel + +from hermes.settings import DepositSettings, HarvestSettings, PostprocessSettings + class HermesCommand: """ Base class for a HERMES workflow command. @@ -20,6 +24,7 @@ class HermesCommand: """ NAME: str = None + settings_class: type = BaseModel def __init__(self, parser: argparse.ArgumentParser): """ Initialize a new instance of any HERMES command. @@ -30,11 +35,29 @@ def __init__(self, parser: argparse.ArgumentParser): self.plugins = self.init_plugins() def init_plugins(self): + # Collect all entry points for this group (i.e., all valid plug-ins for the step) entry_point_group = f"hermes.{self.NAME}" group_plugins = [ (entry_point.name, entry_point.load()) for entry_point in metadata.entry_points(group=entry_point_group) ] + + # Collect the plug-in specific configurations + plugin_settings = { + plugin_name: getattr(plugin_class, 'settings_class', None) + for plugin_name, plugin_class in group_plugins + } + + # Derive a new settings model class that contains all the plug-in extensions + self.settings_class = type(f'{self.__class__.__name__}Settings', (self.settings_class, ), { + '__annotations__': plugin_settings, + **{ + plugin_name: plugin_settings() + for plugin_name, plugin_settings in plugin_settings.items() + if plugin_settings is not None + } + }) + return group_plugins def init_common_parser(self, parser: argparse.ArgumentParser) -> None: @@ -103,6 +126,7 @@ class HermesHarvestCommand(HermesCommand): """ Harvest metadata from configured sources. """ NAME = "harvest" + settings_class = HarvestSettings class HermesProcessCommand(HermesCommand): @@ -121,12 +145,14 @@ class HermesDepositCommand(HermesCommand): """ Deposit the curated metadata to repositories. """ NAME = "deposit" + settings_class = DepositSettings class HermesPostprocessCommand(HermesCommand): """ Post-process the published metadata after deposition. """ NAME = "postprocess" + settings_class = PostprocessSettings def main() -> None: diff --git a/src/hermes/commands/deposit/invenio_rdm.py b/src/hermes/commands/deposit/invenio_rdm.py index ce7fa2b6..adb87e82 100644 --- a/src/hermes/commands/deposit/invenio_rdm.py +++ b/src/hermes/commands/deposit/invenio_rdm.py @@ -15,6 +15,7 @@ InvenioDepositPlugin, InvenioResolver, ) +from hermes.settings import DepositTargetSettings class InvenioRDMClient(InvenioClient): @@ -88,3 +89,5 @@ class IvenioRDMDepositPlugin(InvenioDepositPlugin): platform_name = "invenio_rdm" invenio_client_class = InvenioRDMClient invenio_resolver_class = InvenioRDMResolver + + settings_class = DepositTargetSettings