mirror of
https://gitflic.ru/project/maks1ms/ocab.git
synced 2024-12-24 16:44:44 +03:00
подготовка к публикации
This commit is contained in:
parent
bfa1d13931
commit
d5f6f1bb4f
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,6 +6,4 @@ env
|
|||||||
venv
|
venv
|
||||||
__pycache__
|
__pycache__
|
||||||
OCAB.db
|
OCAB.db
|
||||||
src/paths.json
|
config.yaml
|
||||||
src/ocab_core/config.yaml
|
|
||||||
src/ocab_core/log/**/*
|
|
||||||
|
2221
poetry.lock
generated
2221
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "ocab"
|
name = "ocab-monorepo"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
description = "OCAB is a modular Telegram bot"
|
description = "OCAB is a modular Telegram bot"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
@ -13,9 +13,7 @@ maintainers = [
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://gitflic.ru/project/armatik/ocab"
|
repository = "https://gitflic.ru/project/armatik/ocab"
|
||||||
packages = [
|
packages = [
|
||||||
{ include = "scripts" },
|
{ include = "scripts" }
|
||||||
{ include = "ocab_core", from = "src" },
|
|
||||||
{ include = "ocab_modules", from = "src" }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.poetry.urls]
|
[tool.poetry.urls]
|
||||||
@ -27,21 +25,7 @@ init = 'scripts.init:main'
|
|||||||
module = 'scripts.module:main'
|
module = 'scripts.module:main'
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.11.6,<3.13"
|
python = "~3.12"
|
||||||
aiogram = "^3.10.0"
|
|
||||||
peewee = "^3.17.6"
|
|
||||||
pyyaml = "^6.0.1"
|
|
||||||
requests = "^2.32.3"
|
|
||||||
restrictedpython = "^7.1"
|
|
||||||
dataclasses-json = "^0.6.7"
|
|
||||||
semver = "^3.0.2"
|
|
||||||
hypercorn = "^0.17.3"
|
|
||||||
flet = "^0.23.2"
|
|
||||||
fastapi = "^0.111.1"
|
|
||||||
setuptools = "^71.0.1"
|
|
||||||
dash = "^2.17.1"
|
|
||||||
dash-extensions = "^1.0.18"
|
|
||||||
dash-bootstrap-components = "^1.6.0"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
flake8 = "^7.1.0"
|
flake8 = "^7.1.0"
|
||||||
|
1
src/gnomik/README.md
Normal file
1
src/gnomik/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Гномик
|
29
src/gnomik/gnomik/__main__.py
Normal file
29
src/gnomik/gnomik/__main__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from ocab_core import OCAB
|
||||||
|
from ocab_modules import module_loader
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
ocab = OCAB()
|
||||||
|
await ocab.init_app(
|
||||||
|
[
|
||||||
|
module_loader("standard", "config", safe=False),
|
||||||
|
module_loader("standard", "database", safe=False),
|
||||||
|
module_loader("standard", "fsm_database_storage", safe=False),
|
||||||
|
module_loader("standard", "roles", safe=False),
|
||||||
|
module_loader("external", "yandexgpt", safe=False),
|
||||||
|
#
|
||||||
|
module_loader("standard", "command_helper"),
|
||||||
|
module_loader("standard", "info"),
|
||||||
|
module_loader("standard", "filters"),
|
||||||
|
module_loader("external", "create_report_apps"),
|
||||||
|
module_loader("standard", "admin"),
|
||||||
|
module_loader("standard", "message_processing"),
|
||||||
|
module_loader("standard", "miniapp", safe=False),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
await ocab.start()
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
2162
src/gnomik/poetry.lock
generated
Normal file
2162
src/gnomik/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
src/gnomik/poetry.toml
Normal file
2
src/gnomik/poetry.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
15
src/gnomik/pyproject.toml
Normal file
15
src/gnomik/pyproject.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "gnomik"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Максим Слипенко <maxim@slipenko.com>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "~3.12"
|
||||||
|
ocab-core = { extras=["webhook"], path = "../ocab_core", develop = true }
|
||||||
|
ocab-modules = { path = "../ocab_modules", develop = true }
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
1
src/ocab_core/README.md
Normal file
1
src/ocab_core/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# OCAB Core
|
@ -1,5 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
|
|
||||||
from ocab_core.main import main
|
|
||||||
|
|
||||||
asyncio.run(main())
|
|
@ -1,21 +0,0 @@
|
|||||||
core:
|
|
||||||
token: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
mode: WEBHOOK
|
|
||||||
webhook:
|
|
||||||
public_url: https://.../webhook
|
|
||||||
|
|
||||||
miniapp:
|
|
||||||
public_url: https://.../webapp
|
|
||||||
|
|
||||||
filters:
|
|
||||||
approved_chat_id: "-123456789 | -012345678"
|
|
||||||
default_chat_tag: "@alt_gnome_chat"
|
|
||||||
|
|
||||||
yandexgpt:
|
|
||||||
token: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
token_for_request: 8000
|
|
||||||
token_for_answer: 2000
|
|
||||||
catalogid: xxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
prompt: "Ты чат-бот ..."
|
|
||||||
startword: "Бот| Бот, | бот | бот,"
|
|
||||||
inword: "помогите | не работает"
|
|
@ -1,31 +0,0 @@
|
|||||||
import importlib
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from aiogram import Bot, Dispatcher
|
|
||||||
from aiogram.types import Update
|
|
||||||
from fastapi import FastAPI, Request
|
|
||||||
|
|
||||||
|
|
||||||
def get_module_directory(module_name):
|
|
||||||
spec = importlib.util.find_spec(module_name)
|
|
||||||
if spec is None:
|
|
||||||
raise ImportError(f"Module {module_name} not found")
|
|
||||||
module_path = spec.origin
|
|
||||||
if module_path is None:
|
|
||||||
raise ImportError(f"Module {module_name} has no origin path")
|
|
||||||
return os.path.dirname(module_path)
|
|
||||||
|
|
||||||
|
|
||||||
async def register_bot_webhook(app: FastAPI, bot: Bot, dp: Dispatcher):
|
|
||||||
async def handle_webhook(request: Request):
|
|
||||||
try:
|
|
||||||
update = Update.model_validate(await request.json(), context={"bot": bot})
|
|
||||||
await dp.feed_update(bot, update)
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
return {"ok": False}
|
|
||||||
|
|
||||||
return {"ok": True}
|
|
||||||
|
|
||||||
app.post("/webhook")(handle_webhook)
|
|
@ -1,143 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import traceback
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from aiogram import Bot, Dispatcher
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from hypercorn.asyncio import serve
|
|
||||||
from hypercorn.config import Config as HyperConfig
|
|
||||||
|
|
||||||
from ocab_core.lib import get_module_directory, register_bot_webhook
|
|
||||||
from ocab_core.logger import CustomLogger, log, setup_logger
|
|
||||||
from ocab_core.modules_system import ModulesManager
|
|
||||||
from ocab_core.modules_system.loaders import FSLoader, UnsafeFSLoader
|
|
||||||
from ocab_core.modules_system.public_api import get_module
|
|
||||||
from ocab_core.singleton import Singleton
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ocab_modules.standard.config import IConfig
|
|
||||||
|
|
||||||
ocab_modules_path = get_module_directory("ocab_modules")
|
|
||||||
|
|
||||||
|
|
||||||
def ocab_modules_loader(namespace: str, module_name: str, safe=True):
|
|
||||||
if not safe:
|
|
||||||
return UnsafeFSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
|
||||||
else:
|
|
||||||
return FSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
|
||||||
|
|
||||||
|
|
||||||
bot_modules = [
|
|
||||||
ocab_modules_loader("standard", "config", safe=False),
|
|
||||||
ocab_modules_loader("standard", "database", safe=False),
|
|
||||||
ocab_modules_loader("standard", "fsm_database_storage", safe=False),
|
|
||||||
ocab_modules_loader("standard", "roles", safe=False),
|
|
||||||
ocab_modules_loader("external", "yandexgpt", safe=False),
|
|
||||||
#
|
|
||||||
ocab_modules_loader("standard", "command_helper"),
|
|
||||||
ocab_modules_loader("standard", "info"),
|
|
||||||
ocab_modules_loader("standard", "filters"),
|
|
||||||
ocab_modules_loader("external", "create_report_apps"),
|
|
||||||
ocab_modules_loader("standard", "admin"),
|
|
||||||
ocab_modules_loader("standard", "message_processing"),
|
|
||||||
ocab_modules_loader("standard", "miniapp", safe=False),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
async def long_polling_mode():
|
|
||||||
singleton = Singleton()
|
|
||||||
await singleton.bot.delete_webhook()
|
|
||||||
await singleton.dp.start_polling(singleton.bot)
|
|
||||||
|
|
||||||
|
|
||||||
async def webhook_mode():
|
|
||||||
singleton = Singleton()
|
|
||||||
app = FastAPI()
|
|
||||||
config = get_module("standard.config", "config")
|
|
||||||
|
|
||||||
app.mount("/webapp", singleton.storage["webapp"])
|
|
||||||
|
|
||||||
await register_bot_webhook(app, singleton.bot, singleton.dp)
|
|
||||||
await singleton.bot.set_webhook(config.get("core::webhook::public_url"))
|
|
||||||
|
|
||||||
hyperConfig = HyperConfig()
|
|
||||||
hyperConfig.bind = [f"0.0.0.0:{config.get("core::webhook::port")}"]
|
|
||||||
hyperConfig.logger_class = CustomLogger
|
|
||||||
await serve(app, hyperConfig)
|
|
||||||
|
|
||||||
|
|
||||||
def register_config():
|
|
||||||
config: "IConfig" = get_module("standard.config", "config")
|
|
||||||
|
|
||||||
config.register(
|
|
||||||
"core::token",
|
|
||||||
"password",
|
|
||||||
visible=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
config.register(
|
|
||||||
"core::mode",
|
|
||||||
"select",
|
|
||||||
options=["WEBHOOK", "LONG_POLLING"],
|
|
||||||
default_value="WEBHOOK",
|
|
||||||
visible=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
config.register(
|
|
||||||
"core::webhook::port",
|
|
||||||
"int",
|
|
||||||
default_value=9000,
|
|
||||||
visible=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
config.register(
|
|
||||||
"core::webhook::public_url",
|
|
||||||
"string",
|
|
||||||
visible=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def init_app():
|
|
||||||
setup_logger()
|
|
||||||
singleton = Singleton()
|
|
||||||
|
|
||||||
try:
|
|
||||||
singleton.modules_manager = ModulesManager()
|
|
||||||
|
|
||||||
for module_loader in bot_modules:
|
|
||||||
info = module_loader.info()
|
|
||||||
log(f"Loading {info.name} ({info.id}) module")
|
|
||||||
await singleton.modules_manager.load(module_loader)
|
|
||||||
|
|
||||||
register_config()
|
|
||||||
|
|
||||||
config = get_module("standard.config", "config")
|
|
||||||
|
|
||||||
config.load()
|
|
||||||
|
|
||||||
singleton.bot = Bot(token=config.get("core::token"))
|
|
||||||
singleton.dp = Dispatcher(storage=singleton.storage["_fsm_storage"])
|
|
||||||
singleton.dp.include_routers(*singleton.storage["_routers"])
|
|
||||||
|
|
||||||
for middleware in singleton.storage["_outer_message_middlewares"]:
|
|
||||||
singleton.dp.message.outer_middleware.register(middleware)
|
|
||||||
|
|
||||||
await singleton.modules_manager.late_init()
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await init_app()
|
|
||||||
config = get_module("standard.config", "config")
|
|
||||||
|
|
||||||
if config.get("core::mode") == "WEBHOOK":
|
|
||||||
await webhook_mode()
|
|
||||||
else:
|
|
||||||
await long_polling_mode()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(main())
|
|
1
src/ocab_core/ocab_core/__init__.py
Normal file
1
src/ocab_core/ocab_core/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .main import OCAB
|
38
src/ocab_core/ocab_core/lib.py
Normal file
38
src/ocab_core/ocab_core/lib.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram.types import Update
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_directory(module_name):
|
||||||
|
spec = importlib.util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ImportError(f"Module {module_name} not found")
|
||||||
|
module_path = spec.origin
|
||||||
|
if module_path is None:
|
||||||
|
raise ImportError(f"Module {module_name} has no origin path")
|
||||||
|
return os.path.dirname(module_path)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
|
||||||
|
async def register_bot_webhook(app: FastAPI, bot: Bot, dp: Dispatcher):
|
||||||
|
async def handle_webhook(request: Request):
|
||||||
|
try:
|
||||||
|
update = Update.model_validate(
|
||||||
|
await request.json(), context={"bot": bot}
|
||||||
|
)
|
||||||
|
await dp.feed_update(bot, update)
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"ok": False}
|
||||||
|
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
app.post("/webhook")(handle_webhook)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
pass
|
@ -1,8 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from hypercorn.logging import Logger as HypercornLogger
|
|
||||||
|
|
||||||
app_logger = logging.getLogger("ocab")
|
app_logger = logging.getLogger("ocab")
|
||||||
log_level = logging.INFO
|
log_level = logging.INFO
|
||||||
|
|
||||||
@ -33,10 +31,16 @@ def log(message):
|
|||||||
app_logger.info(message)
|
app_logger.info(message)
|
||||||
|
|
||||||
|
|
||||||
class CustomLogger(HypercornLogger):
|
try:
|
||||||
|
from hypercorn.logging import Logger as HypercornLogger
|
||||||
|
|
||||||
|
class CustomLogger(HypercornLogger):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if self.error_logger:
|
if self.error_logger:
|
||||||
patch_logger(self.error_logger)
|
patch_logger(self.error_logger)
|
||||||
if self.access_logger:
|
if self.access_logger:
|
||||||
patch_logger(self.access_logger)
|
patch_logger(self.access_logger)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
pass
|
118
src/ocab_core/ocab_core/main.py
Normal file
118
src/ocab_core/ocab_core/main.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import traceback
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
|
||||||
|
from ocab_core.lib import register_bot_webhook
|
||||||
|
from ocab_core.logger import CustomLogger, log, setup_logger
|
||||||
|
from ocab_core.modules_system import ModulesManager
|
||||||
|
from ocab_core.modules_system.public_api import get_module
|
||||||
|
from ocab_core.singleton import Singleton
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ocab_modules.standard.config import IConfig
|
||||||
|
|
||||||
|
|
||||||
|
class OCAB:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def init_app(self, bot_modules):
|
||||||
|
setup_logger()
|
||||||
|
singleton = Singleton()
|
||||||
|
|
||||||
|
try:
|
||||||
|
singleton.modules_manager = ModulesManager()
|
||||||
|
|
||||||
|
for module_loader in bot_modules:
|
||||||
|
info = module_loader.info()
|
||||||
|
log(f"Loading {info.name} ({info.id}) module")
|
||||||
|
await singleton.modules_manager.load(module_loader)
|
||||||
|
|
||||||
|
register_config()
|
||||||
|
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
config.load()
|
||||||
|
|
||||||
|
singleton.bot = Bot(token=config.get("core::token"))
|
||||||
|
singleton.dp = Dispatcher(storage=singleton.storage["_fsm_storage"])
|
||||||
|
singleton.dp.include_routers(*singleton.storage["_routers"])
|
||||||
|
|
||||||
|
for middleware in singleton.storage["_outer_message_middlewares"]:
|
||||||
|
singleton.dp.message.outer_middleware.register(middleware)
|
||||||
|
|
||||||
|
await singleton.modules_manager.late_init()
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
if config.get("core::mode") == "WEBHOOK":
|
||||||
|
await self.start_webhook_mode()
|
||||||
|
else:
|
||||||
|
await self.start_long_polling_mode()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
async def start_long_polling_mode(self):
|
||||||
|
singleton = Singleton()
|
||||||
|
await singleton.bot.delete_webhook()
|
||||||
|
await singleton.dp.start_polling(singleton.bot)
|
||||||
|
|
||||||
|
async def start_webhook_mode(self):
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from hypercorn.asyncio import serve
|
||||||
|
from hypercorn.config import Config as HyperConfig
|
||||||
|
except ImportError:
|
||||||
|
log(
|
||||||
|
"Error: FastAPI and Hypercorn are required"
|
||||||
|
"for webhook mode. Please install them."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
singleton = Singleton()
|
||||||
|
app = FastAPI()
|
||||||
|
config = get_module("standard.config", "config")
|
||||||
|
app.mount("/webapp", singleton.storage["webapp"])
|
||||||
|
await register_bot_webhook(app, singleton.bot, singleton.dp)
|
||||||
|
await singleton.bot.set_webhook(config.get("core::webhook::public_url"))
|
||||||
|
hyperConfig = HyperConfig()
|
||||||
|
hyperConfig.bind = [f"0.0.0.0:{config.get("core::webhook::port")}"]
|
||||||
|
hyperConfig.logger_class = CustomLogger
|
||||||
|
await serve(app, hyperConfig)
|
||||||
|
|
||||||
|
|
||||||
|
def register_config():
|
||||||
|
config: "IConfig" = get_module("standard.config", "config")
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::token",
|
||||||
|
"password",
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::mode",
|
||||||
|
"select",
|
||||||
|
options=["WEBHOOK", "LONG_POLLING"],
|
||||||
|
default_value="WEBHOOK",
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::webhook::port",
|
||||||
|
"int",
|
||||||
|
default_value=9000,
|
||||||
|
visible=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
config.register(
|
||||||
|
"core::webhook::public_url",
|
||||||
|
"string",
|
||||||
|
visible=False,
|
||||||
|
)
|
@ -2,7 +2,6 @@ import types
|
|||||||
from _ast import AnnAssign
|
from _ast import AnnAssign
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import flet as ft
|
|
||||||
from aiogram import Bot
|
from aiogram import Bot
|
||||||
from RestrictedPython import (
|
from RestrictedPython import (
|
||||||
RestrictingNodeTransformer,
|
RestrictingNodeTransformer,
|
||||||
@ -97,7 +96,7 @@ def safes_getattr(object, name, default=None, getattr=safer_getattr):
|
|||||||
return getattr(object, name, default)
|
return getattr(object, name, default)
|
||||||
|
|
||||||
|
|
||||||
trusted_settters_classes = [ft.Page, ft.View]
|
trusted_settters_classes = []
|
||||||
|
|
||||||
|
|
||||||
def safes_setattr(self, key, value):
|
def safes_setattr(self, key, value):
|
1612
src/ocab_core/poetry.lock
generated
Normal file
1612
src/ocab_core/poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
src/ocab_core/poetry.toml
Normal file
2
src/ocab_core/poetry.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
26
src/ocab_core/pyproject.toml
Normal file
26
src/ocab_core/pyproject.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "ocab-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Максим Слипенко <maxim@slipenko.com>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "~3.12"
|
||||||
|
aiogram = "^3.10.0"
|
||||||
|
setuptools = "^71.0.1"
|
||||||
|
restrictedpython = "^7.1"
|
||||||
|
semver = "^3.0.2"
|
||||||
|
dataclasses-json = "^0.6.7"
|
||||||
|
fastapi = { version = "^0.111.1", optional = true }
|
||||||
|
hypercorn = { version = "^0.17.3", optional = true }
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
ocab-modules = { path = "../ocab_modules", develop = true }
|
||||||
|
|
||||||
|
[tool.poetry.extras]
|
||||||
|
webhook = ["fastapi", "hypercorn"]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
1
src/ocab_modules/README.md
Normal file
1
src/ocab_modules/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# OCAB Modules
|
1
src/ocab_modules/ocab_modules/__init__.py
Normal file
1
src/ocab_modules/ocab_modules/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .lib import module_loader
|
25
src/ocab_modules/ocab_modules/lib.py
Normal file
25
src/ocab_modules/ocab_modules/lib.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ocab_core.modules_system.loaders.fs_loader import FSLoader
|
||||||
|
from ocab_core.modules_system.loaders.unsafe_fs_loader import UnsafeFSLoader
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_directory(module_name):
|
||||||
|
spec = importlib.util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ImportError(f"Module {module_name} not found")
|
||||||
|
module_path = spec.origin
|
||||||
|
if module_path is None:
|
||||||
|
raise ImportError(f"Module {module_name} has no origin path")
|
||||||
|
return os.path.dirname(module_path)
|
||||||
|
|
||||||
|
|
||||||
|
ocab_modules_path = get_module_directory("ocab_modules")
|
||||||
|
|
||||||
|
|
||||||
|
def module_loader(namespace: str, module_name: str, safe=True):
|
||||||
|
if not safe:
|
||||||
|
return UnsafeFSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
||||||
|
else:
|
||||||
|
return FSLoader(f"{ocab_modules_path}/{namespace}/{module_name}")
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user