Add [router registry]: add import modules method for router registry

This commit is contained in:
Kirill Samoylenkov 2025-10-24 16:19:18 +05:00
parent e4e2701a0a
commit 3171ce3acd

View file

@ -1,6 +1,8 @@
__all__ = ["RouterRegistry"]
import importlib
from pathlib import Path
from typing import Any, Callable, Union
from aiogram import Bot, F, Router
@ -9,6 +11,7 @@ from aiogram.types.bot_command import BotCommand
from aiogram.types.bot_command_scope_all_private_chats import (
BotCommandScopeAllPrivateChats,
)
from loguru import logger as loguru_logger
from bot.handlers.utils.filters import ChatTypeFilter
from bot.handlers.utils.types import (
@ -142,3 +145,122 @@ class RouterRegistry:
],
scope=BotCommandScopeAllPrivateChats(),
)
@staticmethod
def _get_modules_names(
modules_folder: Path,
package: str,
) -> list[str]:
"""
Getting absolute Python modules names from the modules_folder.
Args:
modules_folder (Path):
The folder containing the modules.
A relative path from the file that
calls this method should be used.
package (str):
The existing variable __package__
from the file that calls this method.
Warnings:
The attempt to import __init__.py
indicates something isn't right.
Returns:
list[str]: Absolute module names for import.
"""
modules_names: list[str] = list()
for file_path in modules_folder.rglob("*.py"):
if file_path.name == "__init__.py":
loguru_logger.warning(
"An attempt to load a path using RouterRegistry "
+ "containing __init__.py "
+ "indicates something isn't right. Skipping. "
+ "modules_folder path: {} | ".format(
modules_folder.absolute().as_posix()
)
+ "package: {}".format(package)
)
continue
module_name = (
package
+ "."
+ (
file_path.with_suffix("")
.relative_to(modules_folder.parent)
.as_posix()
.replace("/", ".")
)
)
modules_names.append(module_name)
return modules_names
def import_modules(
self,
modules_folder: Path,
package: str | None,
) -> None:
"""
Importing modules from the folder with Python modules.
It is implied that the modules contain configurations
for RouterRegistry.
For example, there may be register decorators contained there.
Example:
```
registry: RouterRegistry = RouterRegistry()
registry_dir = Path(__file__).parent
registry.import_modules(
registry_dir / "commands",
__package__,
)
registry.import_modules(
registry_dir / "callbacks",
__package__,
)
dispatcher.include_router(registry.router)
```
Args:
modules_folder (Path):
The folder containing the modules.
A relative path from the file that
calls this method should be used.
package (str | None):
The existing variable __package__
from the file that calls this method.
Raises:
ImportError: The package variable cannot be None.
"""
if package is None:
loguru_logger.error(
"It is required that the package be a Python path "
+ "to the module from which the folder of modules "
+ "needs to be loaded."
)
raise ImportError("The package variable cannot be None.")
registry_modules: list[str] = self._get_modules_names(
modules_folder=modules_folder,
package=package,
)
loguru_logger.debug(
"Trying to load these modules: " + str(registry_modules)
)
for module_name in registry_modules:
importlib.import_module(module_name)
loguru_logger.debug("Modules loaded successfully.")