mirror of
https://gitflic.ru/project/maks1ms/ocab.git
synced 2024-12-24 16:44:44 +03:00
добавлена проверка зависимостей
This commit is contained in:
parent
89fe6a3520
commit
3b849417c3
@ -17,10 +17,11 @@
|
||||
"name": "Info",
|
||||
"description": "Модуль с информацией",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0",
|
||||
"version": "1.0.0",
|
||||
"privileged": false,
|
||||
"dependencies": {
|
||||
"standard.roles": "^1.0.0"
|
||||
"standard.roles": "^1.0.0",
|
||||
"standard.database": "^1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -54,7 +55,6 @@
|
||||
|
||||
## Взаимодействие между модулями
|
||||
|
||||
Модули могут взаимодействовать друг с другом через API, предоставляемое системой управления модулями.
|
||||
Модули могут взаимодействовать друг с другом через [API](../src/ocab_core/modules_system/public_api/__init__.py), предоставляемое системой управления модулями.
|
||||
|
||||
Например, есть `ocab_core.modules_system.public_api.get_module`.
|
||||
Функция, которая получает модуль или предоставляемые им объекты по его идентификатору.
|
||||
Например, есть функция `get_module`. Она позволяет получить модуль или предоставляемые им объекты по его идентификатору.
|
||||
|
13
poetry.lock
generated
13
poetry.lock
generated
@ -1124,6 +1124,17 @@ pygments = ">=2.13.0,<3.0.0"
|
||||
[package.extras]
|
||||
jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "3.0.2"
|
||||
description = "Python helper for Semantic Versioning (https://semver.org)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"},
|
||||
{file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stevedore"
|
||||
version = "5.2.0"
|
||||
@ -1307,4 +1318,4 @@ multidict = ">=4.0"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.11.6,<3.13"
|
||||
content-hash = "ea35c6a1b64b487fba434fe79cdbf6b78e21941e28d7cda433fd4093c3a0923d"
|
||||
content-hash = "5df07f0efc29d67f3ef2952b7d26a58098c16d5a391f469258f91ba47ebb972f"
|
||||
|
@ -30,6 +30,7 @@ pyyaml = "^6.0.1"
|
||||
requests = "^2.32.3"
|
||||
restrictedpython = "^7.1"
|
||||
dataclasses-json = "^0.6.7"
|
||||
semver = "^3.0.2"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
flake8 = "^7.1.0"
|
||||
@ -37,6 +38,7 @@ black = "^24.4.2"
|
||||
isort = "^5.13.2"
|
||||
bandit = "^1.7.9"
|
||||
pre-commit = "^3.7.1"
|
||||
semver = "^3.0.2"
|
||||
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
|
@ -12,6 +12,8 @@ class ModuleInfo:
|
||||
description: str
|
||||
version: str
|
||||
author: str
|
||||
privileged: bool
|
||||
dependencies: dict
|
||||
|
||||
|
||||
class AbstractLoader:
|
||||
|
@ -18,13 +18,9 @@ class FSLoader(UnsafeFSLoader):
|
||||
self.builtins["__import__"] = self._hook_import
|
||||
|
||||
def load(self):
|
||||
# TODO handle dependencies from info
|
||||
|
||||
self.info()
|
||||
|
||||
# with open(os.path.join(self.path, "__init__.py"), "r") as f:
|
||||
# source = f.read()
|
||||
|
||||
info = self.info()
|
||||
if info.privileged:
|
||||
raise Exception("Only non privileged modules are allowed to be imported")
|
||||
return self._hook_import(".")
|
||||
|
||||
def _resolve_module_from_path(self, module_name: str):
|
||||
@ -52,8 +48,7 @@ class FSLoader(UnsafeFSLoader):
|
||||
if name == allowed or name.startswith(f"{allowed}."):
|
||||
return __import__(name, *args, **kwargs)
|
||||
|
||||
# TODO: allow only public api for modules
|
||||
if name.startswith("ocab_core."):
|
||||
if name == "ocab_core.modules_system.public_api":
|
||||
return __import__(name, *args, **kwargs)
|
||||
|
||||
module_file_path = self._resolve_module_from_path(name)
|
||||
|
@ -1,12 +1,48 @@
|
||||
import semver
|
||||
|
||||
from ocab_core.modules_system.loaders.base import AbstractLoader
|
||||
|
||||
|
||||
def is_version_compatible(version, requirement):
|
||||
def parse_requirement(req):
|
||||
if req.startswith("^"):
|
||||
base_version = req[1:]
|
||||
base_version_info = semver.VersionInfo.parse(base_version)
|
||||
range_start = base_version_info
|
||||
range_end = base_version_info.bump_major()
|
||||
return [f">={range_start}", f"<{range_end}"]
|
||||
else:
|
||||
return [req]
|
||||
|
||||
for r in parse_requirement(requirement):
|
||||
if not semver.Version.parse(version).match(r):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ModulesManager:
|
||||
def __init__(self):
|
||||
self.modules = {}
|
||||
|
||||
def load(self, loader: AbstractLoader):
|
||||
info = loader.info()
|
||||
|
||||
if info.id in self.modules:
|
||||
return
|
||||
|
||||
for dependency, version in info.dependencies.items():
|
||||
if dependency not in self.modules:
|
||||
raise Exception(
|
||||
f"Module {info.id} depends on {dependency}, but it is not loaded"
|
||||
)
|
||||
loaded_dependency_info = self.modules[dependency]["info"]
|
||||
if not is_version_compatible(loaded_dependency_info.version, version):
|
||||
raise Exception(
|
||||
f"Module {info.id} depends on {dependency}, "
|
||||
f"but version {version} is not compatible"
|
||||
)
|
||||
|
||||
module = loader.load()
|
||||
|
||||
self.modules[info.id] = {
|
||||
|
@ -1 +1,3 @@
|
||||
from ocab_core.logger import log # noqa
|
||||
|
||||
from .public_api import Storage, get_module, register_router
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Config YAML",
|
||||
"description": "Модуль для работы с конфигурационным файлом бота (YAML)",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0",
|
||||
"version": "1.0.0",
|
||||
"privileged": true,
|
||||
"dependencies": {}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Database",
|
||||
"description": "Модуль для работы с БД",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0",
|
||||
"version": "1.0.0",
|
||||
"privileged": true,
|
||||
"dependencies": {}
|
||||
}
|
||||
|
@ -1,24 +1,18 @@
|
||||
# flake8: noqa
|
||||
from typing import Any, Type
|
||||
from typing import Type
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.types import Message
|
||||
|
||||
from ocab_core.logger import log
|
||||
from ocab_core.modules_system.public_api import get_module
|
||||
from ocab_core.modules_system.public_api import get_module, log
|
||||
|
||||
from .interfaces import IDbApi, IRoles
|
||||
|
||||
# from src.modules.standard.database import db_api
|
||||
|
||||
|
||||
db_api: Type[IDbApi] = get_module(
|
||||
"standard.database",
|
||||
"db_api",
|
||||
)
|
||||
|
||||
# db_api.init_db_connection()
|
||||
|
||||
Roles: Type[IRoles] = get_module("standard.roles", "Roles")
|
||||
|
||||
|
||||
|
@ -3,9 +3,10 @@
|
||||
"name": "Info",
|
||||
"description": "Модуль с информацией",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0",
|
||||
"version": "1.0.0",
|
||||
"privileged": false,
|
||||
"dependencies": {
|
||||
"standard.roles": "^1.0.0"
|
||||
"standard.roles": "^1.0.0",
|
||||
"standard.database": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Roles",
|
||||
"description": "Модуль для работы с ролями",
|
||||
"author": "OCAB Team",
|
||||
"version": "1.0",
|
||||
"version": "1.0.0",
|
||||
"privileged": true,
|
||||
"dependencies": {
|
||||
"standard.config": "^1.0.0",
|
||||
|
Loading…
Reference in New Issue
Block a user