From 332237e1f8623922cade912cd5768f93e877f95f Mon Sep 17 00:00:00 2001 From: Endkind Date: Sun, 15 Jun 2025 22:27:52 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCge=20Dokumentation=20zu=20Klassen=20und?= =?UTF-8?q?=20Methoden=20hinzu=20und=20erweitere=20die=20Release-Drafter-K?= =?UTF-8?q?onfiguration=20um=20Dokumentationskategorie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/release-drafter.yml | 4 ++++ ModuBotCore/__init__.py | 40 +++++++++++++++++++++++++++++++++ ModuBotCore/config/__init__.py | 13 +++++++++++ ModuBotCore/config/logger.py | 10 +++++++++ ModuBotCore/helpers/__init__.py | 11 ++++++++- ModuBotCore/modules/__init__.py | 23 +++++++++++++++++++ 6 files changed, 100 insertions(+), 1 deletion(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 24306b4..cf29ea7 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -16,6 +16,10 @@ categories: - title: '✅ Tests' labels: - 'tests' + - title: '📚 Documentation' + labels: + - 'documentation' + change-template: '- $TITLE @$AUTHOR (#$NUMBER)' no-changes-template: '- No changes' template: | diff --git a/ModuBotCore/__init__.py b/ModuBotCore/__init__.py index 895776b..3f356fe 100644 --- a/ModuBotCore/__init__.py +++ b/ModuBotCore/__init__.py @@ -11,12 +11,29 @@ class ModuBotCore(BaseConfig): + """ + Core class for the ModuBot framework. + + Handles logging, module loading, and lifecycle management (run/stop). + Modules are expected to reside in the "modules" directory and inherit from the defined MODULE_BASE_CLASS. + + :cvar NAME: The name of the bot core. + :cvar VERSION: Current version of the bot core. + :cvar LOGGER_CONFIG: Logger configuration class. + :cvar MODULE_BASE_CLASS: Base class for all modules to be loaded. + """ + NAME: ClassVar[str] = "ModuBotCore" VERSION: ClassVar[str] = "0.0.1" LOGGER_CONFIG: ClassVar[Type[LoggerConfig]] = LoggerConfig MODULE_BASE_CLASS: ClassVar[Type[BaseModule]] = BaseModule def __init__(self): + """ + Initializes logging and prepares the module list. + + Registers the stop() method to be called automatically on application exit. + """ logging.basicConfig( level=self.LOGGER_CONFIG.LEVEL, format=self.LOGGER_CONFIG.FORMAT, @@ -26,6 +43,11 @@ def __init__(self): atexit.register(self.stop) def run(self): + """ + Starts the bot and enables all loaded modules. + + Calls the on_enable() method of each module after loading. + """ self.logger.info(f"Starting {self.NAME}") self._load_modules() for module in self.modules: @@ -33,12 +55,24 @@ def run(self): module.on_enable() def stop(self): + """ + Disables all loaded modules and logs shutdown. + + Calls the on_disable() method of each module. + """ for module in self.modules: self.logger.info(f'Disabling module "{module.NAME}"') module.on_disable() self.logger.info(f"Stopping {self.NAME}") def _load_modules(self): + """ + Dynamically loads all modules from the "modules" directory. + + Each module must be in its own directory with an `__init__.py` file. + The module must contain a class that inherits from MODULE_BASE_CLASS. + Only modules with ENABLING = True will be instantiated and added. + """ root = Path().resolve() module_dir = root / "modules" self.logger.debug(f'Loading modules from "{module_dir}"') @@ -78,4 +112,10 @@ def _load_modules(self): @property def logger(self) -> logging.Logger: + """ + Returns the logger instance for the bot. + + :return: Logger bound to the bot's NAME. + :rtype: logging.Logger + """ return logging.getLogger(self.NAME) diff --git a/ModuBotCore/config/__init__.py b/ModuBotCore/config/__init__.py index 6e98e10..606f68d 100644 --- a/ModuBotCore/config/__init__.py +++ b/ModuBotCore/config/__init__.py @@ -7,6 +7,19 @@ class BaseConfig: + """ + Base configuration class with runtime type checking for class variables. + + This class automatically validates ClassVar attributes on subclass creation. + It ensures that the declared types match the actual values provided. + + Supported inner types for ClassVar are: + - Primitive types: str, int, float, bool + - Type wrappers, e.g., Type[SomeClass] + + :raises TypeError: If a ClassVar has an invalid or unsupported value/type. + """ + def __init_subclass__(cls) -> None: hints = get_type_hints(cls) diff --git a/ModuBotCore/config/logger.py b/ModuBotCore/config/logger.py index b4f2d5b..9f31d4a 100644 --- a/ModuBotCore/config/logger.py +++ b/ModuBotCore/config/logger.py @@ -7,6 +7,16 @@ @dataclass(frozen=True) class LoggerConfig(BaseConfig): + """ + Configuration class for the logging system. + + Defines the log level, formatting, and timestamp format used by the logger. + + :cvar LEVEL: Logging level (e.g., DEBUG, INFO). Defaults to the LOG_LEVEL environment variable or 'INFO'. + :cvar FORMAT: Format string for log messages. + :cvar DATEFMT: Format string for timestamps in log messages. + """ + LEVEL: ClassVar[str] = os.getenv("LOG_LEVEL", "INFO") FORMAT: ClassVar[str] = "[%(asctime)s - %(levelname)s - %(name)s]: %(message)s" DATEFMT: ClassVar[str] = "%m/%d/%Y %H:%M:%S" diff --git a/ModuBotCore/helpers/__init__.py b/ModuBotCore/helpers/__init__.py index 3f8587a..bfee140 100644 --- a/ModuBotCore/helpers/__init__.py +++ b/ModuBotCore/helpers/__init__.py @@ -1,3 +1,12 @@ def str2bool(value: str) -> bool: - """Convert string value to boolean.""" + """ + Convert a string representation to a boolean value. + + Common truthy values include: "yes", "true", "t", "y", "1" (case-insensitive). + + :param value: Input string to convert. + :type value: str + :return: True if the value is considered truthy, False otherwise. + :rtype: bool + """ return value.lower() in ("yes", "true", "t", "y", "1") diff --git a/ModuBotCore/modules/__init__.py b/ModuBotCore/modules/__init__.py index 74a4804..0f41bcb 100644 --- a/ModuBotCore/modules/__init__.py +++ b/ModuBotCore/modules/__init__.py @@ -6,17 +6,40 @@ class BaseModule(ABC, BaseConfig): + """ + Abstract base class for all ModuBot modules. + + All modules must inherit from this class and implement the `on_enable` and `on_disable` lifecycle methods. + + :cvar NAME: The name of the module. + :cvar ENABLING: Whether this module should be loaded and enabled. + """ + NAME: ClassVar[str] = "BaseModule" ENABLING: ClassVar[bool] = True @property def logger(self) -> logging.Logger: + """ + Returns a logger instance specific to the module. + + :return: Logger named after the module. + :rtype: logging.Logger + """ return logging.getLogger(self.NAME) @abstractmethod def on_enable(self): + """ + Hook that is called when the module is enabled. + Must be implemented by subclasses. + """ pass @abstractmethod def on_disable(self): + """ + Hook that is called when the module is disabled. + Must be implemented by subclasses. + """ pass