mirror of
https://gitflic.ru/project/alt-gnome/karkas.git
synced 2024-12-23 16:23:02 +03:00
style: refactor and translate comments
This commit is contained in:
parent
5950fa3bb8
commit
a6c0433569
@ -4,7 +4,7 @@ RUN pip install poetry
|
|||||||
RUN mkdir -p /app
|
RUN mkdir -p /app
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
# Фикс
|
# Fix
|
||||||
|
|
||||||
RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
||||||
sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
||||||
|
@ -7,11 +7,11 @@ from karkas_core import Karkas
|
|||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
karkas = Karkas()
|
karkas = Karkas()
|
||||||
|
# Argument `safe` has a value `False` because of `super().__init__()`
|
||||||
await karkas.init_app(
|
await karkas.init_app(
|
||||||
[
|
[
|
||||||
block_loader("standard", "config", safe=False),
|
block_loader("standard", "config", safe=False),
|
||||||
block_loader("standard", "command_helper"),
|
block_loader("standard", "command_helper"),
|
||||||
# safe=False из-за super().__init__()
|
|
||||||
block_loader("standard", "filters", safe=False),
|
block_loader("standard", "filters", safe=False),
|
||||||
block_loader("standard", "report"),
|
block_loader("standard", "report"),
|
||||||
block_loader("standard", "welcome", safe=False),
|
block_loader("standard", "welcome", safe=False),
|
||||||
|
@ -4,7 +4,7 @@ RUN pip install poetry
|
|||||||
RUN mkdir -p /app
|
RUN mkdir -p /app
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
# Фикс
|
# Fix
|
||||||
|
|
||||||
RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
RUN sed -i '/karkas-core = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
||||||
sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
sed -i '/karkas-blocks = {/{s/, develop = true//}' /app/src/altlinux/pyproject.toml && \
|
||||||
|
@ -20,6 +20,7 @@ async def main():
|
|||||||
block_loader("external", "create_report_apps"),
|
block_loader("external", "create_report_apps"),
|
||||||
block_loader("standard", "info"),
|
block_loader("standard", "info"),
|
||||||
block_loader("standard", "help"),
|
block_loader("standard", "help"),
|
||||||
|
|
||||||
# block_loader("external", "yandexgpt", safe=False),
|
# block_loader("external", "yandexgpt", safe=False),
|
||||||
#
|
#
|
||||||
# block_loader("standard", "admin"),
|
# block_loader("standard", "admin"),
|
||||||
|
@ -4,7 +4,8 @@ from aiogram import F, Router
|
|||||||
from .handlers import answer_to_message
|
from .handlers import answer_to_message
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
# Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
|
|
||||||
|
# If the message starts with the word "Гномик" ("гномик") or responds to a bot message, `answer_to_message` is called
|
||||||
router.message.register(
|
router.message.register(
|
||||||
answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик")
|
answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик")
|
||||||
)
|
)
|
||||||
|
@ -72,7 +72,7 @@ class YandexGPT:
|
|||||||
response = await self.async_request(
|
response = await self.async_request(
|
||||||
url=url, headers=headers, prompt=request
|
url=url, headers=headers, prompt=request
|
||||||
)
|
)
|
||||||
except Exception as e: # TODO: Переделать обработку ошибок
|
except Exception as e: # TODO: Recreate error handling
|
||||||
# print(e)
|
# print(e)
|
||||||
log(f"Error: {e}")
|
log(f"Error: {e}")
|
||||||
|
|
||||||
@ -216,17 +216,22 @@ class YandexGPT:
|
|||||||
self, text, voice, emotion, speed, format, quality
|
self, text, voice, emotion, speed, format, quality
|
||||||
):
|
):
|
||||||
tts = "tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
|
tts = "tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
|
||||||
# TODO: Сделать функцию TTS
|
# TODO: Make TTS function
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
async def async_yandex_cloud_vision(self, image, features, language):
|
async def async_yandex_cloud_vision(self, image, features, language):
|
||||||
# TODO: Сделать функцию Vision
|
# TODO: Make Vision function
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
async def collect_messages(self, message_id, chat_id):
|
async def collect_messages(self, message_id, chat_id):
|
||||||
|
# Collect a chain of messages in the format:
|
||||||
|
#
|
||||||
|
# [
|
||||||
|
# {"role": "user", "text": "<USER_NAME>: Hello!"},
|
||||||
|
# {"role": "assistant", "text": "Hello!"}
|
||||||
|
# ]
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
# Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"},
|
|
||||||
# {"role": "assistant", "text": "Привет!"}]
|
|
||||||
while True:
|
while True:
|
||||||
message = db_api.get_message_text(chat_id, message_id)
|
message = db_api.get_message_text(chat_id, message_id)
|
||||||
if db_api.get_message_ai_model(chat_id, message_id) != None:
|
if db_api.get_message_ai_model(chat_id, message_id) != None:
|
||||||
@ -244,9 +249,14 @@ class YandexGPT:
|
|||||||
async def collecting_messages_for_history(
|
async def collecting_messages_for_history(
|
||||||
self, start_message_id, end_message_id, chat_id
|
self, start_message_id, end_message_id, chat_id
|
||||||
):
|
):
|
||||||
|
# Collect a chain of messages in the format:
|
||||||
|
#
|
||||||
|
# [
|
||||||
|
# {"role": "user", "text": "<USER_NAME>: Hello!"},
|
||||||
|
# {"role": "assistant", "text": "Hello!"}
|
||||||
|
# ]
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
# Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"},
|
|
||||||
# {"role": "assistant", "text": "Привет!"}]
|
|
||||||
while True:
|
while True:
|
||||||
message = db_api.get_message_text(chat_id, start_message_id)
|
message = db_api.get_message_text(chat_id, start_message_id)
|
||||||
if db_api.get_message_ai_model(chat_id, start_message_id) != None:
|
if db_api.get_message_ai_model(chat_id, start_message_id) != None:
|
||||||
|
@ -41,23 +41,23 @@ async def chat_not_in_approve_list(message: Message, bot: Bot):
|
|||||||
|
|
||||||
|
|
||||||
async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
|
async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
|
||||||
# *, can_send_messages: bool | None = None, can_send_audios: bool | None = None, can_send_documents: bool | None = None, can_send_photos: bool | None = None, can_send_videos: bool | None = None, can_send_video_notes: bool | None = None, can_send_voice_notes: bool | None = None, can_send_polls: bool | None = None, can_send_other_messages: bool | None = None, can_add_web_page_previews: bool | None = None, can_change_info: bool | None = None, can_invite_users: bool | None = None, can_pin_messages: bool | None = None, can_manage_topics: bool | None = None, **extra_data: Any)
|
# TODO: type variable using `typing`
|
||||||
|
|
||||||
mutePermissions = {
|
mutePermissions = {
|
||||||
"can_send_messages": False,
|
"can_send_messages": False, # bool | None
|
||||||
"can_send_audios": False,
|
"can_send_audios": False, # bool | None
|
||||||
"can_send_documents": False,
|
"can_send_documents": False, # bool | None
|
||||||
"can_send_photos": False,
|
"can_send_photos": False, # bool | None
|
||||||
"can_send_videos": False,
|
"can_send_videos": False, # bool | None
|
||||||
"can_send_video_notes": False,
|
"can_send_video_notes": False, # bool | None
|
||||||
"can_send_voice_notes": False,
|
"can_send_voice_notes": False, # bool | None
|
||||||
"can_send_polls": False,
|
"can_send_polls": False, # bool | None
|
||||||
"can_send_other_messages": False,
|
"can_send_other_messages": False, # bool | None
|
||||||
"can_add_web_page_previews": False,
|
"can_add_web_page_previews": False, # bool | None
|
||||||
"can_change_info": False,
|
"can_change_info": False, # bool | None
|
||||||
"can_invite_users": False,
|
"can_invite_users": False, # bool | None
|
||||||
"can_pin_messages": False,
|
"can_pin_messages": False, # bool | None
|
||||||
"can_manage_topics": False,
|
"can_manage_topics": False, # bool | None
|
||||||
|
# **extra_data: Any
|
||||||
}
|
}
|
||||||
end_time = time + int(time.time())
|
end_time = time + int(time.time())
|
||||||
await bot.restrict_chat_member(
|
await bot.restrict_chat_member(
|
||||||
|
@ -17,7 +17,7 @@ from .handlers import (
|
|||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
# Если сообщение содержит какой либо текст и выполняется фильтр ChatNotInApproveFilter, то вызывается функция chat_not_in_approve_list
|
# If message is not empty and the `ChatNotInApproveFilter` is applied, then the `chat_not_in_approve_list` function is called
|
||||||
router.message.register(chat_not_in_approve_list, ChatNotInApproveFilter(), F.text)
|
router.message.register(chat_not_in_approve_list, ChatNotInApproveFilter(), F.text)
|
||||||
|
|
||||||
router.message.register(get_chat_id, ChatModerOrAdminFilter(), Command("chatID"))
|
router.message.register(get_chat_id, ChatModerOrAdminFilter(), Command("chatID"))
|
||||||
|
@ -74,7 +74,7 @@ class ConfigManager:
|
|||||||
for key, value in updates.items():
|
for key, value in updates.items():
|
||||||
self._check_rights(key, module_id, "set")
|
self._check_rights(key, module_id, "set")
|
||||||
if key in self._metadata:
|
if key in self._metadata:
|
||||||
# TODO: add checks to validate the type and value based on metadata
|
# TODO: add metadata-based type and value validation
|
||||||
self._config[key] = value
|
self._config[key] = value
|
||||||
else:
|
else:
|
||||||
raise KeyError(f"Key {key} is not registered.")
|
raise KeyError(f"Key {key} is not registered.")
|
||||||
|
@ -206,7 +206,7 @@ def get_miniapp_blueprint(config: "ConfigManager", prefix: str):
|
|||||||
"-",
|
"-",
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: добавить валидацию значений
|
# TODO: add values validation
|
||||||
|
|
||||||
updated_settings = {}
|
updated_settings = {}
|
||||||
for value, id_dict in zip(values, keys):
|
for value, id_dict in zip(values, keys):
|
||||||
@ -217,7 +217,8 @@ def get_miniapp_blueprint(config: "ConfigManager", prefix: str):
|
|||||||
meta = config.get_meta(key)
|
meta = config.get_meta(key)
|
||||||
|
|
||||||
if meta["type"] == "password":
|
if meta["type"] == "password":
|
||||||
if value: # Only update if a new value is provided
|
# Is updated only if new value is specified
|
||||||
|
if value:
|
||||||
updated_settings[key] = value
|
updated_settings[key] = value
|
||||||
else:
|
else:
|
||||||
updated_settings[key] = value
|
updated_settings[key] = value
|
||||||
|
@ -94,7 +94,7 @@ class ChatIDFilter(BaseFilter):
|
|||||||
|
|
||||||
approved_chats = self.approved_chats or get_approved_chat_id()
|
approved_chats = self.approved_chats or get_approved_chat_id()
|
||||||
|
|
||||||
# Если список для фильтрации пуст - разрешаем всем.
|
# If filtering list is empty, allow anything
|
||||||
if len(approved_chats) == 0:
|
if len(approved_chats) == 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -26,8 +26,6 @@ except Exception:
|
|||||||
COMMAND_HELPER_MODULE_LOADED = False
|
COMMAND_HELPER_MODULE_LOADED = False
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Уважительная просьба не удалять и не изменять нижеизложенный текст
|
|
||||||
# без согласия команды проекта «Каркас».
|
|
||||||
# We kindly ask you not to delete or change the following text without
|
# We kindly ask you not to delete or change the following text without
|
||||||
# the consent of the «Karkas» project team.
|
# the consent of the «Karkas» project team.
|
||||||
FOOTER = """===============
|
FOOTER = """===============
|
||||||
|
@ -28,9 +28,6 @@ async def get_info_answer_by_id(message: Message, bot: Bot, user_id: int):
|
|||||||
|
|
||||||
|
|
||||||
async def get_user_info(message: Message, bot: Bot):
|
async def get_user_info(message: Message, bot: Bot):
|
||||||
# Проверяем содержимое сообщения, если содержит вторым элементом тег пользователя, то выводим информацию о нем
|
|
||||||
# Если сообщение отвечает на другое сообщение, то выводим информацию о пользователе, на чье сообщение был ответ
|
|
||||||
# Если это бот то выводим информацию, что это бот и какая модель yandexgpt используется
|
|
||||||
try:
|
try:
|
||||||
if message.reply_to_message:
|
if message.reply_to_message:
|
||||||
user_id = message.reply_to_message.from_user.id
|
user_id = message.reply_to_message.from_user.id
|
||||||
|
@ -8,7 +8,7 @@ from flask import request
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dash import Dash
|
from dash import Dash
|
||||||
|
|
||||||
# TODO: добавить прокидывание BASE_PATH, т.к. это параметр из настроек
|
# TODO: add `BASE_PATH` transfer, because this is a parameter from the settings
|
||||||
|
|
||||||
WEBAPP_LOADER_TEMPLATE = """
|
WEBAPP_LOADER_TEMPLATE = """
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -56,7 +56,6 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
|
|||||||
dbc.icons.BOOTSTRAP,
|
dbc.icons.BOOTSTRAP,
|
||||||
],
|
],
|
||||||
external_scripts=[
|
external_scripts=[
|
||||||
#
|
|
||||||
"https://telegram.org/js/telegram-web-app.js"
|
"https://telegram.org/js/telegram-web-app.js"
|
||||||
],
|
],
|
||||||
server=server,
|
server=server,
|
||||||
@ -156,7 +155,7 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
|
|||||||
|
|
||||||
setup_auth_clientcallbacks(app)
|
setup_auth_clientcallbacks(app)
|
||||||
|
|
||||||
# Открытие на кнопку меню
|
# Open on the menu button
|
||||||
app.clientside_callback(
|
app.clientside_callback(
|
||||||
"""
|
"""
|
||||||
function(n_clicks) {
|
function(n_clicks) {
|
||||||
@ -173,7 +172,7 @@ def create_dash_app(requests_pathname_prefix: str = None) -> dash.Dash:
|
|||||||
Input("open-offcanvas", "n_clicks"),
|
Input("open-offcanvas", "n_clicks"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Закрываем offcanvas при клике на ссылку в меню
|
# Closing `offcanvas` when clicking on the link in the menu
|
||||||
app.clientside_callback(
|
app.clientside_callback(
|
||||||
"""
|
"""
|
||||||
function(n_clicks) {
|
function(n_clicks) {
|
||||||
|
@ -67,8 +67,10 @@ class TestRoles(unittest.IsolatedAsyncioTestCase):
|
|||||||
)
|
)
|
||||||
cls.assertEqual(await cls.roles.get_role_name(cls.roles.user_role_id), "USER")
|
cls.assertEqual(await cls.roles.get_role_name(cls.roles.user_role_id), "USER")
|
||||||
cls.assertEqual(await cls.roles.get_role_name(cls.roles.bot_role_id), "BOT")
|
cls.assertEqual(await cls.roles.get_role_name(cls.roles.bot_role_id), "BOT")
|
||||||
|
|
||||||
|
# Non-existent role ID
|
||||||
with cls.assertRaises(ValueError):
|
with cls.assertRaises(ValueError):
|
||||||
await cls.roles.get_role_name(999) # Несуществующий ID роли
|
await cls.roles.get_role_name(999)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
|
@ -9,9 +9,8 @@ class ChatStats(Table):
|
|||||||
|
|
||||||
|
|
||||||
class Messages(Table):
|
class Messages(Table):
|
||||||
# Временная мера, пока не примут
|
# Key format: `{message_chat_id}-{message_id}`
|
||||||
# https://github.com/piccolo-orm/piccolo/pull/984
|
# (A temporary measure until https://github.com/piccolo-orm/piccolo/pull/984 is accepted)
|
||||||
# {message_chat_id}-{message_id}
|
|
||||||
key = Text(primary_key=True)
|
key = Text(primary_key=True)
|
||||||
|
|
||||||
chat_id = Integer()
|
chat_id = Integer()
|
||||||
@ -23,9 +22,8 @@ class Messages(Table):
|
|||||||
|
|
||||||
|
|
||||||
class UserStats(Table):
|
class UserStats(Table):
|
||||||
# Временная мера, пока не примут
|
# Key format: `{chat_id}-{user_id}`
|
||||||
# https://github.com/piccolo-orm/piccolo/pull/984
|
# (A temporary measure until https://github.com/piccolo-orm/piccolo/pull/984 is accepted)
|
||||||
# {chat_id}-{user_id}
|
|
||||||
key = Text(primary_key=True)
|
key = Text(primary_key=True)
|
||||||
|
|
||||||
chat_id = Integer()
|
chat_id = Integer()
|
||||||
|
@ -80,7 +80,7 @@ last_success = {}
|
|||||||
|
|
||||||
|
|
||||||
async def new_member_handler(event: "ChatMemberUpdated", bot: Bot):
|
async def new_member_handler(event: "ChatMemberUpdated", bot: Bot):
|
||||||
# НЕ СРАБОТАЕТ, ЕСЛИ ЧЕЛОВЕК УЖЕ ОГРАНИЧЕН В ПРАВАХ (RESTRICTED)
|
# WARN: IT WON'T WORK IF THE PERSON IS ALREADY RESTRICTED
|
||||||
if event.new_chat_member.status == ChatMemberStatus.MEMBER:
|
if event.new_chat_member.status == ChatMemberStatus.MEMBER:
|
||||||
task = task_manager.build_random_task(event, bot)
|
task = task_manager.build_random_task(event, bot)
|
||||||
keys = await task.run()
|
keys = await task.run()
|
||||||
@ -353,7 +353,7 @@ async def module_init():
|
|||||||
handle_inline_button_verification
|
handle_inline_button_verification
|
||||||
)
|
)
|
||||||
|
|
||||||
# Нельзя применить ChatIDFilter из-за отстутсвия id чата
|
# ChatIDFilter can't be applied because there is no chat ID
|
||||||
router.poll_answer()(handle_poll_verification)
|
router.poll_answer()(handle_poll_verification)
|
||||||
|
|
||||||
register_router(router)
|
register_router(router)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
# TODO: rewrite for compatibility with English
|
||||||
def get_plural_form(number, singular, genitive_singular, plural):
|
def get_plural_form(number, singular, genitive_singular, plural):
|
||||||
if 11 <= number % 100 <= 19:
|
if 11 <= number % 100 <= 19:
|
||||||
return f"{number} {plural}"
|
return f"{number} {plural}"
|
||||||
@ -11,14 +12,12 @@ def get_plural_form(number, singular, genitive_singular, plural):
|
|||||||
|
|
||||||
class MultiKeyDict:
|
class MultiKeyDict:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.value_to_keys = {} # Словарь значений и связанных с ними ключей
|
self.value_to_keys = {}
|
||||||
self.key_to_value = {} # Словарь ключей и связанных с ними значений
|
self.key_to_value = {}
|
||||||
|
|
||||||
def add(self, value, keys):
|
def add(self, value, keys):
|
||||||
# Добавляем значение в словарь с множеством ключей
|
|
||||||
self.value_to_keys[value] = set(keys)
|
self.value_to_keys[value] = set(keys)
|
||||||
|
|
||||||
# Для каждого ключа создаем запись в словаре key_to_value
|
|
||||||
for key in keys:
|
for key in keys:
|
||||||
self.key_to_value[key] = value
|
self.key_to_value[key] = value
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ class UnsafeFSLoader(AbstractLoader):
|
|||||||
|
|
||||||
full_path = self._resolve_module_from_path(".")
|
full_path = self._resolve_module_from_path(".")
|
||||||
|
|
||||||
|
# TODO: remove duplication
|
||||||
if full_path.name == "__init__.py":
|
if full_path.name == "__init__.py":
|
||||||
module_name = full_path.parent.name
|
module_name = full_path.parent.name
|
||||||
path = full_path.parent.parent.absolute()
|
path = full_path.parent.parent.absolute()
|
||||||
@ -46,16 +47,12 @@ class UnsafeFSLoader(AbstractLoader):
|
|||||||
module_name = full_path.stem
|
module_name = full_path.stem
|
||||||
path = full_path.parent.absolute()
|
path = full_path.parent.absolute()
|
||||||
|
|
||||||
# Добавляем директорию модуля в sys.path
|
|
||||||
sys.path.insert(0, str(path))
|
sys.path.insert(0, str(path))
|
||||||
|
|
||||||
# Загружаем спецификацию модуля
|
|
||||||
spec = importlib.util.spec_from_file_location(module_name, full_path)
|
spec = importlib.util.spec_from_file_location(module_name, full_path)
|
||||||
|
|
||||||
# Создаем модуль
|
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
|
||||||
# Выполняем модуль
|
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
@ -93,7 +93,7 @@ class ModulesManager:
|
|||||||
async def load(self, loader: AbstractLoader):
|
async def load(self, loader: AbstractLoader):
|
||||||
info = loader.info()
|
info = loader.info()
|
||||||
|
|
||||||
# Check if the module is already loaded
|
# Is the module loaded
|
||||||
if any(mod["info"].id == info.id for mod in self.modules):
|
if any(mod["info"].id == info.id for mod in self.modules):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -48,13 +48,10 @@ class UnsafeFSLoader:
|
|||||||
|
|
||||||
sys.path.insert(0, str(path))
|
sys.path.insert(0, str(path))
|
||||||
|
|
||||||
# Загружаем спецификацию модуля
|
|
||||||
spec = importlib.util.spec_from_file_location(module_name, full_path)
|
spec = importlib.util.spec_from_file_location(module_name, full_path)
|
||||||
|
|
||||||
# Создаем модуль
|
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
|
||||||
# Выполняем модуль
|
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
Loading…
Reference in New Issue
Block a user