从logging.Handler向PySimpleGUI.Multiline写入时抛出异常
问题描述
我开发了一个包含按钮和Multiline组件的PySimpleGUI程序,点击按钮会触发一个执行数秒的方法(其中调用了GitPython相关方法)。为了让该方法持续将输出写入Multiline,我创建了Logger并添加了自定义OutputHandler:
class OutputHandler(logging.Handler): window: PySimpleGUI.Window def __init__(self, window: PySimpleGUI.Window): super().__init__(logging.DEBUG) self.window = window def emit(self, record): print(record.msg) self.window["-OUTPUT-"].print(record.msg) self.window.refresh()
Logger被传入该方法,方法的输出及GitPython的进度信息均通过此Logger输出。但目前偶尔会出现如下异常:
Exception in thread Thread-12 (pump_stream): Traceback (most recent call last): File "...\Python310\lib\site-packages\git\cmd.py", line 142, in pump_stream handler(line) File "...\Python310\lib\site-packages\git\util.py", line 662, in handler return self._parse_progress_line(line.rstrip()) File "...\Python310\lib\site-packages\git\util.py", line 648, in _parse_progress_line self.update( File "MyGitPythonApp.py", line 97, in update self.logger.info(message) File "...\Python310\lib\logging\__init__.py", line 1477, in info self._log(INFO, msg, args, **kwargs) File "...\Python310\lib\logging\__init__.py", line 1624, in _log self.handle(record) File "...\Python310\lib\logging\__init__.py", line 1634, in handle self.callHandlers(record) File "...\Python310\lib\logging\__init__.py", line 1696, in callHandlers hdlr.handle(record) File "...\Python310\lib\logging\__init__.py", line 968, in handle self.emit(record) File "MyGitPythonApp.py", line 29, in emit self.window["-OUTPUT-"].print(record.msg) File "...\Python310\lib\site-packages\PySimpleGUI\PySimpleGUI.py", line 3582, in print _print_to_element(self, *args, end=end, sep=sep, text_color=kw_text_color, background_color=kw_background_color, justification=justification, File "...\Python310\lib\site-packages\PySimpleGUI\PySimpleGUI.py", line 17678, in _print_to_element multiline_element.update(outstring, append=True, text_color_for_value=text_color, background_color_for_value=background_color, autoscroll=autoscroll, File "...\Python310\lib\site-packages\PySimpleGUI\PySimpleGUI.py", line 3442, in update starting_point = self.Widget.index(tk.INSERT) File "...\Python310\lib\tkinter\__init__.py", line 3767, in index return str(self.tk.call(self._w, 'index', index)) RuntimeError: main thread is not in main loop The above exception was the direct cause of the following exception: Traceback (most recent call last): File "...\Python310\lib\threading.py", line 1016, in _bootstrap_inner self.run() File "...\Python310\lib\threading.py", line 953, in run self._target(*self._args, **self._kwargs) File "...\Python310\lib\site-packages\git\cmd.py", line 148, in pump_stream raise CommandError([f"<{name}-pump>"] + remove_password_if_present(cmdline), ex) from ex git.exc.CommandError: Cmd('<stderr-pump>') failed due to: RuntimeError('main thread is not in main loop') cmdline: <stderr-pump> git fetch -v --progress -- origin
请问该异常是什么原因导致的?
异常原因分析
这个异常的核心原因是子线程直接操作GUI组件:
- PySimpleGUI底层基于tkinter,tkinter的GUI操作严格要求必须在**主线程(主事件循环所在线程)**执行,不允许子线程直接修改GUI元素。
- GitPython在处理
git fetch这类命令的进度信息时,会开启独立子线程(比如报错中的Thread-12 (pump_stream))来实时读取命令输出并处理进度。 - 你的自定义
OutputHandler在emit方法中直接调用self.window["-OUTPUT-"].print()更新Multiline组件,而这个emit方法是被GitPython的子线程触发的,相当于在子线程中执行了GUI更新操作,违反了tkinter的线程安全规则,因此抛出RuntimeError: main thread is not in main loop异常,进而引发GitPython的CommandError。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

