diff --git a/Difficult_Rocket/__init__.py b/Difficult_Rocket/__init__.py index bbb2a7f..4db7523 100644 --- a/Difficult_Rocket/__init__.py +++ b/Difficult_Rocket/__init__.py @@ -13,7 +13,6 @@ build_version = Version("2.2.0.0") # 编译文件版本(与游戏本体无关) api_version = Version("0.1.1.0") # API 版本 __version__ = sdk_version - __all__ = [ # __init__ "DR_status", @@ -86,6 +85,7 @@ def load_logger(): if not log_config_path.is_file(): # 生成默认配置文件 from Difficult_Rocket.data import log_config + try: log_config_path.write_text(log_config.default_config) except (FileNotFoundError, OSError, PermissionError): @@ -94,29 +94,31 @@ def load_logger(): logger_config = rtoml.loads(log_config.default_config) else: # 读取配置文件 - with open(log_config_path, encoding='utf-8') as f: + with open(log_config_path, encoding="utf-8") as f: logger_config = rtoml.load(f) # 输入 lndl 进行配置 from lib_not_dr.loggers.config import read_config, get_logger + read_config(logger_config) logger = get_logger("main") - logger.info("Logger config loaded", tag='DR-init') - logger.info(f"DR status:\n{DR_status.as_markdown()}", tag='DR-init') + logger.info("Logger config loaded", tag="DR-init") + logger.info(f"DR status:\n{DR_status.as_markdown()}", tag="DR-init") if warn_config: - logger.warn("Failed to load log config file, use default config", tag='DR-init') + logger.warn("Failed to load log config file, use default config", tag="DR-init") # 读取日志配置 # 也保证可以直接运行,不带日志 ( 因为有默认配置 ) load_logger() - if DR_status.playing: from Difficult_Rocket.utils.thread import new_thread + def think_it(something): return something + @new_thread("think") def think(some_thing_to_think): gotcha = think_it(some_thing_to_think) diff --git a/Difficult_Rocket/api/__init__.py b/Difficult_Rocket/api/__init__.py index b13d9ec..e414c21 100644 --- a/Difficult_Rocket/api/__init__.py +++ b/Difficult_Rocket/api/__init__.py @@ -11,7 +11,6 @@ github: @shenjackyuanjie gitee: @shenjackyuanjie """ - __all__ = [ "exception", # 错误类定义 diff --git a/Difficult_Rocket/api/screen.py b/Difficult_Rocket/api/screen.py index 00bc07b..c39687c 100644 --- a/Difficult_Rocket/api/screen.py +++ b/Difficult_Rocket/api/screen.py @@ -33,7 +33,6 @@ class BaseScreen(EventDispatcher, Options): self.window_pointer = main_window if TYPE_CHECKING: - def on_command(self, command: CommandText, window: ClientWindow): """ 命令输入事件 @@ -154,7 +153,7 @@ class BaseScreen(EventDispatcher, Options): """ def on_file_drop( - self, x: int, y: int, paths: List[PathLike], window: ClientWindow + self, x: int, y: int, paths: List[PathLike], window: ClientWindow ): """File(s) were dropped into the window, will return the position of the cursor and a list of paths to the files that were dropped. @@ -217,14 +216,14 @@ class BaseScreen(EventDispatcher, Options): """ def on_mouse_drag( - self, - x: int, - y: int, - dx: int, - dy: int, - buttons: int, - modifiers: int, - window: ClientWindow, + self, + x: int, + y: int, + dx: int, + dy: int, + buttons: int, + modifiers: int, + window: ClientWindow, ): """The mouse was moved with one or more mouse buttons pressed. @@ -250,7 +249,7 @@ class BaseScreen(EventDispatcher, Options): """ def on_mouse_press( - self, x: int, y: int, button: int, modifiers: int, window: ClientWindow + self, x: int, y: int, button: int, modifiers: int, window: ClientWindow ): """A mouse button was pressed (and held down). @@ -269,7 +268,7 @@ class BaseScreen(EventDispatcher, Options): """ def on_mouse_release( - self, x: int, y: int, button: int, modifiers: int, window: ClientWindow + self, x: int, y: int, button: int, modifiers: int, window: ClientWindow ): """A mouse button was released. @@ -288,7 +287,7 @@ class BaseScreen(EventDispatcher, Options): """ def on_mouse_scroll( - self, x: int, y: int, scroll_x: float, scroll_y: float, window: ClientWindow + self, x: int, y: int, scroll_x: float, scroll_y: float, window: ClientWindow ): """The mouse wheel was scrolled. diff --git a/Difficult_Rocket/client/__init__.py b/Difficult_Rocket/client/__init__.py index 1920bc8..871bd19 100644 --- a/Difficult_Rocket/client/__init__.py +++ b/Difficult_Rocket/client/__init__.py @@ -44,7 +44,6 @@ from Difficult_Rocket.exception.language import LanguageNotFound from lib_not_dr import loggers - logger = loggers.config.get_logger("client") @@ -129,7 +128,7 @@ def pyglet_load_fonts_folder(folder) -> None: if not font_path.exists(): font_path.mkdir(parents=True) return None - logger.info(tr().client.load.font.start().format(font_path), tag='font') + logger.info(tr().client.load.font.start().format(font_path), tag="font") start_time = time.time_ns() for dir_path, dir_names, file_names in os.walk(font_path): dir_path = Path(dir_path) @@ -137,7 +136,8 @@ def pyglet_load_fonts_folder(folder) -> None: file_name = Path(file_name) if file_name.suffix in (".ttf", ".otf"): logger.debug( - tr().client.load.font.file().format(str(dir_path / file_name)), tag='font' + tr().client.load.font.file().format(str(dir_path / file_name)), + tag="font", ) try: pyglet.font.add_file(str(dir_path / file_name)) @@ -149,7 +149,9 @@ def pyglet_load_fonts_folder(folder) -> None: ) end_time = time.time_ns() use_time = end_time - start_time - logger.info(tr().client.load.font.use_time().format(use_time / 1000000000), tag='font') + logger.info( + tr().client.load.font.use_time().format(use_time / 1000000000), tag="font" + ) def _call_back(call_back: Callable) -> Callable: @@ -308,10 +310,13 @@ class ClientWindow(Window): # TODO: wait for pyglet 2.1 pyglet.app.run(float(self.SPF)) except KeyboardInterrupt: - self.logger.warn("==========client stop. KeyboardInterrupt info==========", tag="starter") + self.logger.warn( + "==========client stop. KeyboardInterrupt info==========", tag="starter" + ) traceback.print_exc() self.logger.warn( - "==========client stop. KeyboardInterrupt info end==========", tag="starter" + "==========client stop. KeyboardInterrupt info end==========", + tag="starter", ) self.dispatch_event("on_close", "input") sys.exit(0) @@ -498,7 +503,7 @@ class ClientWindow(Window): @_call_screen_after def on_key_press(self, symbol, modifiers) -> None: if symbol == key.ESCAPE and not ( - modifiers & ~(key.MOD_NUMLOCK | key.MOD_CAPSLOCK | key.MOD_SCROLLLOCK) + modifiers & ~(key.MOD_NUMLOCK | key.MOD_CAPSLOCK | key.MOD_SCROLLLOCK) ): self.dispatch_event("on_close", "window") if symbol == key.SLASH: diff --git a/Difficult_Rocket/client/fps/fps_log.py b/Difficult_Rocket/client/fps/fps_log.py index 58bf796..7f0af0c 100644 --- a/Difficult_Rocket/client/fps/fps_log.py +++ b/Difficult_Rocket/client/fps/fps_log.py @@ -36,9 +36,9 @@ class FpsLogger: else: self.fps_list.append(float(1 / tick)) if len(self.fps_list) > self.count: - self.fps_list = self.fps_list[-self.count + 1 :] # 整个列表往前挪一位 + self.fps_list = self.fps_list[-self.count + 1:] # 整个列表往前挪一位 if len(self.get_fps_list) > self.count: - self.get_fps_list = self.get_fps_list[-self.count + 1 :] # 整个列表往前挪一位 + self.get_fps_list = self.get_fps_list[-self.count + 1:] # 整个列表往前挪一位 try: self._fps = statistics.geometric_mean( self.fps_list[-100:] diff --git a/Difficult_Rocket/client/guis/format/html.py b/Difficult_Rocket/client/guis/format/html.py index 8eeb640..401b74b 100644 --- a/Difficult_Rocket/client/guis/format/html.py +++ b/Difficult_Rocket/client/guis/format/html.py @@ -20,8 +20,8 @@ from pyglet.text.formats import structured default_style = { "font_name": "Times New Roman", "font_size": 12, - "bold": False, - "italic": False, + "bold": False, + "italic": False, } @@ -35,17 +35,17 @@ class SingleTextStyle: """ def __init__( - self, - font_name: str = "", - font_size: int = 12, - bold: bool = False, - italic: bool = False, - color: str = "white", - text_tag: list = None, - show: bool = True, - prefix: str = "", - suffix: str = "", - text: str = "", + self, + font_name: str = "", + font_size: int = 12, + bold: bool = False, + italic: bool = False, + color: str = "white", + text_tag: list = None, + show: bool = True, + prefix: str = "", + suffix: str = "", + text: str = "", ): self.font_name = font_name self.font_size = font_size @@ -142,10 +142,10 @@ class SingleTextStyle: """ assert isinstance(other, SingleTextStyle) return ( - self.font_name == other.font_name - and self.font_size == other.font_size - and self.color == other.color - and self.show == other.show + self.font_name == other.font_name + and self.font_size == other.font_size + and self.color == other.color + and self.show == other.show ) def same_bold(self, other: "SingleTextStyle") -> bool: @@ -215,9 +215,9 @@ class SingleTextStyle: """ return ( ( - font_HTML_end - + (bold_HTML_end if self.bold else "") - + (italic_HTML_end if self.italic else "") + font_HTML_end + + (bold_HTML_end if self.bold else "") + + (italic_HTML_end if self.italic else "") ) if suffix else self.HTML_bold() + self.HTML_italic() + self.HTML_font() @@ -248,7 +248,7 @@ default_fonts_config = [ # Markdown 粗体语法规则匹配 "match": re.compile(r"\*\*(.*?(? str: if ignore: # 为了方便退出 break for ignore_index in range( - match_start + ignore_text.span()[0], - match_start + ignore_text.span()[1], + match_start + ignore_text.span()[0], + match_start + ignore_text.span()[1], ): # 对每一个可能的字符进行检测 if style_list[ignore_index].have_tag( - config["ignore"]["tag"] + config["ignore"]["tag"] ): # 如果确实包含要忽略的 ignore = True # 忽略为True break @@ -324,7 +324,7 @@ def decode_text2HTML(text: str, configs=None, show_style: bool = False) -> str: ) # 根据配置的正则表达式匹配要添加tag的字符 for tag_text in tag_texts: # 对每一个匹配到的~~~~~~ for tag_index in range( - match_start + tag_text.span()[0], match_start + tag_text.span()[1] + match_start + tag_text.span()[0], match_start + tag_text.span()[1] ): # 用于遍历匹配到的字符 style_list[tag_index] += config["tag"]["style"] # 为匹配到的字符添加样式 @@ -337,7 +337,7 @@ def decode_text2HTML(text: str, configs=None, show_style: bool = False) -> str: # 为每一个显示的字符设置显示属性 for shown_text in shown_texts: # 每一个显示的匹配项 for shown_index in range( - match_start + shown_text.span()[0], match_start + shown_text.span()[1] + match_start + shown_text.span()[0], match_start + shown_text.span()[1] ): style_list[shown_index].show = True # 字体样式列表的 [shown_index] 设置显示属性变为 True @@ -349,17 +349,17 @@ def decode_text2HTML(text: str, configs=None, show_style: bool = False) -> str: if not style_list[style_index - 1].same_font(style_list[style_index]): style_list[style_index - 1].suffix += style_list[ style_index - 1 - ].HTML_font(suffix=True) + ].HTML_font(suffix=True) style_list[style_index].prefix += style_list[style_index].HTML_font() if not style_list[style_index - 1].same_bold(style_list[style_index]): style_list[style_index - 1].suffix += style_list[ style_index - 1 - ].HTML_bold(suffix=True) + ].HTML_bold(suffix=True) style_list[style_index].prefix += style_list[style_index].HTML_bold() if not style_list[style_index - 1].same_italic(style_list[style_index]): style_list[style_index - 1].suffix += style_list[ style_index - 1 - ].HTML_italic(suffix=True) + ].HTML_italic(suffix=True) style_list[style_index].prefix += style_list[ style_index ].HTML_italic() diff --git a/Difficult_Rocket/command/api.py b/Difficult_Rocket/command/api.py index 4fcd5f6..a083c45 100644 --- a/Difficult_Rocket/command/api.py +++ b/Difficult_Rocket/command/api.py @@ -50,9 +50,9 @@ class CommandText: if find != -1: if not len(text) == len(self.text): self.text = ( - self.text[find + len(text) :] + self.text[find + len(text):] if not self.text[find + len(text)] == " " - else self.text[find + len(text) + 1 :] + else self.text[find + len(text) + 1:] ) return True return False @@ -68,7 +68,7 @@ class CommandText: # 20230122 我现在也不知道为啥这么写了 # 果然使用正则表达式就是让一个问题变成两个问题 except IndexError: - self.text = self.text[finding.span()[1] + 1 :] + self.text = self.text[finding.span()[1] + 1:] return True if next_find == " ": return True diff --git a/Difficult_Rocket/command/line.py b/Difficult_Rocket/command/line.py index c1e7664..301c25d 100644 --- a/Difficult_Rocket/command/line.py +++ b/Difficult_Rocket/command/line.py @@ -36,15 +36,15 @@ class CommandLineTextEntry(widgets.TextEntry): """ def __init__( - self, - x: int, - y: int, - width: int, - color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255), - text_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0, 255), - caret_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0), - batch: Optional[Batch] = None, - group: Optional[Group] = None, + self, + x: int, + y: int, + width: int, + color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255), + text_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0, 255), + caret_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0), + batch: Optional[Batch] = None, + group: Optional[Group] = None, ): super().__init__( x=x, @@ -66,16 +66,16 @@ class CommandLine(widgets.WidgetBase): """ def __init__( - self, - x: int, - y: int, - width: int, - height: int, - length: int, - batch: Batch, - group: Group = None, - command_text: str = "/", - font_size: int = 20, + self, + x: int, + y: int, + width: int, + height: int, + length: int, + batch: Batch, + group: Group = None, + command_text: str = "/", + font_size: int = 20, ): super().__init__(x, y, width, height) @@ -182,14 +182,14 @@ class CommandLine(widgets.WidgetBase): """ assert isinstance(value, int), "Command View must be integer" assert ( - -self.length < value < self.length + -self.length < value < self.length ), f"Command View must be bigger than {-self.length} and smaller than {self.length}" if value == -1: # flush command list self._label.insert(0, self._label[-1]) self._label.pop(-1) for line in range(self.length): self._label[line].y = ( - self.y + self.command_distance + (line * self.command_split) + self.y + self.command_distance + (line * self.command_split) ) self._label[0].text = self.text self.text = "" @@ -223,10 +223,10 @@ class CommandLine(widgets.WidgetBase): time.sleep(wait) if self._label[0].visible and not self.editing: while ( - (self._label[0].opacity >= 30) - and self._label[0].visible - and (self._label[0] is this) - and not self.editing + (self._label[0].opacity >= 30) + and self._label[0].visible + and (self._label[0] is this) + and not self.editing ): # (label 的透明度不是 0) and (label 还在显示) and (label 还是载入线程时候的那个label) and (现在不在输入新行) self._label[0].opacity -= 2 @@ -279,7 +279,7 @@ class CommandLine(widgets.WidgetBase): if motion == key.MOTION_DELETE: # 确保不越界 self.text = f"{self.text[:self._text_position]}{self.text[self._text_position + 1:]}" # 简单粗暴的删除 elif ( - motion == key.MOTION_BACKSPACE and self._text_position >= 1 + motion == key.MOTION_BACKSPACE and self._text_position >= 1 ): # 确保不越界 self.text = f"{self.text[:self._text_position - 1]}{self.text[self._text_position:]}" # 简单粗暴的删除 self._text_position -= 1 # 记得切换光标位置 @@ -288,19 +288,19 @@ class CommandLine(widgets.WidgetBase): elif motion == key.MOTION_LEFT and self._text_position >= 0: # 确保不越界 self._text_position -= 1 elif motion == key.MOTION_RIGHT and self._text_position <= len( - self.text + self.text ): # 确保不越界 self._text_position += 1 elif motion in ( - key.MOTION_BEGINNING_OF_LINE, - key.MOTION_BEGINNING_OF_FILE, - key.MOTION_PREVIOUS_PAGE, + key.MOTION_BEGINNING_OF_LINE, + key.MOTION_BEGINNING_OF_FILE, + key.MOTION_PREVIOUS_PAGE, ): self._text_position = 0 elif motion in ( - key.MOTION_END_OF_LINE, - key.MOTION_END_OF_FILE, - key.MOTION_NEXT_PAGE, + key.MOTION_END_OF_LINE, + key.MOTION_END_OF_FILE, + key.MOTION_NEXT_PAGE, ): self._text_position = len(self.text) diff --git a/Difficult_Rocket/crash/__init__.py b/Difficult_Rocket/crash/__init__.py index 7393590..90318b0 100644 --- a/Difficult_Rocket/crash/__init__.py +++ b/Difficult_Rocket/crash/__init__.py @@ -61,10 +61,10 @@ def crash_info_handler(info: Optional[str] = None) -> str: def markdown_line_handler( - string: Optional[Union[str, bool, int, float]], - code: bool = False, - level: int = 1, - end: str = "\n", + string: Optional[Union[str, bool, int, float]], + code: bool = False, + level: int = 1, + end: str = "\n", ) -> str: lvl = "- " * level f_string = string diff --git a/Difficult_Rocket/gui/widget/button.py b/Difficult_Rocket/gui/widget/button.py index c782968..0239570 100644 --- a/Difficult_Rocket/gui/widget/button.py +++ b/Difficult_Rocket/gui/widget/button.py @@ -94,15 +94,15 @@ class PressTextButton(widgets.WidgetBase): """ def __init__( - self, - x: int, - y: int, - width: int, - height: int, - text: str, - batch: Optional[Batch] = None, - group: Optional[Group] = None, - theme: Optional[ButtonThemeOptions] = None, + self, + x: int, + y: int, + width: int, + height: int, + text: str, + batch: Optional[Batch] = None, + group: Optional[Group] = None, + theme: Optional[ButtonThemeOptions] = None, ): super().__init__(x, y, width, height) self.main_batch = batch or Batch() @@ -160,7 +160,7 @@ class PressTextButton(widgets.WidgetBase): text_width = self.text_label.content_width self.text_label.x = self._x + (self.width - text_width) // 2 self.text_label.y = ( - self._y + (self.height - self.font_height) // 2 + (self.font_height * 0.2) + self._y + (self.height - self.font_height) // 2 + (self.font_height * 0.2) ) # 修正一下位置 def __contains__(self, item): diff --git a/Difficult_Rocket/gui/widget/theme/__init__.py b/Difficult_Rocket/gui/widget/theme/__init__.py index 4fed2de..3d617f4 100644 --- a/Difficult_Rocket/gui/widget/theme/__init__.py +++ b/Difficult_Rocket/gui/widget/theme/__init__.py @@ -23,7 +23,6 @@ class BaseTheme(dict): setattr(self, k, v) if TYPE_CHECKING: - def init(self, batch: Batch, group: Group, **kwargs) -> None: """ Init theme diff --git a/Difficult_Rocket/mod/__init__.py b/Difficult_Rocket/mod/__init__.py index 95b52bb..e65b6e9 100644 --- a/Difficult_Rocket/mod/__init__.py +++ b/Difficult_Rocket/mod/__init__.py @@ -3,4 +3,3 @@ # Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com # All rights reserved # ------------------------------- - diff --git a/Difficult_Rocket/mod/loader/__init__.py b/Difficult_Rocket/mod/loader/__init__.py index 2b15cbd..da4b6c7 100644 --- a/Difficult_Rocket/mod/loader/__init__.py +++ b/Difficult_Rocket/mod/loader/__init__.py @@ -74,25 +74,27 @@ class ModManager(Options): :return: """ if not mod_path.exists(): - logger.error(tr().mod.load.faild.not_exist().format(mod_path)) + logger.error(tr().mod.load.faild.not_exist().format(mod_path), tag="load") return None _add_path_to_sys([mod_path.parent]) try: if mod_path.name == "__pycache__": # 忽略 __pycache__ 文件夹 (Python 编译文件) return None - logger.info(tr().mod.load.loading().format(mod_path)) + logger.info(tr().mod.load.loading().format(mod_path), tag="load") if ( - mod_path.is_dir() - or mod_path.suffix in PACKAGE_SUFFIX - or mod_path.suffix in ONE_FILE_SUFFIX + mod_path.is_dir() + or mod_path.suffix in PACKAGE_SUFFIX + or mod_path.suffix in ONE_FILE_SUFFIX ): # 文件夹 mod loading_mod = importlib.import_module(mod_path.name) if not hasattr(loading_mod, "mod_class") or not issubclass( - loading_mod.mod_class, ModInfo + loading_mod.mod_class, ModInfo ): - logger.warn(tr().mod.load.faild.no_mod_class().format(mod_path)) + logger.warn( + tr().mod.load.faild.no_mod_class().format(mod_path), tag="load" + ) return None mod_class: type(ModInfo) = loading_mod.mod_class # 获取 mod 类 if mod_class.mod_id not in self.find_mod_paths: @@ -100,12 +102,13 @@ class ModManager(Options): return mod_class except ImportError: logger.warn( - tr().mod.load.faild.error().format(mod_path, traceback.format_exc()) + tr().mod.load.faild.error().format(mod_path, traceback.format_exc()), + tag="load", ) return None def find_mods_in_path( - self, extra_mods_path: Optional[List[Path]] = None + self, extra_mods_path: Optional[List[Path]] = None ) -> List[Path]: """ 查找所有 mod 路径 @@ -125,19 +128,21 @@ class ModManager(Options): # 忽略 __pycache__ 文件夹 (Python 编译文件) continue if ( - mod.is_dir() - or mod.suffix in PACKAGE_SUFFIX - or mod.suffix in ONE_FILE_SUFFIX + mod.is_dir() + or mod.suffix in PACKAGE_SUFFIX + or mod.suffix in ONE_FILE_SUFFIX ): # 文件夹 mod mods_path.append(mod) - logger.info(tr().mod.finded().format(len(mods_path), time.time() - start_time)) + logger.info( + tr().mod.finded().format(len(mods_path), time.time() - start_time), tag="find" + ) return mods_path def load_mods( - self, - extra_path: Optional[List[Path]] = None, - extra_mod_path: Optional[List[Path]] = None, + self, + extra_path: Optional[List[Path]] = None, + extra_mod_path: Optional[List[Path]] = None, ) -> List[type(ModInfo)]: """ 加载所有 mod (可提供额外的 mod 路径) @@ -149,7 +154,7 @@ class ModManager(Options): _add_path_to_sys(find_path) mods = [] start_time = time.time() - logger.info(tr().mod.load.start().format(find_path)) + logger.info(tr().mod.load.start().format(find_path), tag="load") for path in find_path: if not path.exists(): path.mkdir(parents=True) @@ -161,7 +166,7 @@ class ModManager(Options): for path in extra_mod_path: if (cache := self.load_mod(path)) is not None: mods.append(cache) - logger.info(tr().mod.load.use_time().format(time.time() - start_time)) + logger.info(tr().mod.load.use_time().format(time.time() - start_time), tag="load") return mods def init_mods(self, mods: List[type(ModInfo)]): @@ -175,13 +180,16 @@ class ModManager(Options): try: init_mod = mod_class() self.loaded_mod_modules[init_mod.mod_id] = init_mod - logger.info(tr().mod.init.success().format(init_mod, init_mod.version)) + logger.info( + tr().mod.init.success().format(init_mod, init_mod.version), tag="init" + ) except Exception as e: logger.error( - tr().mod.init.faild().format(mod_class, e, traceback.format_exc()) + tr().mod.init.faild().format(mod_class, e, traceback.format_exc()), + tag="init", ) continue - logger.info(tr().mod.init.use_time().format(time.time() - start_time)) + logger.info(tr().mod.init.use_time().format(time.time() - start_time), tag="init") def unload_mod(self, mod_id: str, game: Game) -> Optional[ModInfo]: """ @@ -191,19 +199,20 @@ class ModManager(Options): :return: 卸载的 mod 的 ModInfo 类 """ if ( - not (mod_class := self.loaded_mod_modules.get(mod_id)) - and (mod_class := self.get_mod_module(mod_id)) is None + not (mod_class := self.loaded_mod_modules.get(mod_id)) + and (mod_class := self.get_mod_module(mod_id)) is None ): - logger.warn(tr().mod.unload.faild.not_find().format(mod_id)) + logger.warn(tr().mod.unload.faild.not_find().format(mod_id), tag="unload") return None try: mod_class.on_unload(game=game) self.loaded_mod_modules.pop(mod_class.mod_id) - logger.info(tr().mod.unload.success().format(mod_id)) + logger.info(tr().mod.unload.success().format(mod_id), tag="unload") return mod_class except Exception as e: logger.error( - tr().mod.unload.faild.error().format(mod_id, e, traceback.format_exc()) + tr().mod.unload.faild.error().format(mod_id, e, traceback.format_exc()), + tag="unload", ) return None @@ -219,7 +228,9 @@ class ModManager(Options): return mod_class: Optional[ModInfo] = None if unload.mod_id not in self.find_mod_paths: - logger.warn(tr().mod.reload.faild.not_find().format(unload.mod_id)) + logger.warn( + tr().mod.reload.faild.not_find().format(unload.mod_id), tag="reload" + ) paths = self.find_mods_in_path() for path in paths: mod_class = self.load_mod(path) @@ -232,4 +243,4 @@ class ModManager(Options): self.init_mods([mod_class]) if mod_id in self.loaded_mod_modules and mod_class is not None: self.loaded_mod_modules[mod_id].on_load(game=game, old_self=mod_class) - logger.info(tr().mod.reload.success().format(mod_id)) + logger.info(tr().mod.reload.success().format(mod_id), tag="reload") diff --git a/Difficult_Rocket/runtime.py b/Difficult_Rocket/runtime.py index b876b90..bf01469 100644 --- a/Difficult_Rocket/runtime.py +++ b/Difficult_Rocket/runtime.py @@ -14,7 +14,6 @@ from typing import Optional, List, Tuple from Difficult_Rocket.api.types import Options, Version - __all__ = ["DR_runtime"] diff --git a/Difficult_Rocket/utils/camera.py b/Difficult_Rocket/utils/camera.py index 0a02c8f..7be575a 100644 --- a/Difficult_Rocket/utils/camera.py +++ b/Difficult_Rocket/utils/camera.py @@ -29,13 +29,13 @@ class Camera: """ def __init__( - self, - window, - zoom: Optional[float] = 1.0, - dx: Optional[float] = 1.0, - dy: Optional[float] = 1.0, - min_zoom: Optional[float] = 1.0, - max_zoom: Optional[float] = 1.0, + self, + window, + zoom: Optional[float] = 1.0, + dx: Optional[float] = 1.0, + dy: Optional[float] = 1.0, + min_zoom: Optional[float] = 1.0, + max_zoom: Optional[float] = 1.0, ) -> None: self.window = window self.dx = dx @@ -126,15 +126,15 @@ class GroupCamera(Group): """ def __init__( - self, - window, - order: int = 0, - parent: Optional[Group] = None, - view_x: Optional[int] = 0, - view_y: Optional[int] = 0, - zoom: Optional[float] = 1.0, - min_zoom: Optional[float] = 1.0, - max_zoom: Optional[float] = 1.0, + self, + window, + order: int = 0, + parent: Optional[Group] = None, + view_x: Optional[int] = 0, + view_y: Optional[int] = 0, + zoom: Optional[float] = 1.0, + min_zoom: Optional[float] = 1.0, + max_zoom: Optional[float] = 1.0, ): super().__init__(order=order, parent=parent) self._window = window @@ -219,17 +219,17 @@ class CenterGroupFrame(Group): """ def __init__( - self, - window, - order: int = 0, - parent: Optional[Group] = None, - dx: Optional[int] = 0, - dy: Optional[int] = 0, - width: Optional[int] = 0, - height: Optional[int] = 0, - zoom: Optional[float] = 1.0, - min_zoom: Optional[float] = 1.0, - max_zoom: Optional[float] = 1.0, + self, + window, + order: int = 0, + parent: Optional[Group] = None, + dx: Optional[int] = 0, + dy: Optional[int] = 0, + width: Optional[int] = 0, + height: Optional[int] = 0, + zoom: Optional[float] = 1.0, + min_zoom: Optional[float] = 1.0, + max_zoom: Optional[float] = 1.0, ): super().__init__(order=order, parent=parent) self.window = window diff --git a/Difficult_Rocket/utils/thread.py b/Difficult_Rocket/utils/thread.py index 2202444..dd63bdb 100644 --- a/Difficult_Rocket/utils/thread.py +++ b/Difficult_Rocket/utils/thread.py @@ -120,9 +120,9 @@ class FunctionThread(threading.Thread): def new_thread( - arg: Optional[Union[str, Callable]] = None, - daemon: bool = False, - log_thread: bool = True, + arg: Optional[Union[str, Callable]] = None, + daemon: bool = False, + log_thread: bool = True, ): """ This is a one line solution to make your function executes in parallels. diff --git a/Difficult_Rocket/utils/translate.py b/Difficult_Rocket/utils/translate.py index 6277053..ecb5272 100644 --- a/Difficult_Rocket/utils/translate.py +++ b/Difficult_Rocket/utils/translate.py @@ -36,7 +36,7 @@ class TranslateConfig: def set(self, item: str, value: Union[bool, "Tr", "Translates"]) -> "TranslateConfig": assert ( - getattr(self, item, None) is not None + getattr(self, item, None) is not None ), f"Config {item} is not in TranslateConfig" assert isinstance(value, bool) setattr(self, item, value) @@ -62,10 +62,10 @@ key_type = Union[str, int, Hashable] class Translates: def __init__( - self, - value: Union[Dict[str, Any], list, tuple, str], - config: Optional[TranslateConfig] = None, - get_list: Optional[List[Tuple[bool, str]]] = None, + self, + value: Union[Dict[str, Any], list, tuple, str], + config: Optional[TranslateConfig] = None, + get_list: Optional[List[Tuple[bool, str]]] = None, ): """一个用于翻译的东西 :param value: 翻译键节点 @@ -77,9 +77,9 @@ class Translates: self._get_list = get_list or [] def set_conf_( - self, - option: Union[str, TranslateConfig], - value: Optional[Union[bool, List[str]]] = None, + self, + option: Union[str, TranslateConfig], + value: Optional[Union[bool, List[str]]] = None, ) -> "Translates": assert isinstance(option, (TranslateConfig, str)) if isinstance(option, TranslateConfig): @@ -117,7 +117,7 @@ class Translates: print(raise_info) def __getitem__( - self, item: Union[key_type, List[key_type], Tuple[key_type]] + self, item: Union[key_type, List[key_type], Tuple[key_type]] ) -> "Translates": try: if isinstance(item, (str, int, Hashable)): @@ -127,11 +127,11 @@ class Translates: for a_item in item: cache_value = cache_value[a_item] if isinstance( - cache_value, - ( - int, - str, - ), + cache_value, + ( + int, + str, + ), ): self._config.is_final = True self._get_list.append((True, item)) @@ -158,7 +158,7 @@ class Translates: def __getattr__(self, item: key_type) -> "Translates": if (self._config.is_final or any(x[0] for x in self._get_list)) and hasattr( - self._value, item + self._value, item ): return getattr(self._value, item) # 实际上我这里完全不需要处理正常需求,因为 __getattribute__ 已经帮我处理过了 @@ -181,10 +181,10 @@ class Tr: """ def __init__( - self, - language: str = None, - config: Optional[TranslateConfig] = None, - lang_path: Optional[Path] = None, + self, + language: str = None, + config: Optional[TranslateConfig] = None, + lang_path: Optional[Path] = None, ): """ 诶嘿,我抄的MCDR diff --git a/config/local_logger.toml b/config/local_logger.toml deleted file mode 100644 index 6d2ccbd..0000000 --- a/config/local_logger.toml +++ /dev/null @@ -1,123 +0,0 @@ -logger_version = '1.0.0' - -[Loggers] - - [Loggers.root] - level = 'DEBUG' - color = 'main_color' - file = 'main_log_file' - handlers = ['main_std_handler'] - - [Loggers.client] - level = 'TRACE' - color = 'main_color' - file = 'main_log_file' - handlers = ['main_std_handler'] - - [Loggers.server] - level = 'TRACE' - color = 'DiGua_color' - file = 'main_log_file' - handlers = ['main_std_handler'] - -[Files] - - [Files.main_log_file] - name = './logs/{long_time}_logs.md' - level = 'TRACE' - cache_len = 20 - cache_time = 1 - mode = 'a' - encoding = 'utf-8' - -[Handler] - - [Handler.main_std_handler] - class = 'str handler' - format = 'format.main_format' - - [Handler.main_file_hander] - class = 'cached file handler' - format = 'format.main_format' - -[Formatter] - -main_format = '[{long_time}] [{logger_name}] {level} | {file_name}:{code_line} | {marker} | {message}' -file_name = 'no frame' -code_line = 'no frame' -short_time = '%Y-%m-%d %H-%M-%S' -long_time = '%Y-%m-%d %H-%M-%S:%%S' - -[Colors] - - [Colors.main_color] - # 翻了三个月的颜色啊 - long_time = '\u001b[38;2;201;222;56m' - short_time = '\u001b[38;2;201;222;56m' - code_line = '\u001b[38;2;0;255;180m' - file_name = '\u001b[38;2;0;255;180m' - info = '\u001b[0m' - message = '\u001b[0m' - logger = '\u001b[0m' - marker = '\u001b[0m' - # level colors - TRACE.info = '\u001b[38;2;138;173;244m' - FINE.info = '\u001b[35;48;2;44;44;54m' - DEBUG.info = '\u001b[38;2;133;138;149m' - INFO.info = '\u001b[0m' - WARNING.info = '\u001b[33m' - ERROR.info = '\u001b[31m' - FATAL.info = '\u001b[38;2;255;255;0;48;2;120;10;10m' - FATAL.logger = '\u001b[38;2;245;189;230m' - - [Colors.fancy_main_color] - long_time = '\u001b[38;2;201;222;56m' - short_time = '\u001b[38;2;201;222;56m' - file_name = '\u001b[38;2;0;255;180m' - code_line = '\u001b[38;2;0;255;180m' - info = '\u001b[0m' - message = '\u001b[0m' - logger = '\u001b[0m' - marker = '\u001b[0m' - # level colors - TRACE.info = '\u001b[38;2;138;173;244m' - TRACE.message = '\u001b[38;2;138;173;244m' - FINE.info = '\u001b[35;48;2;44;44;54m' - FINE.message = '\u001b[35m' - DEBUG.info = '\u001b[38;2;133;138;149m' - DEBUG.message = '\u001b[38;2;133;138;149m' - INFO.info = '\u001b[0m' - INFO.message = '\u001b[0m' - WARNING.info = '\u001b[33m' - WARNING.message = '\u001b[33m' - ERROR.info = '\u001b[31m' - ERROR.message = '\u001b[31m' - FATAL.info = '\u001b[38;2;255;255;0;48;2;120;10;10m' - FATAL.message = '\u001b[38;2;255;255;0;48;2;120;10;10m' - FATAL.logger = '\u001b[38;2;245;189;230m' - - [Colors.DiGua_color] - # catppuccin Macchiato - long_time = '\u001b[38;2;202;211;245m' - short_time = '\u001b[38;2;202;211;245m' - file_name = '\u001b[38;2;139;213;202m' - code_line = '\u001b[38;2;166;218;149m' - info = '\u001b[0m' - logger = '\u001b[0m' - message = '\u001b[0m' - marker = '\u001b[0m' - # level colors - TRACE.info = '\u001b[38;2;138;173;244m' - TRACE.message = '\u001b[38;2;138;173;244m' - FINE.info = '\u001b[38;2;198;160;246m' - FINE.message = '\u001b[38;2;198;160;246m' - DEBUG.info = '\u001b[38;2;133;138;149m' - DEBUG.message = '\u001b[38;2;133;138;149m' - ERROR.info = '\u001b[38;2;237;135;150m' - ERROR.message = '\u001b[38;2;237;135;150m' - WARNING.info = '\u001b[38;2;245;169;127m' - WARNING.message = '\u001b[38;2;245;169;127m' - FATAL.info = '\u001b[38;2;255;255;0;48;2;120;10;10m' - FATAL.message = '\u001b[38;2;255;255;0;48;2;120;10;10m' - FATAL.loggger = '\u001b[38;2;245;189;230m' - diff --git a/libs/utils/logger-old.py b/libs/utils/logger-old.py deleted file mode 100644 index 86e74a9..0000000 --- a/libs/utils/logger-old.py +++ /dev/null @@ -1,1116 +0,0 @@ -""" -@author shenjackyuanjie -@contact 3695888@qq.com -""" -# ------------------------------- -# Difficult Rocket -# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com -# All rights reserved -# ------------------------------- -import io -import os -import re -import sys -import time -import enum -import atexit -import inspect -import warnings -import threading - -from types import FrameType -from dataclasses import dataclass -from logging import NOTSET, DEBUG -from typing import NamedTuple, Optional, Type, Union, Dict, Iterable, List - -Version = '1.1.0' - -# os.system('') -color_support = True - -if sys.platform == "win32": - try: - # https://stackoverflow.com/questions/36760127/... - # how-to-use-the-new-support-for-ansi-escape-sequences-in-the-windows-10-console - from ctypes import windll - - kernel32 = windll.kernel32 - kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) - except OSError: # pragma: no cover - color_support = False - -# print(os.path.abspath(os.curdir)) -# TODO 这个文件就是个大TODO -""" -如果想要直接使用 logger 来 logging -直接调用 logger.debug() 即可 -默认配置会有 ----------- -配置方式一 -直接使用 logger.Logger() -将会创建一个空 logger -可以自行通过 -配置方式二 -logger = logger.get_logger(name) -直接获取一个配置好的logger -""" - -color_reset_suffix = "\033[0m" -""" 只是用来重置颜色的后缀 """ - -re_find_color_code = r'\033\[[^\f\n\r\t\vm]*m' -re_color_code = re.compile(re_find_color_code) -re_find_formats = re.compile(r'\{\w+}') -# re_find_level_code = r'' - -""" -OFF > FATAL > ERROR > WARN > INFO > FINE > FINER > DEBUG > TRACE > ALL -logging.py -CRITICAL = 50 -FATAL = CRITICAL -ERROR = 40 -WARNING = 30 -WARN = WARNING -INFO = 20 -DEBUG = 10 -NOTSET = 0 -""" -FINE = 7 -TRACE = 5 -ALL = NOTSET - - -class LoggingLevel: - """定义LoggingLevel属性(即是变量) """ - CRITICAL = 50 - FATAL = CRITICAL - ERROR = 40 - WARNING = 30 - WARN = WARNING - INFO = 20 - DEBUG = 10 - FINE = 7 - TRACE = 5 - NOTSET = 0 - ALL = NOTSET - CRITICAL_t = 'CRITICAL' - FATAL_t = 'FATAL' - ERROR_t = 'ERROR' - WARNING_t = 'WARNING' - WARN_t = 'WARN' - INFO_t = 'INFO' - DEBUG_t = 'DEBUG' - FINE_t = 'FINE' - TRACE_t = 'TRACE' - NOTSET_t = 'NOTSET' - ALL_t = 'ALL' - - @staticmethod - def type() -> Type: - return int - - -logging_level_type = int - -level_name_map: Dict[logging_level_type, str] = { - LoggingLevel.ALL: 'ALL', # NOTSET - LoggingLevel.TRACE: 'TRACE', - LoggingLevel.FINE: 'FINE', - LoggingLevel.DEBUG: 'DEBUG', - LoggingLevel.INFO: 'INFO', - LoggingLevel.WARNING: 'WARNING', # WARN - LoggingLevel.ERROR: 'ERROR', - LoggingLevel.FATAL: 'FATAL' -} - -name_level_map: Dict[str, logging_level_type] = { - 'NOTSET': LoggingLevel.ALL, - 'ALL': LoggingLevel.ALL, - 'TRACE': LoggingLevel.TRACE, - 'FINE': LoggingLevel.FINE, - 'DEBUG': LoggingLevel.DEBUG, - 'INFO': LoggingLevel.INFO, - 'WARNING': LoggingLevel.WARNING, - 'WARN': LoggingLevel.WARNING, - 'ERROR': LoggingLevel.ERROR, - 'CRITICAL': LoggingLevel.FATAL, - 'FATAL': LoggingLevel.FATAL -} - - -def get_level_by_name(name: str) -> logging_level_type: - return name_level_map[name.upper()] - - -def get_name_by_level(level: logging_level_type) -> str: - return level_name_map[level] - - -logger_configs = { - 'Logger': { - 'root': { - 'level': DEBUG, - 'color': 'main_color', - 'file': 'main_log_file', - }, - 'client': { - 'level': TRACE, - 'color': 'fancy_main_color', - 'file': 'main_log_file', - }, - 'server': { - 'level': TRACE, - 'color': 'DiGua_color', - 'file': 'main_log_file', - }, - - }, - 'Color': { - 'main_color': { - 'main_time': '\033[38;2;201;222;56m', - 'file_name': '\033[38;2;0;255;180m', - 'code_line': '\033[38;2;0;255;180m', - 'info': '\033[0m', - 'message': '\033[0m', - 'logger': '\033[0m', - 'marker': '\033[0m', - LoggingLevel.TRACE_t: {'info': '\033[38;2;138;173;244m'}, - LoggingLevel.FINE_t: {'info': '\033[35;48;2;44;44;54m'}, - LoggingLevel.DEBUG_t: {'info': '\033[38;2;133;138;149m'}, - LoggingLevel.INFO_t: {'info': '\033[0m'}, - LoggingLevel.WARNING_t: {'info': '\033[33m'}, - LoggingLevel.ERROR_t: {'info': '\033[31m'}, - LoggingLevel.FATAL_t: {'info': '\033[38;2;255;255;0;48;2;120;10;10m', 'logger': '\033[38;2;245;189;230m'} - }, - 'fancy_main_color': { - 'main_time': '\033[38;2;201;222;56m', - 'file_name': '\033[38;2;0;255;180m', - 'code_line': '\033[38;2;0;255;180m', - 'info': '\033[0m', - 'message': '\033[0m', - 'logger': '\033[0m', - 'marker': '\033[0m', - LoggingLevel.TRACE_t: {'info': '\033[38;2;138;173;244m', 'message': '\033[38;2;138;173;244m'}, - LoggingLevel.FINE_t: {'info': '\033[35;48;2;44;44;54m', 'message': '\033[35m'}, - LoggingLevel.DEBUG_t: {'info': '\033[38;2;133;138;149m', 'message': '\033[38;2;133;138;149m'}, - LoggingLevel.INFO_t: {'info': '\033[0m', 'message': '\033[0m'}, - LoggingLevel.WARNING_t: {'info': '\033[33m', 'message': '\033[33m'}, - LoggingLevel.ERROR_t: {'info': '\033[31m', 'message': '\033[31m'}, - LoggingLevel.FATAL_t: {'info': '\033[38;2;255;255;0;48;2;120;10;10m', - 'message': '\033[38;2;255;255;0;48;2;120;10;10m', 'logger': '\033[38;2;245;189;230m'} - }, - 'DiGua_color': { - # catppuccin Macchiato - 'main_time': '\033[38;2;202;211;245m', - 'file_name': '\033[38;2;139;213;202m', - 'code_line': '\033[38;2;166;218;149m', - 'info': '\033[0m', - 'logger': '\033[0m', - 'message': '\033[0m', - 'marker': '\033[0m', - LoggingLevel.TRACE_t: {'info': '\033[38;2;138;173;244m', 'message': '\033[38;2;138;173;244m'}, - LoggingLevel.FINE_t: {'info': '\033[38;2;198;160;246m', 'message': '\033[38;2;198;160;246m'}, - LoggingLevel.DEBUG_t: {'info': '\033[38;2;133;138;149m', 'message': '\033[38;2;133;138;149m'}, - LoggingLevel.INFO_t: {'info': '\033[0m', 'message': '\033[0m'}, - LoggingLevel.WARNING_t: {'info': '\033[38;2;245;169;127m', 'message': '\033[38;2;245;169;127m'}, - LoggingLevel.ERROR_t: {'info': '\033[38;2;237;135;150m', 'message': '\033[38;2;237;135;150m'}, - LoggingLevel.FATAL_t: {'info': '\033[38;2;255;255;0;48;2;120;10;10m', - 'message': '\033[38;2;255;255;0;48;2;120;10;10m', 'logger': '\033[38;2;245;189;230m'} - } - }, - 'File': { - 'main_log_file': { - 'mode': 'a', - 'encoding': 'utf-8', - 'level': TRACE, - 'file_name': './logs/{long_time}_logs.md', - 'cache_len': 10, - 'cache_time': 1 - }, - }, - 'Formatter': { - 'MESSAGE': { - 'format': '[{long_time}] [{logger_name}] {level} | {file_name}:{code_line} | {message}' - }, - 'file_name': 'no frame', - 'code_line': 'no frame', - 'short_time': '%Y-%m-%d %H-%M-%S', - 'long_time': '%Y-%m-%d %H-%M-%S:%%S', - } -} - - -@dataclass -class LogFileConf: - file_name: str = 'logs/log.txt' - file_mode: str = 'a' - file_encoding: str = 'utf-8' - file_level: logging_level_type = LoggingLevel.DEBUG - file_cache_len: int = 20 - file_cache_time: Union[int, float] = 1 - - -class Message_content(NamedTuple): - """用于存储 log 信息的不可变元组""" - log_time: float - text: str - level: int - logger_name: Optional[str] = 'root' - marker: Optional[str] = None - end: Optional[str] = '\n' - flush: Optional[bool] = False - frame: Optional[FrameType] = None - - def __str__(self): - return ( - f"Message Content at {self.log_time}|by logger {self.logger_name}|in level {self.level}" - f"|with marker {self.marker}|ends as {self.end}|" - f"by frame {self.frame}|{'and will flush' if self.flush else 'and will not flush'}|" - f"text are: {self.text}" - ) - - -class ThreadLock: - """一个用来 with 的线程锁""" - - def __init__(self, the_lock: threading.Lock, time_out: Union[float, int] = 1 / 60) -> None: - """ - :param the_lock: 用于 with 的线程锁 - :param time_out: with 的超时时间 - """ - self.lock = the_lock - self.time_out = time_out - - def __enter__(self): - self.lock.acquire(timeout=self.time_out) - if not self.lock.locked(): - raise RuntimeError(f'Lock time Out with {self.time_out}') - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.lock.locked(): - self.lock.release() - - -class ListCache: - """一个线程安全的列表缓存""" - - def __init__(self, lock: ThreadLock): - self._cache = [] - self.with_thread_lock = lock - - def append(self, value: Union[str, Iterable[str]]): - with self.with_thread_lock: - if isinstance(value, str): - self._cache.append(value) - elif isinstance(value, Iterable): - self._cache.append(*value) - else: - raise TypeError( - f"cache must be string or Iterable. not a {type(value)}") - - def __getitem__(self, item) -> str: - assert isinstance(item, int) - with self.with_thread_lock: - try: - return self._cache[item] - except IndexError as exp: - print(f'cache:{self.cache}') - raise IndexError( - f'there is no cache at {item}!\n' - f'cache:{self.cache}\n' - f'{exp}' - ) from exp - - def __call__(self, *args, **kwargs) -> List[str]: - return self.cache - - def __iter__(self): - self._iter_len = len(self.cache) - return self - - def __next__(self): - if self._iter_len == -1: - del self._iter_len - raise StopIteration('there is no more cache') - returns = self.cache[-self._iter_len] - self._iter_len -= 1 - return returns - - def __bool__(self): - return len(self.cache) > 0 - - @property - def cache(self): - return self._cache - - def clear(self): - with self.with_thread_lock: - self.cache.clear() - - -class ColorCodeEnum(enum.Enum): - main_time = "main_time" - code_line = "code_line" - file_name = "file_name" - info = "info" - message = "message" - logger = "logger" - marker = "marker" - - -class FormatCodeEnum(enum.Enum): - long_time: str = '%Y-%m-%d %H-%M-%S:%%S' - short_time: str = '%Y-%m-%d %H-%M-%S' - logger_name: str = '{logger_name}' - level: str = '{level}' - fine_name: str = '{file_name}' - code_line: str = '{code_line}' - marker: str = '{marker}' - message: str = '{message}' - - -class FormatterConfig(NamedTuple): - """ Named Tuple 真好用 """ - support_color: bool - format: str - formats: Dict[str, str] - color: Dict[str, Union[str, Dict[str, str]]] - - -class FormatterTemplate: - """用于格式化 log 信息的模板类""" - - def __init__(self, configs: FormatterConfig): - self.configs = configs - - def format(self, message: Message_content) -> str: - raise NotImplementedError('There is a formatter that not implemented') - - -class StdFormatter(FormatterTemplate): - """ 一个标准的格式化类 """ - - def __init__(self, configs: FormatterConfig): - super().__init__(configs=configs) - - def format_time(self, input_time: Optional[float] = None) -> Dict[str, str]: - millisecond = str((input_time - int(input_time)) * 1000) - long_time = time.strftime(self.configs.formats['long_time'].replace('%%S', millisecond)) - short_time = time.strftime(self.configs.formats['short_time'].replace('%%S', millisecond)) - return {'{long_time}': long_time, '{short_time}': short_time} - - def get_color_code(self, level: str, content: ColorCodeEnum) -> str: - assert content in ColorCodeEnum - if content in self.configs.color[level]: - return self.configs.color[level][content.name].replace(r"\u001b", '\u001b') - return self.configs.color[content.name].replace(r'\u001b', '\u001b') - - """ - format 支持的内容: - {long_time}: 长时间 - {short_time}: 短时间 - {logger_name}: logger 名称 - {level}: 记录等级 - {file_name}: 文件名 - {code_line}: 代码行 - {marker}: 标记 - {message}: 消息 - """ - - def color_format(self, message: Message_content) -> str: - if not self.configs.support_color: - return self.format(message=message) - times = self.format_time(input_time=message.log_time) - need_colors = list(re_find_formats.findall(self.configs.format)) - new_config = self.configs.format - for need_color in need_colors: - if not hasattr(FormatCodeEnum, need_color[1:-1]): - warnings.warn(f'logger config wrong! get {need_color}') - continue - color_code = color_reset_suffix - if need_color[1:-1] in self.configs.color[level_name_map[message.level]]: - color_code = self.configs.color[level_name_map[message.level]][need_color[1:-1]] - elif need_color[1:-1] in self.configs.color: - color_code = self.configs.color[need_color[1:-1]] - new_config.replace(need_color, f'{color_code}{need_color}{color_reset_suffix}') - - def format(self, message: Message_content) -> str: - """ - 将传入得 message 中的信息格式化之后输出为单一字符串 - :param message: - :return: str - """ - times = self.format_time(input_time=message.log_time) - level = level_name_map[message.level] - formatted_str = self.configs.format - for time_text, value in times.items(): - formatted_str.replace(time_text, value) - - formatted_str.replace("{marker}", message.marker) \ - .replace("{message}", message.text) \ - .replace("{level}", level) - file_name = '*' - code_line = '*' - if message.frame is not None: - file_name = message.frame.f_code.co_filename - code_line = message.frame.f_lineno - formatted_str.replace("{file_name}", file_name) \ - .replace("{code_line}", code_line) - # 注意:类似这种“链式调用”不应超过 5 行,否则将降低可读性 - # 关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL - # 依照 RFC 2119 的叙述解读 - return formatted_str - - -""" -logger a -.enable = True -.level = 0 -handler b -> shell - .enable = True - .level = 30 -handler c -> file - .enable = True - .level = 0 - -a.info('abc') - -b -> none -c -> [info]'abc' - -""" - - -class StreamHandlerTemplate: - """ 一个一个一个 stream template 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 """ - name = "handler temple" - - def __init__(self, level: int, formatter: Optional[FormatterTemplate] = None): - """ - :param level: 处理器输出等级 - :param formatter: 格式化处理器 - """ - self.enable = True - self.level = level - self.formatter = formatter - - def write(self, message: Message_content) -> bool: - """ - 向 输出 文件/stdio 写入信息 - :param message: 要写入的信息包 - :return: 是否写入成功 - """ - raise NotImplementedError("You Need to Implement the 'write' method") - - def flush(self) -> bool: - """ - 刷新缓冲区 - :return: 是否刷新成功 - """ - return True - - def close(self) -> bool: - """:return: stream 是否关闭成功""" - raise NotImplementedError("You Need to Implement the 'close' method") - - def setFormatter(self, fmt: FormatterTemplate) -> None: - """ - 用于与 logging 兼容 - :param fmt: 要设置的格式化处理器 - :return: None - """ - self.formatter = fmt - - def __str__(self): - """ - :return: 自己的名字 等级 - """ - return f"{self.name}{{level={self.level}}}" - - -class StdHandler(StreamHandlerTemplate): - """ 向标准输入输出流输出信息 """ - name = "std handler" - - def __init__(self, level: int, formatter: Optional[FormatterTemplate] = None): - """ - :param level: 级别 - :param formatter: 格式器 - """ - super().__init__(level=level, formatter=formatter) - - def write(self, message: Message_content) -> bool: - print(self.formatter.format(message), end=message.end, flush=message.flush) - return True - - def close(self) -> bool: - return True - - def flush(self) -> bool: - print('', end='', flush=True) - return True - - def __repr__(self): - return f'StdHandler(level={self.level}, formatter={self.formatter})' - - -class CachedFileHandler(StreamHandlerTemplate): - """ 缓存文件的处理器 """ - name = 'cached file handler' - - def __init__(self, level: int, formatter: Optional[FormatterTemplate] = None, - file_conf: Union[dict, LogFileConf, None] = None): - """ - :param level: - :param formatter: - :param file_conf: 文件配置 - """ - super().__init__(level=level, formatter=formatter) - if file_conf is None: - self.file_conf = LogFileConf() - elif isinstance(file_conf, dict): - self.file_conf = LogFileConf(**file_conf) - elif isinstance(file_conf, LogFileConf): - self.file_conf = file_conf - # 缓存 - self.len = 0 - self.cache_stream = io.StringIO() - # 状态 - self.started = True - self.thread_started = False - self.flushing = False - # 同步锁 - self.threaded_write = threading.Timer(1, self.flush, kwargs={'by_thread': True}) # 基于 timer 的多线程 - - def _start_thread(self) -> bool: - """ - 如果成功启动 返回 True - 已经启动则返回 False - :return: 是否启动 - """ - if self.thread_started: - return False - self.threaded_write = threading.Timer(1, self.flush, kwargs={'by_thread': True}) - self.threaded_write.start() - self.thread_started = True - return True - - def _stop_thread(self) -> bool: - """ - 成功关闭 返回 True - 未开启/关闭失败 返回 False - :return: 是否成功关闭 - """ - if not self.threaded_write.is_alive(): - self.thread_started = False - return False - self.threaded_write.cancel() - - def write(self, message: Message_content) -> bool: - self.len += 1 - formatted_message = f'{self.formatter.format(message)}{message.end}' - self.cache_stream.write(formatted_message) - if message.flush or self.len >= self.file_conf.file_cache_len: - if not self.flush(): - self.flush() - elif not self.thread_started: - self._start_thread() - return True - - def close(self) -> bool: - self.cache_stream.close() - return True - - def flush(self, by_thread: Optional[bool] = False) -> bool: - if by_thread: - self.threaded_write = threading.Timer(1, self.flush, kwargs={'by_thread': True}) - self.threaded_write.start() - if self.flushing: - return False - self.flushing = True - if cache := self.cache_stream.getvalue(): - self.flushing = True - self.cache_stream.close() - self.cache_stream = io.StringIO() - self.len = 0 - with open(file=self.file_conf.file_name, mode=self.file_conf.file_mode, - encoding=self.file_conf.file_encoding) as log_file: - log_file.write(cache) - self.flushing = False - return True - - -class LogFileCache: - """日志文件缓存""" - - def __init__(self, file_conf: dict): - """ - :param file_conf: 日志文件配置 - """ - # 配置相关 - self._logfile_name = os.path.abspath(format_str(file_conf['file_name'])) # log 文件名称 - self.level: logging_level_type = file_conf.get('level', DEBUG) - self.file_conf = file_conf - self.flush_time = file_conf['cache_time'] # 缓存刷新时长 - self.cache_entries_num = file_conf['cache_len'] - self.started = True - self.running = False - # 同步锁 - self.cache_lock = threading.Lock() # 主锁 - self.time_limit_lock = ThreadLock(self.cache_lock, time_out=1 / 60) # 直接用于 with 的主锁 - self.threaded_write = threading.Timer(1, self._log_file_time_write, kwargs={'thread': True}) # 基于 timer 的多线程 - # 日志缓存表 - self.log_cache = ListCache(self.time_limit_lock) - self.file_setup() - - def file_setup(self): - cache_time = 0 - file_type = self.logfile_name[self.logfile_name.rfind('.'):] - file_pure_name = self.logfile_name[:self.logfile_name.rfind('.')] - while os.path.isfile(self.logfile_name): - cache_time += 1 - self.logfile_name = f'{file_pure_name}-{cache_time}{file_type}' - - def end_thread(self) -> None: - """结束日志写入进程,顺手把目前的缓存写入""" - self.cache_lock.acquire(blocking=True) - if self.running: - self.threaded_write.cancel() - self.running = False - self.started = False - self._log_file_time_write() - atexit.unregister(self.end_thread) - - def start_thread(self) -> None: - self.threaded_write.start() - self.started = True - self.running = True - atexit.register(self.end_thread) - - @property - def logfile_name(self) -> str: - self._logfile_name: str - return self._logfile_name - - @logfile_name.setter - def logfile_name(self, value: str) -> None: - with self.time_limit_lock: - self._logfile_name = value - - def _log_file_time_write(self, thread: bool = False) -> None: - """使用 threading.Timer 调用的定时写入日志文件的函数""" - if self.log_cache: - with self.time_limit_lock: - if self.log_cache: - with open(file=self.logfile_name, - encoding=self.file_conf.get('encoding', 'utf-8'), - mode=self.file_conf.get('mode', 'a')) as log_file: - log_file.writelines(self.log_cache.cache.copy()) - self.log_cache.clear() - if thread: - self.running = False - - def write_logs(self, string: str, flush: bool = False) -> None: - self.log_cache.append(string) - if len(self.log_cache.cache) >= 10: - self._log_file_time_write() - return None - if flush: - self._log_file_time_write() - if self.started and not self.running: - self.threaded_write = threading.Timer(1, self._log_file_time_write, kwargs={ - 'thread': True}) # 基于 timer 的多线程 - self.threaded_write.start() - self.running = True - - -class Logger: - """shenjackのlogger""" - - def __init__(self, - name: str = 'root', - level: int = DEBUG, - file_conf: Optional[List[LogFileCache]] = None, - colors: Optional[Dict[Union[int, str], - Dict[str, str]]] = None, - formats=None - ) -> None: - """ - 配置模式: 使用 kwargs 配置 - :param name: logger 名称 默认为 root - :param level: logging 输出等级 默认为 DEBUG(10) - :param file_conf: logger 的文件处理配置 - :param colors: dict 颜色配置 - :param formats: 格式化配置 - """ - self.enable = True - self.name = name - self.level = level - self.min_level = self.level - self.colors = colors or logger_configs['Color']['main_color'] - self.formats = formats or logger_configs['Formatter'].copy() - self.streams: List[StreamHandlerTemplate] = [] - self.handler: List[StdHandler] = [] - if file_conf: - self.file_cache = file_conf - self.min_level = min(min(file.level for file in file_conf), self.level) - else: - self.file_cache = [] - self.warn = self.warning - - def format_formats(self) -> None: - if 'long_time' not in self.formats: - self.formats['long_time'] = '%Y-%m-%d %H-%M-%S:%%S' - if 'short_time' not in self.formats: - self.formats['short_time'] = '%Y-%m-%d %H-%M-%S' - - def add_stream(self, stream: StreamHandlerTemplate) -> bool: - """ - 向 logger 添加一个输出方法 (stream handler) - :param stream: 将要添加的 stream handler - :return: 是否添加成功 如果 stream 已经存在则返回 False - """ - if stream in self.streams: - return False - self.streams.append(stream) - return True - - def enabled_for(self, level: logging_level_type) -> bool: - return level >= self.min_level if self.enable else False - - # def format_time(self, input_time: Optional[float] = None) -> Dict[str, str]: - # # 毫秒 - # get_time: float = input_time or time.time() - # millisecond = str((get_time - int(get_time)) * 1000) - # long_time = time.strftime( - # self.formats['long_time'].replace('%%S', millisecond)) - # short_time = time.strftime( - # self.formats['short_time'].replace('%%S', millisecond)) - # return {'long_time': long_time, 'short_time': short_time} - - # def filter_and_make_log(): make_log(formatted_string) - def make_log(self, *values: object, - level: int, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - if frame is None: - if (frame := inspect.currentframe()) is not None: - frame = ( - frame - if frame.f_back is None - else ( - frame.f_back - if frame.f_back.f_back is None - else frame.f_back.f_back - ) - ) - message = Message_content(log_time=time.time(), - text=sep.join(i if type(i) is str else str(i) for i in values), - level=level, logger_name=self.name, marker=marker, end=end, flush=flush, frame=frame) - - # 调用 steams - for stream in self.streams: - stream.write(message) - - message_color = self.colors[get_name_by_level( - level)]['message'] if 'message' in self.colors[get_name_by_level(level)] else self.colors['message'] - text = f"{message_color}{sep.join(i if type(i) is str else str(i) for i in values)}{color_reset_suffix}" - # print('abc', 'abc', marker='123') - print_text = self.format_text(level=level, text=text, frame=frame) - if level >= self.level: - print(print_text, end=end) - for file in self.file_cache: - file: LogFileCache - if level < file.level: - continue - file.write_logs(f"{re.sub(re_find_color_code, '', print_text)}{end}", flush=flush) - return print_text - - def format_text(self, level: int, text: str, frame: Optional[FrameType]) -> str: - level_with_color = ( - f"[{self.colors[get_name_by_level(level)].get('info')}" - f"{get_name_by_level(level)}{color_reset_suffix}]" - ) - level_with_color = f"{level_with_color}{' ' * (9 - len_without_color_maker(level_with_color))}" - formats = self.formats.copy() - if frame is not None: - formats['file_name'] = ( - f"{self.colors[get_name_by_level(level)].get('file_name', self.colors['file_name'])}" - f"{os.path.split(frame.f_code.co_filename)[-1]}{color_reset_suffix}" - ) - formats['code_line'] = ( - f"{self.colors[get_name_by_level(level)].get('code_line', self.colors['code_line'])}" - f"{frame.f_lineno}{color_reset_suffix}" - ) - formats['logger_name'] = ( - f'{self.colors[get_name_by_level(level)].get("logger", self.colors["logger"])}' - f'{self.name}{color_reset_suffix}' - ) - now_time = str(time.time()) - for key, value in formats.items(): - if isinstance(value, dict) and 'strftime' in value: - value['strftime']: str - formats[key] = ( - f"{self.colors[get_name_by_level(level)].get(key, self.colors[key])}" - f"{time.strftime(value['strftime'].replace('%%S', now_time[now_time.find('.') + 1:now_time.find('.') + 5]))}" - f"{color_reset_suffix}" - ) - return self.formats['MESSAGE']['format'].format( - level_with_color=level_with_color, - level=level_with_color, - message=text, - **formats - ) - - def trace(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.TRACE, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def fine(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.FINE, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def debug(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.DEBUG, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def info(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.INFO, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def warning(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.WARNING, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def error(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.ERROR, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - def fatal(self, *values: object, - marker: Optional[str] = None, - sep: Optional[str] = ' ', - end: Optional[str] = '\n', - flush: Optional[bool] = False, - frame: Optional[FrameType] = None - ) -> Optional[str]: - return self.make_log(*values, level=LoggingLevel.FATAL, marker=marker, sep=sep, end=end, flush=flush, - frame=frame) - - -_logger_class = Logger - - -class RootLogger(Logger): - """ 默认的 logger """ - - def __init__(self, level: int = LoggingLevel.WARNING, *args, **kwargs): - super().__init__(level=level, *args, **kwargs) - - -root_logger = RootLogger() - - -def basic_config() -> None: - ... - - -trace = root_logger.trace -fine = root_logger.fine -debug = root_logger.debug -info = root_logger.info -warning = root_logger.warning -error = root_logger.error -fatal = root_logger.fatal - - -def format_str(text: str) -> str: - formats = logger_configs['Formatter'].copy() - now_time = str(time.time()) - for key, value in formats.items(): - if isinstance(value, dict) and 'strftime' in value: - value['strftime']: str - formats[key] = ( - time.strftime(value['strftime'].replace('%%S', now_time[now_time.find('.') + 1:now_time.find('.') + 5])) - ) - return text.format(**formats) - - -def len_without_color_maker(text: str) -> int: - with_out_text = re.sub(re_find_color_code, '', text) - return len(with_out_text) - - -def gen_file_conf(file_name: str, - file_level: int = DEBUG, - file_mode: str = 'a', - file_encoding: str = 'utf-8', - file_cache_len: int = 10, - file_cache_time: Union[int, float] = 1 - ) -> dict: - """ - 生成一个文件配置 - :param file_name: 日志文件名 - :param file_level: 日志文件记录级别 - :param file_mode: 文件模式 - :param file_encoding: 文件编码 - :param file_cache_len: 文件缓存长度 - :param file_cache_time: 文件缓存时间 - :return: 生成的配置 - """ - return {'file_name': file_name, - 'level': file_level, - 'mode': file_mode, - 'encoding': file_encoding, - 'cache_len': file_cache_len, - 'cache_time': file_cache_time} - - -def gen_color_conf(color_name: Optional[str] = None, **colors) -> dict: - default_color = logger_configs['Color']['main_color' if color_name is None else color_name].copy() - default_color.update(colors) - return default_color - - -def logger_with_default_settings(name: str, - level: int = DEBUG, - file_conf: Optional[dict] = None, - colors: Optional[dict] = None, - formats: Optional[dict] = None - ) -> Logger: - return Logger(name=name, - level=level, - file_conf=[LogFileCache(gen_file_conf(**file_conf))], - colors=gen_color_conf(**colors), - formats=logger_configs['Formatter'].copy().update(formats)) - - -def add_file_config(conf_name: str, - file_name: str, - file_level: int = DEBUG, - file_mode: str = 'a', - file_encoding: str = 'utf-8', - file_cache_len: int = 10, - file_cache_time: Union[int, float] = 1 - ) -> None: - """ - 向 logger config 里添加一个文件配置 - :param conf_name: 文件配置名称 - :param file_name: 日志文件名 - :param file_level: 日志文件记录级别 - :param file_mode: 文件模式 - :param file_encoding: 文件编码 - :param file_cache_len: 文件缓存长度 - :param file_cache_time: 文件缓存时间 - :return: None - """ - logger_configs['File'][conf_name] = {'file_name': file_name, - 'level': file_level, - 'mode': file_mode, - 'encoding': file_encoding, - 'cache_len': file_cache_len, - 'cache_time': file_cache_time} - - -def get_logger(name: str = 'root') -> Logger: - """ - 此函数用于从 global_config 中取出对应的配置建立一个相应的 logger - :param name: logger的名称 默认为 root - :return: 创建好的 logger - """ - if name in logger_configs['Logger']: - the_config = logger_configs['Logger'][name] - else: - the_config = logger_configs['Logger']['root'] - file_handler = None - if 'file' in the_config: - file_handler = [LogFileCache( - logger_configs['File'][the_config['file']])] - color = the_config['color'] if 'color' in the_config else 'main_color' - return Logger(name=name, - level=the_config['level'], - file_conf=file_handler, - colors=logger_configs['Color'][color], - formats=logger_configs['Formatter'].copy()) - - -def test_logger(the_logger: Logger): - the_logger.trace('tracing') - the_logger.trace('tracing') - the_logger.trace('tracing') - the_logger.fine('some fine!') - the_logger.fine('some fine!') - the_logger.fine('some fine!') - the_logger.debug('debugging') - the_logger.debug('debugging') - the_logger.debug('debugging') - the_logger.info("Hello World!!") - the_logger.info("Hello World!!") - the_logger.warn('warning') - the_logger.warn('warning') - the_logger.error('error haaaa') - the_logger.error('error haaaa') - the_logger.fatal('oh no') - - -if __name__ == "__main__": - os.chdir('../../') - logger = get_logger('server') - - logger.info('my name is:', logger.name) - a_logger = get_logger('client') - - a_logger.trace('tracing') - a_logger.fine('some fine!') - a_logger.debug('debugging') - a_logger.info("Hello World!!") - a_logger.warn('warning') - a_logger.error('error haaaa') - a_logger.fatal('oh no') - logger.info('my name is:', logger.name) - # for _ in range(5): - test_logger(logger) - test_logger(a_logger) - print(Message_content(log_time=time.time(), text='aaa', level=4, marker='abc', end='abc', flush=False, - frame=inspect.currentframe())) - print(ColorCodeEnum.code_line.name) diff --git a/scripts/lndl-config.py b/scripts/lndl-config.py index bc6efa7..95f3679 100644 --- a/scripts/lndl-config.py +++ b/scripts/lndl-config.py @@ -13,12 +13,8 @@ from lib_not_dr.nuitka import nuitka_config_type, raw_config_type def gen_pyglet_no_follow_import() -> list: no_follow_import = [] - no_follow_import += [ - f"pyglet.app.{x}" for x in ["win32", "xlib", "cocoa"] - ] - no_follow_import += [ - f"pyglet.input.{x}" for x in ["win32", "linux", "macos"] - ] + no_follow_import += [f"pyglet.app.{x}" for x in ["win32", "xlib", "cocoa"]] + no_follow_import += [f"pyglet.input.{x}" for x in ["win32", "linux", "macos"]] no_follow_import += [ f"pyglet.libs.{x}" for x in ["win32", "x11", "wayland", "darwin", "egl", "headless"] @@ -36,9 +32,7 @@ def gen_pyglet_no_follow_import() -> list: "headless", ) ] - no_follow_import += [ - f"pyglet.gl.{x}" for x in ["win32", "xlib", "cocoa", "headless"] - ] + no_follow_import += [f"pyglet.gl.{x}" for x in ["win32", "xlib", "cocoa", "headless"]] mult_plat_libs = ["app", "input", "libs", "window", "canvas", "gl"] if platform.system() == "Windows": @@ -59,15 +53,15 @@ def gen_pyglet_no_follow_import() -> list: def main(config: raw_config_type) -> nuitka_config_type: - print('debug', config) - config = config['cli'] + print("debug", config) + config = config["cli"] - config['file-version'] = str(build_version) - config['product-version'] = str(sdk_version) - config['macos-app-version'] = str(sdk_version) + config["file-version"] = str(build_version) + config["product-version"] = str(sdk_version) + config["macos-app-version"] = str(sdk_version) - config['nofollow-import-to'] += gen_pyglet_no_follow_import() - config['output-dir'] = './build/nuitka-' + platform.system().lower() + config["nofollow-import-to"] += gen_pyglet_no_follow_import() + config["output-dir"] = "./build/nuitka-" + platform.system().lower() - print('done', config) + print("done", config) return config