Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ path = ["REUSE.toml"]
precedence = "aggregate"
SPDX-FileCopyrightText = "German Aerospace Center (DLR), Helmholtz-Zentrum Dresden-Rossendorf, Forschungszentrum Jülich"
SPDX-License-Identifier = "CC0-1.0"

[[annotations]]
path = ["src/**/*.py", "test/**/*.py"]
precedence = "aggregate"
SPDX-FileCopyrightText = "German Aerospace Center (DLR), Helmholtz-Zentrum Dresden-Rossendorf, Forschungszentrum Jülich"
SPDX-License-Identifier = "Apache-2.0"
46 changes: 7 additions & 39 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ pytest-cov = "^3.0.0"
taskipy = "^1.10.3"
flake8 = "^5.0.4"
requests-mock = "^1.10.0"
pytest-httpserver = "^1.1.3"

# Packages for developers for creating documentation
[tool.poetry.group.docs]
Expand Down
14 changes: 7 additions & 7 deletions src/hermes/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
# "unused import" errors.
# flake8: noqa

from hermes.commands.base import HermesHelpCommand
from hermes.commands.base import HermesVersionCommand
from hermes.commands.clean.base import HermesCleanCommand
from hermes.commands.init.base import HermesInitCommand
from hermes.commands.curate.base import HermesCurateCommand
# from hermes.commands.base import HermesHelpCommand
# from hermes.commands.base import HermesVersionCommand
# from hermes.commands.clean.base import HermesCleanCommand
# from hermes.commands.init.base import HermesInitCommand
# from hermes.commands.curate.base import HermesCurateCommand
from hermes.commands.harvest.base import HermesHarvestCommand
from hermes.commands.process.base import HermesProcessCommand
# from hermes.commands.process.base import HermesProcessCommand
from hermes.commands.deposit.base import HermesDepositCommand
from hermes.commands.postprocess.base import HermesPostprocessCommand
# from hermes.commands.postprocess.base import HermesPostprocessCommand
76 changes: 25 additions & 51 deletions src/hermes/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
import logging
import pathlib
from importlib import metadata
from typing import Dict, Optional, Type
from typing import Type, Union

import toml
from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict


class _HermesSettings(BaseSettings):
class HermesSettings(BaseSettings):
"""Root class for HERMES configuration model."""

model_config = SettingsConfigDict(env_file_encoding='utf-8')

logging: Dict = {}
logging: dict = {}


class HermesCommand(abc.ABC):
Expand All @@ -31,7 +31,7 @@ class HermesCommand(abc.ABC):
"""

command_name: str = ""
settings_class: Type = _HermesSettings
settings_class: Type = HermesSettings

def __init__(self, parser: argparse.ArgumentParser):
"""Initialize a new instance of any HERMES command.
Expand All @@ -45,28 +45,27 @@ def __init__(self, parser: argparse.ArgumentParser):
self.log = logging.getLogger(f"hermes.{self.command_name}")
self.errors = []

@classmethod
def init_plugins(cls):
def init_plugins(self):
"""Collect and initialize the plugins available for the HERMES command."""

# Collect all entry points for this group (i.e., all valid plug-ins for the step)
entry_point_group = f"hermes.{cls.command_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
cls.derive_settings_class({
plugin_name: plugin_class.settings_class
for plugin_name, plugin_class in group_plugins.items()
if hasattr(plugin_class, "settings_class") and plugin_class.settings_class is not None
})
entry_point_group = f"hermes.{self.command_name}"
group_plugins = {}
group_settings = {}

for entry_point in metadata.entry_points(group=entry_point_group):
plugin_cls = entry_point.load()

group_plugins[entry_point.name] = plugin_cls
if hasattr(plugin_cls, 'settings_class') and plugin_cls.settings_class is not None:
group_settings[entry_point.name] = plugin_cls.settings_class

self.derive_settings_class(group_settings)

return group_plugins

@classmethod
def derive_settings_class(cls, setting_types: Dict[str, Type]) -> None:
def derive_settings_class(cls, setting_types: dict[str, Type]) -> None:
"""Build a new Pydantic data model class for configuration.

This will create a new class that includes all settings from the plugins available.
Expand Down Expand Up @@ -131,13 +130,10 @@ def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:

def load_settings(self, args: argparse.Namespace):
"""Load settings from the configuration file (passed in from command line)."""
try:
toml_data = toml.load(args.path / args.config)
self.root_settings = HermesCommand.settings_class.model_validate(toml_data)
self.settings = getattr(self.root_settings, self.command_name)
except FileNotFoundError as e:
self.log.error("hermes.toml was not found. Try to run 'hermes init' first or create one manually.")
raise e # This will lead to our default error message & sys.exit

toml_data = toml.load(args.path / args.config)
self.root_settings = HermesCommand.settings_class.model_validate(toml_data)
self.settings = getattr(self.root_settings, self.command_name)

def patch_settings(self, args: argparse.Namespace):
"""Process command line options for the settings."""
Expand All @@ -164,7 +160,9 @@ def __call__(self, args: argparse.Namespace):
class HermesPlugin(abc.ABC):
"""Base class for all HERMES plugins."""

settings_class: Optional[Type] = None
pluing_node = None

settings_class: Union[Type, None] = None

@abc.abstractmethod
def __call__(self, command: HermesCommand) -> None:
Expand Down Expand Up @@ -202,27 +200,3 @@ def __call__(self, args: argparse.Namespace) -> None:
# Otherwise, simply show the general help and exit (cleanly).
self.parser.print_help()
self.parser.exit()

def load_settings(self, args: argparse.Namespace):
"""No settings are needed for the help command."""
pass


class HermesVersionSettings(BaseModel):
"""Intentionally empty settings class for the version command."""
pass


class HermesVersionCommand(HermesCommand):
"""Show HERMES version and exit."""

command_name = "version"
settings_class = HermesVersionSettings

def load_settings(self, args: argparse.Namespace):
"""Pass loading settings as not necessary for this command."""
pass

def __call__(self, args: argparse.Namespace) -> None:
self.log.info(metadata.version("hermes"))
self.parser.exit()
22 changes: 12 additions & 10 deletions src/hermes/commands/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import sys

from hermes import logger
from hermes.commands import (HermesHelpCommand, HermesVersionCommand, HermesCleanCommand,
HermesHarvestCommand, HermesProcessCommand, HermesCurateCommand,
HermesDepositCommand, HermesPostprocessCommand, HermesInitCommand)
# FIXME: remove comments after new implementation of modules is available
# from hermes.commands import (HermesHelpCommand, HermesVersionCommand, HermesCleanCommand,
# HermesHarvestCommand, HermesProcessCommand, HermesCurateCommand,
# HermesDepositCommand, HermesPostprocessCommand, HermesInitCommand)
from hermes.commands import HermesDepositCommand, HermesHarvestCommand
from hermes.commands.base import HermesCommand


Expand All @@ -36,15 +38,15 @@ def main() -> None:
setting_types = {}

for command in (
HermesHelpCommand(parser),
HermesVersionCommand(parser),
HermesInitCommand(parser),
HermesCleanCommand(parser),
# HermesHelpCommand(parser),
# HermesVersionCommand(parser),
# HermesInitCommand(parser),
# HermesCleanCommand(parser),
HermesHarvestCommand(parser),
HermesProcessCommand(parser),
HermesCurateCommand(parser),
# HermesProcessCommand(parser),
# HermesCurateCommand(parser),
HermesDepositCommand(parser),
HermesPostprocessCommand(parser),
# HermesPostprocessCommand(parser),
):
if command.settings_class is not None:
setting_types[command.command_name] = command.settings_class
Expand Down
Loading
Loading