From 8f2adbfbc47b4564b3bb34ee1b2196972faa3442 Mon Sep 17 00:00:00 2001
From: Maxim Slipenko <maxim@slipenko.com>
Date: Mon, 26 Aug 2024 17:01:56 +0300
Subject: [PATCH] style: enable flake8-type-checking and move imports to
 TYPE_CHECKING

---
 .flake8                                       |  2 ++
 .pre-commit-config.yaml                       |  2 ++
 .../create_report_apps/create_report.py       | 18 ++++++----
 .../karkas_blocks/standard/chats/main.py      | 12 ++++---
 .../standard/config/miniapp_ui.py             | 10 +++---
 .../karkas_blocks/standard/help/main.py       |  5 +--
 .../standard/miniapp/dash_telegram_auth.py    |  8 +++--
 .../karkas_blocks/standard/statistics/main.py | 16 +++++----
 .../karkas_blocks/standard/users/main.py      | 12 ++++---
 .../karkas_blocks/standard/welcome/main.py    |  9 ++---
 .../welcome/verifications_methods/base.py     | 11 +++---
 .../welcome/verifications_methods/simple.py   |  7 ++--
 .../welcome/verifications_methods/utils.py    |  9 +++--
 src/karkas_core/karkas_core/lib.py            | 34 ++++++++-----------
 .../modules_system/loaders/base.py            |  8 +++--
 .../modules_system/public_api/public_api.py   | 10 +++---
 .../karkas_core/modules_system/safe/policy.py |  8 +++--
 src/karkas_core/karkas_core/singleton.py      | 14 +++++---
 18 files changed, 115 insertions(+), 80 deletions(-)

diff --git a/.flake8 b/.flake8
index 4e2b181..fb9ec7c 100644
--- a/.flake8
+++ b/.flake8
@@ -4,3 +4,5 @@ per-file-ignores =
 max-line-length = 88
 count = true
 extend-ignore = E203,E701
+
+extend-select = TC010,TC200
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7167028..6babcf4 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -29,6 +29,8 @@ repos:
     rev: 7.1.0 # sync:flake8:poetry.lock
     hooks:
       - id: flake8
+        additional_dependencies:
+          - flake8-type-checking
   - repo: https://github.com/PyCQA/bandit
     rev: 1.7.9 # sync:bandit:poetry.lock
     hooks:
diff --git a/src/karkas_blocks/karkas_blocks/external/create_report_apps/create_report.py b/src/karkas_blocks/karkas_blocks/external/create_report_apps/create_report.py
index 9eaf223..22b1855 100644
--- a/src/karkas_blocks/karkas_blocks/external/create_report_apps/create_report.py
+++ b/src/karkas_blocks/karkas_blocks/external/create_report_apps/create_report.py
@@ -1,6 +1,7 @@
+from typing import TYPE_CHECKING
+
 from aiogram import Bot, Router
 from aiogram.enums import ParseMode
-from aiogram.fsm.context import FSMContext
 from aiogram.fsm.state import State, StatesGroup
 from aiogram.types import (
     BufferedInputFile,
@@ -14,6 +15,9 @@ from karkas_core.modules_system.public_api import Utils, get_fsm_context
 
 from .report import Report
 
+if TYPE_CHECKING:
+    from aiogram.fsm.context import FSMContext
+
 router = Router()
 
 
@@ -65,7 +69,7 @@ app_info_message = """Укажите название и версию прило
 
 
 @router.message(ReportState.input_system_info)
-async def system_entered(message: Message, state: FSMContext):
+async def system_entered(message: Message, state: "FSMContext"):
     await state.update_data(system=message.text)
     await message.answer(
         text=app_info_message,
@@ -80,28 +84,28 @@ step_by_step_message = (
 
 
 @router.message(ReportState.input_app_name)
-async def app_name_entered(message: Message, state: FSMContext):
+async def app_name_entered(message: Message, state: "FSMContext"):
     await state.update_data(app=message.text)
     await message.answer(text=step_by_step_message)
     await state.set_state(ReportState.input_problem_step_by_step)
 
 
 @router.message(ReportState.input_problem_step_by_step)
-async def problem_step_by_step_entered(message: Message, state: FSMContext):
+async def problem_step_by_step_entered(message: Message, state: "FSMContext"):
     await state.update_data(problem_step_by_step=message.text)
     await message.answer(text="Опиши, что произошло (фактический результат).")
     await state.set_state(ReportState.input_actual_result)
 
 
 @router.message(ReportState.input_actual_result)
-async def actual_result_entered(message: Message, state: FSMContext):
+async def actual_result_entered(message: Message, state: "FSMContext"):
     await state.update_data(actual=message.text)
     await message.answer(text="Опиши ожидаемый результат.")
     await state.set_state(ReportState.input_expected_result)
 
 
 @router.message(ReportState.input_expected_result)
-async def expected_result_entered(message: Message, state: FSMContext):
+async def expected_result_entered(message: Message, state: "FSMContext"):
     await state.update_data(expected=message.text)
     await message.answer(
         text="Если есть дополнительная информация, то напиши ее.",
@@ -116,7 +120,7 @@ async def expected_result_entered(message: Message, state: FSMContext):
 
 
 @router.message(ReportState.input_additional_info)
-async def additional_info_entered(message: Message, state: FSMContext):
+async def additional_info_entered(message: Message, state: "FSMContext"):
     if message.text == "Дополнительной информации нет":
         additional_info = ""
     else:
diff --git a/src/karkas_blocks/karkas_blocks/standard/chats/main.py b/src/karkas_blocks/karkas_blocks/standard/chats/main.py
index f0b8a5b..1a52807 100644
--- a/src/karkas_blocks/karkas_blocks/standard/chats/main.py
+++ b/src/karkas_blocks/karkas_blocks/standard/chats/main.py
@@ -1,12 +1,14 @@
-from typing import Any, Awaitable, Callable, Dict
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
 
 from aiogram import BaseMiddleware
-from aiogram.types import Chat, TelegramObject
 
 from .db.tables import ChatInfo
 
+if TYPE_CHECKING:
+    from aiogram.types import Chat, TelegramObject
 
-async def update_chat_info(chat: Chat):
+
+async def update_chat_info(chat: "Chat"):
     chat_name = chat.title if chat.type != "private" else ""
 
     await ChatInfo.insert(
@@ -24,8 +26,8 @@ async def update_chat_info(chat: Chat):
 class ChatsMiddleware(BaseMiddleware):
     async def __call__(
         self,
-        handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
-        event: TelegramObject,
+        handler: Callable[["TelegramObject", Dict[str, Any]], Awaitable[Any]],
+        event: "TelegramObject",
         data: Dict[str, Any],
     ) -> Any:
         chat = event.chat
diff --git a/src/karkas_blocks/karkas_blocks/standard/config/miniapp_ui.py b/src/karkas_blocks/karkas_blocks/standard/config/miniapp_ui.py
index 799be60..420bd8f 100644
--- a/src/karkas_blocks/karkas_blocks/standard/config/miniapp_ui.py
+++ b/src/karkas_blocks/karkas_blocks/standard/config/miniapp_ui.py
@@ -1,8 +1,6 @@
 import asyncio
 from typing import TYPE_CHECKING
 
-from .config_manager import ConfigManager
-
 try:
     import dash_bootstrap_components as dbc
     import flask
@@ -17,8 +15,10 @@ from karkas_core.modules_system.public_api import get_module
 if TYPE_CHECKING:
     from karkas_blocks.standard.roles import Roles as IRoles
 
+    from .config_manager import ConfigManager
 
-def create_control(key: str, config: ConfigManager):
+
+def create_control(key: str, config: "ConfigManager"):
     value = config.get(key)
     meta = config.get_meta(key)
 
@@ -85,7 +85,7 @@ def create_control(key: str, config: ConfigManager):
     return dbc.Row(row, className="mb-3 mx-1")
 
 
-def build_settings_tree(config: ConfigManager):
+def build_settings_tree(config: "ConfigManager"):
     tree = {}
 
     for key, value in config._metadata.items():
@@ -134,7 +134,7 @@ def create_settings_components(tree, level=0):
     return components
 
 
-def get_miniapp_blueprint(config: ConfigManager, prefix: str):
+def get_miniapp_blueprint(config: "ConfigManager", prefix: str):
     Roles: "type[IRoles]" = get_module("standard.roles", "Roles")
 
     roles = Roles()
diff --git a/src/karkas_blocks/karkas_blocks/standard/help/main.py b/src/karkas_blocks/karkas_blocks/standard/help/main.py
index 4bf124f..5299298 100644
--- a/src/karkas_blocks/karkas_blocks/standard/help/main.py
+++ b/src/karkas_blocks/karkas_blocks/standard/help/main.py
@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING
 
 from aiogram import Router
 from aiogram.filters import Command
-from aiogram.types import Message
 
 from karkas_core.modules_system.public_api import (
     get_metainfo,
@@ -12,6 +11,8 @@ from karkas_core.modules_system.public_api import (
 )
 
 if TYPE_CHECKING:
+    from aiogram.types import Message
+
     from karkas_blocks.standard.config import IConfig
 
 config: "IConfig" = get_module("standard.config", "config")
@@ -47,7 +48,7 @@ def format_commands(commands_dict):
     return "\n".join(formatted_commands)
 
 
-async def help(message: Message):
+async def help(message: "Message"):
     commands = ""
     version = ""
 
diff --git a/src/karkas_blocks/karkas_blocks/standard/miniapp/dash_telegram_auth.py b/src/karkas_blocks/karkas_blocks/standard/miniapp/dash_telegram_auth.py
index 2d5a928..3e84cb7 100644
--- a/src/karkas_blocks/karkas_blocks/standard/miniapp/dash_telegram_auth.py
+++ b/src/karkas_blocks/karkas_blocks/standard/miniapp/dash_telegram_auth.py
@@ -1,9 +1,13 @@
+from typing import TYPE_CHECKING
+
 import flask
 from aiogram.utils.web_app import safe_parse_webapp_init_data
-from dash import Dash
 from dash_extensions.enrich import Input, Output
 from flask import request
 
+if TYPE_CHECKING:
+    from dash import Dash
+
 # TODO: добавить прокидывание BASE_PATH, т.к. это параметр из настроек
 
 WEBAPP_LOADER_TEMPLATE = """
@@ -112,7 +116,7 @@ def get_auth_server(bot_token: str):
     return server
 
 
-def setup_auth_clientcallbacks(app: Dash):
+def setup_auth_clientcallbacks(app: "Dash"):
     app.clientside_callback(
         """
         function(n_intervals) {
diff --git a/src/karkas_blocks/karkas_blocks/standard/statistics/main.py b/src/karkas_blocks/karkas_blocks/standard/statistics/main.py
index 7e85deb..e0cd72c 100644
--- a/src/karkas_blocks/karkas_blocks/standard/statistics/main.py
+++ b/src/karkas_blocks/karkas_blocks/standard/statistics/main.py
@@ -1,12 +1,14 @@
-from typing import Any, Awaitable, Callable, Dict
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
 
 from aiogram import BaseMiddleware
-from aiogram.types import Message, TelegramObject
 
 from .db.tables import ChatStats, Messages, UserStats
 
+if TYPE_CHECKING:
+    from aiogram.types import Message, TelegramObject
 
-async def update_chat_stats(event: Message):
+
+async def update_chat_stats(event: "Message"):
     await ChatStats.insert(
         ChatStats(chat_id=event.chat.id, date=event.date, messages_count=1)
     ).on_conflict(
@@ -18,7 +20,7 @@ async def update_chat_stats(event: Message):
     ).run()
 
 
-async def update_user_stats(event: Message):
+async def update_user_stats(event: "Message"):
     await UserStats.insert(
         UserStats(
             key=f"{event.chat.id}-{event.from_user.id}",
@@ -36,7 +38,7 @@ async def update_user_stats(event: Message):
     ).run()
 
 
-async def save_messages(event: Message):
+async def save_messages(event: "Message"):
     await Messages.insert(
         Messages(
             key=f"{event.chat.id}-{event.message_id}",
@@ -54,8 +56,8 @@ async def save_messages(event: Message):
 class StatisticsMiddleware(BaseMiddleware):
     async def __call__(
         self,
-        handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
-        event: TelegramObject,
+        handler: Callable[["TelegramObject", Dict[str, Any]], Awaitable[Any]],
+        event: "TelegramObject",
         data: Dict[str, Any],
     ) -> Any:
 
diff --git a/src/karkas_blocks/karkas_blocks/standard/users/main.py b/src/karkas_blocks/karkas_blocks/standard/users/main.py
index 6c88781..e74b1ba 100644
--- a/src/karkas_blocks/karkas_blocks/standard/users/main.py
+++ b/src/karkas_blocks/karkas_blocks/standard/users/main.py
@@ -1,12 +1,14 @@
-from typing import Any, Awaitable, Callable, Dict
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
 
 from aiogram import BaseMiddleware
-from aiogram.types import TelegramObject, User
 
 from .db.tables import UserInfo
 
+if TYPE_CHECKING:
+    from aiogram.types import TelegramObject, User
 
-async def update_user_info(user: User):
+
+async def update_user_info(user: "User"):
     if user.last_name is None:
         user_name = user.first_name
     else:
@@ -26,8 +28,8 @@ async def update_user_info(user: User):
 class UsersMiddleware(BaseMiddleware):
     async def __call__(
         self,
-        handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
-        event: TelegramObject,
+        handler: Callable[["TelegramObject", Dict[str, Any]], Awaitable[Any]],
+        event: "TelegramObject",
         data: Dict[str, Any],
     ) -> Any:
         user = event.from_user
diff --git a/src/karkas_blocks/karkas_blocks/standard/welcome/main.py b/src/karkas_blocks/karkas_blocks/standard/welcome/main.py
index bac7446..2f4acba 100644
--- a/src/karkas_blocks/karkas_blocks/standard/welcome/main.py
+++ b/src/karkas_blocks/karkas_blocks/standard/welcome/main.py
@@ -7,7 +7,6 @@ from aiogram import Bot, Router, types
 from aiogram.enums import ChatMemberStatus, ParseMode
 from aiogram.exceptions import TelegramBadRequest
 from aiogram.filters import JOIN_TRANSITION, LEAVE_TRANSITION, ChatMemberUpdatedFilter
-from aiogram.types import ChatMemberUpdated, PollAnswer
 
 from karkas_core.modules_system.public_api import get_module, log, register_router
 
@@ -22,6 +21,8 @@ from .verifications_methods.simple import (
 from .verifications_methods.utils import user_mention
 
 if TYPE_CHECKING:
+    from aiogram.types import ChatMemberUpdated, PollAnswer
+
     from karkas_blocks.standard.config import IConfig
     from karkas_blocks.standard.filters import ChatIDFilter as IChatIDFilter
 
@@ -78,7 +79,7 @@ verification_tasks = MultiKeyDict()
 last_success = {}
 
 
-async def new_member_handler(event: ChatMemberUpdated, bot: Bot):
+async def new_member_handler(event: "ChatMemberUpdated", bot: Bot):
     # НЕ СРАБОТАЕТ, ЕСЛИ ЧЕЛОВЕК УЖЕ ОГРАНИЧЕН В ПРАВАХ (RESTRICTED)
     if event.new_chat_member.status == ChatMemberStatus.MEMBER:
         task = task_manager.build_random_task(event, bot)
@@ -87,7 +88,7 @@ async def new_member_handler(event: ChatMemberUpdated, bot: Bot):
         verification_tasks.add(task, keys)
 
 
-async def left_member_handler(event: ChatMemberUpdated, bot: Bot):
+async def left_member_handler(event: "ChatMemberUpdated", bot: Bot):
     user_id = event.from_user.id
     chat_id = event.chat.id
 
@@ -144,7 +145,7 @@ async def success_end(task: BaseTask):
         last_success[task.from_chat_id] = message.message_id
 
 
-async def handle_poll_verification(answer: PollAnswer, bot: Bot):
+async def handle_poll_verification(answer: "PollAnswer", bot: Bot):
     key = key_from_poll(answer.poll_id)
     if not verification_tasks.exists(key):
         return
diff --git a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/base.py b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/base.py
index afc3853..f9be39a 100644
--- a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/base.py
+++ b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/base.py
@@ -1,21 +1,24 @@
 import asyncio
 from functools import wraps
+from typing import TYPE_CHECKING
 
-from aiogram import Bot
 from aiogram.exceptions import TelegramBadRequest
 from aiogram.filters.callback_data import CallbackData
-from aiogram.types import ChatMemberUpdated
 
 from karkas_core.modules_system.public_api import log
 
 from .utils import mute_user, unmute_user
 
+if TYPE_CHECKING:
+    from aiogram import Bot
+    from aiogram.types import ChatMemberUpdated
+
 
 class BaseTask:
     def __init__(
         self,
-        event: ChatMemberUpdated,
-        bot: Bot,
+        event: "ChatMemberUpdated",
+        bot: "Bot",
         timeout_func=None,
         attempt_number=1,
         max_attempts=1,
diff --git a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/simple.py b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/simple.py
index f396822..e82f6b8 100644
--- a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/simple.py
+++ b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/simple.py
@@ -1,6 +1,6 @@
 from string import Template
+from typing import TYPE_CHECKING
 
-from aiogram import Bot
 from aiogram.enums import ParseMode, PollType
 from aiogram.types import ChatMemberUpdated, InlineKeyboardButton, InlineKeyboardMarkup
 
@@ -8,6 +8,9 @@ from ..utils import get_plural_form, key_from_poll, key_from_user_chat
 from .base import BaseTask, VerificationCallback, mute_while_task
 from .utils import user_mention
 
+if TYPE_CHECKING:
+    from aiogram import Bot
+
 
 class SimpleBaseTask(BaseTask):
     pass
@@ -120,7 +123,7 @@ class SimplePollTask(SimpleVariantsBaseTask):
     def __init__(
         self,
         event: ChatMemberUpdated,
-        bot: Bot,
+        bot: "Bot",
         timeout_func=None,
         attempt_number=1,
         max_attempts=1,
diff --git a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/utils.py b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/utils.py
index f544735..0365f6f 100644
--- a/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/utils.py
+++ b/src/karkas_blocks/karkas_blocks/standard/welcome/verifications_methods/utils.py
@@ -1,9 +1,12 @@
 import time
+from typing import TYPE_CHECKING
 
-from aiogram import Bot
 from aiogram.enums import ParseMode
 from aiogram.types import ChatPermissions, User
 
+if TYPE_CHECKING:
+    from aiogram import Bot
+
 
 def user_mention(user: User, mode=ParseMode.HTML):
     if mode == ParseMode.HTML:
@@ -14,7 +17,7 @@ def user_mention(user: User, mode=ParseMode.HTML):
         raise ValueError(f"Unknown parse mode {mode}")
 
 
-async def mute_user(chat_id, user_id, until, bot: Bot):
+async def mute_user(chat_id, user_id, until, bot: "Bot"):
     end_time = until + int(time.time())
     await bot.restrict_chat_member(
         chat_id,
@@ -40,7 +43,7 @@ async def mute_user(chat_id, user_id, until, bot: Bot):
     )
 
 
-async def unmute_user(chat_id, user_id, bot: Bot):
+async def unmute_user(chat_id, user_id, bot: "Bot"):
     await bot.restrict_chat_member(
         chat_id,
         user_id,
diff --git a/src/karkas_core/karkas_core/lib.py b/src/karkas_core/karkas_core/lib.py
index 7cc7acb..6608524 100644
--- a/src/karkas_core/karkas_core/lib.py
+++ b/src/karkas_core/karkas_core/lib.py
@@ -1,10 +1,14 @@
 import importlib
 import os
 import traceback
+from typing import TYPE_CHECKING
 
-from aiogram import Bot, Dispatcher
 from aiogram.types import Update
 
+if TYPE_CHECKING:
+    from aiogram import Bot, Dispatcher
+    from fastapi import FastAPI, Request
+
 
 def get_module_directory(module_name):
     spec = importlib.util.find_spec(module_name)
@@ -16,23 +20,15 @@ def get_module_directory(module_name):
     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}
 
-    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}
 
-            return {"ok": True}
-
-        app.post("/webhook")(handle_webhook)
-
-except ImportError:
-    pass
+    app.post("/webhook")(handle_webhook)
diff --git a/src/karkas_core/karkas_core/modules_system/loaders/base.py b/src/karkas_core/karkas_core/modules_system/loaders/base.py
index ebcb89e..9696931 100644
--- a/src/karkas_core/karkas_core/modules_system/loaders/base.py
+++ b/src/karkas_core/karkas_core/modules_system/loaders/base.py
@@ -1,9 +1,11 @@
-import types
 from dataclasses import dataclass
-from typing import Dict, List, Optional, Union
+from typing import TYPE_CHECKING, Dict, List, Optional, Union
 
 from dataclasses_json import dataclass_json
 
+if TYPE_CHECKING:
+    import types
+
 
 @dataclass_json
 @dataclass
@@ -39,5 +41,5 @@ class AbstractLoader:
     def info(self) -> ModuleInfo:
         raise NotImplementedError
 
-    def load(self) -> types.ModuleType:
+    def load(self) -> "types.ModuleType":
         raise NotImplementedError
diff --git a/src/karkas_core/karkas_core/modules_system/public_api/public_api.py b/src/karkas_core/karkas_core/modules_system/public_api/public_api.py
index 53e6185..6b0869a 100644
--- a/src/karkas_core/karkas_core/modules_system/public_api/public_api.py
+++ b/src/karkas_core/karkas_core/modules_system/public_api/public_api.py
@@ -1,8 +1,7 @@
 import inspect
 import types
-from typing import Any, Tuple, Union
+from typing import TYPE_CHECKING, Any, Tuple, Union
 
-from aiogram import BaseMiddleware, Router
 from aiogram.fsm.context import FSMContext
 from aiogram.fsm.storage.base import StorageKey
 
@@ -10,18 +9,21 @@ from aiogram.fsm.storage.base import StorageKey
 from karkas_core.modules_system.loaders.base import DependencyInfo
 from karkas_core.singleton import Singleton
 
+if TYPE_CHECKING:
+    from aiogram import BaseMiddleware, Router
+
 
 async def set_chat_menu_button(menu_button):
     app = Singleton()
     await app.bot.set_chat_menu_button(menu_button=menu_button)
 
 
-def register_router(router: Router):
+def register_router(router: "Router"):
     app = Singleton()
     app.storage["_routers"].append(router)
 
 
-def register_outer_message_middleware(middleware: BaseMiddleware):
+def register_outer_message_middleware(middleware: "BaseMiddleware"):
     app = Singleton()
     app.storage["_outer_message_middlewares"].append(middleware)
 
diff --git a/src/karkas_core/karkas_core/modules_system/safe/policy.py b/src/karkas_core/karkas_core/modules_system/safe/policy.py
index 8dfc14b..58c11ac 100644
--- a/src/karkas_core/karkas_core/modules_system/safe/policy.py
+++ b/src/karkas_core/karkas_core/modules_system/safe/policy.py
@@ -1,6 +1,5 @@
 import types
-from _ast import AnnAssign
-from typing import Any
+from typing import TYPE_CHECKING, Any
 
 from aiogram import Bot
 from RestrictedPython import (
@@ -20,6 +19,9 @@ from RestrictedPython.Guards import (  # guarded_setattr,; full_write_guard,
 from karkas_core.logger import log
 from karkas_core.modules_system.safe.zope_guards import extra_safe_builtins
 
+if TYPE_CHECKING:
+    from _ast import AnnAssign
+
 
 class RestrictedPythonPolicy(RestrictingNodeTransformer):
     def visit_AsyncFunctionDef(self, node):
@@ -50,7 +52,7 @@ class RestrictedPythonPolicy(RestrictingNodeTransformer):
         return self.node_contents_visit(node)
     """
 
-    def visit_AnnAssign(self, node: AnnAssign) -> Any:
+    def visit_AnnAssign(self, node: "AnnAssign") -> Any:
         # missing in RestrictingNodeTransformer
         # this doesn't need the logic that is in visit_Assign
         # because it doesn't have a "targets" attribute,
diff --git a/src/karkas_core/karkas_core/singleton.py b/src/karkas_core/karkas_core/singleton.py
index 3a0f1f4..8f86585 100644
--- a/src/karkas_core/karkas_core/singleton.py
+++ b/src/karkas_core/karkas_core/singleton.py
@@ -1,7 +1,11 @@
-from aiogram import Bot, Dispatcher
+from typing import TYPE_CHECKING
+
 from aiogram.fsm.storage.memory import MemoryStorage
 
-from karkas_core.modules_system import ModulesManager
+if TYPE_CHECKING:
+    from aiogram import Bot, Dispatcher
+
+    from karkas_core.modules_system import ModulesManager
 
 
 class SingletonMeta(type):
@@ -15,9 +19,9 @@ class SingletonMeta(type):
 
 
 class Singleton(metaclass=SingletonMeta):
-    bot: Bot
-    dp: Dispatcher = None
-    modules_manager: ModulesManager = None
+    bot: "Bot"
+    dp: "Dispatcher" = None
+    modules_manager: "ModulesManager" = None
     storage = {
         "_fsm_storage": MemoryStorage(),
         "_routers": [],