import datetime

from colorama import init, Fore, Back, Style
import inspect, os

class Logger:

    @staticmethod
    def INFO(text, timestamp=True):

        init(autoreset=True)
        stack = inspect.stack()
        caller_frame = stack[1]
        filename = os.path.basename(caller_frame.filename)
        function_name = caller_frame.function
        text = f"({filename}) {function_name} -> [INFO] - {Fore.BLUE + str(text)}"
        extra = ""
        if timestamp:extra = f"[{datetime.datetime.now().isoformat()}]"
        text = f"{extra} {text}"
        print(text)


    @staticmethod
    def WARN(text, timestamp=True):

        init(autoreset=True)
        stack = inspect.stack()
        caller_frame = stack[1]
        filename = os.path.basename(caller_frame.filename)
        function_name = caller_frame.function
        text = f"({filename}) {function_name} -> [WARN] - {Fore.YELLOW + str(text)}"
        extra = ""
        if timestamp:extra = f"[{datetime.datetime.now().isoformat()}]"
        text = f"{extra} {text}"
        print(text)


    @staticmethod
    def ERROR(text, timestamp=True):

        init(autoreset=True)
        stack = inspect.stack()
        caller_frame = stack[1]
        filename = os.path.basename(caller_frame.filename)
        function_name = caller_frame.function
        text = f"({filename}) {function_name} -> [ERROR] - {Fore.RED + str(text)}"
        extra = ""
        if timestamp:extra = f"[{datetime.datetime.now().isoformat()}]"
        text = f"{extra} {text}"
        print(text)

    @staticmethod
    def SUCCESS(text, timestamp=True):
        init(autoreset=True)
        stack = inspect.stack()
        caller_frame = stack[1]
        filename = os.path.basename(caller_frame.filename)
        function_name = caller_frame.function
        text = f"({filename}) {function_name} -> [SUCCESS] - {Fore.GREEN + str(text)}"
        extra = ""
        if timestamp:extra = f"[{datetime.datetime.now().isoformat()}]"
        text = f"{extra} {text}"
        print(text)


import json, os
from pathlib import Path
from common.utils import Logger


class IO:

    @staticmethod
    def LoadJSON(path_to_file: str) -> dict:
        """
        :param path_to_file: Путь к файлу
        :return: JSON Данные
        """
        #Logger.INFO(f"Incoming data {path_to_file}")
        try:
            with open(path_to_file, mode='r', encoding="utf8") as f:
                content = f.read()
                if not content.strip():
                    #Logger.WARN("Target file is empty, returning {} as a result")
                    return {}
                #Logger.SUCCESS("Successfully loaded and returned")
                return json.loads(content)

        except FileNotFoundError:
            #Logger.ERROR(f"{path_to_file} not found!")
            raise FileNotFoundError("Путь к JSON не найден!")

    @staticmethod
    def DumpJSON(obj: dict, file: str):
        """
        :param obj: Объект типа Dict
        :param file: Имя файла или путь к файлу
        :return: Нечего
        """
        #Logger.INFO(f"Incoming data: {obj} and {file}")
        try:


            with open(file, mode="w", encoding="utf8") as f:
                json.dump(obj, f, ensure_ascii=True, indent=4)
                #Logger.SUCCESS("Successfully dumped")

        except Exception as e:
            #Logger.ERROR(f"{e}")
            raise IOError(f"{e}")

    @staticmethod
    def CreateFile(filename: str, filepath: str):
        """
        :param filename: Имя файла включая расширение
        :param filepath: Путь к директории файла
        :return: Нечего
        """

        #Logger.INFO(f"Incoming data: {filename} and {filepath}")
        try:
            open(f"{filepath}\\{filename}", mode="w")
            #Logger.SUCCESS(f"Successfully created {filename} in {filepath}")
        except Exception as e:
            #Logger.ERROR(str(e))
            raise FileNotFoundError(e)

    @staticmethod
    def RemoveFile(path_to_file: str):
        """
        :param path_to_file: Путь к файлу
        :return: Нечего
        """
        #Logger.INFO(f"Incoming data: {path_to_file}")
        if os.path.exists(path_to_file):
            os.remove(path_to_file)
            #Logger.SUCCESS(f"Successfully removed {path_to_file}")
        else:
            #Logger.ERROR(f"{path_to_file} not found")
            raise FileNotFoundError(f"{path_to_file} не найден.")

    @staticmethod
    def EnsureFileExists(path: Path, default_data: dict | None = None) -> None:
        #Logger.INFO(f"Incoming data; {str(path)}, {default_data}")
        if default_data is None:
            default_data = {}
            #Logger.WARN("Default data is empty")
        if not path.exists():
            with open(path, "w", encoding="utf-8") as f:
                json.dump(default_data, f, indent=4, ensure_ascii=False)
                #Logger.SUCCESS("Successfully dumped")

    @staticmethod
    def GetValue(path: Path, *keys, default=None):
        #Logger.INFO(f"Incoming data: {str(path)}, {str(*keys)}, {str(default)}")
        data = IO.LoadJSON(path)
        for key in keys:
            if isinstance(data, dict) and key in data:
                data = data[key]
            else:
                #Logger.WARN(f"Incorrect isinstance for {key} ({str(type(key))}, returned None")
                return default

        #Logger.SUCCESS(f"Successfully returned {data}")
        return data


Логгер тормозит работу программы при чем очень сильно.
Узнать причину и решение..