Write to PySimpleGUI.Multiline from logging.Handler throws exception

76 Views Asked by At

I have a PySimpleGUI with a button and a multiline. When I click on the button, a method is called and running for a couple of seconds (calls i.a. GitPython methods). The method shall write its output to the multiline continuously. To do so I created a logger and added a handler to it:

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()

The logger is forwarded to my method and the method prints its output to it. The GitPython progress is also forwarded to this logger.

Now sporadically I'm facing the following exception:

    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

What's wrong here?

1

There are 1 best solutions below

0
On

Not to update GUI in logger method, try

    def emit(self, record):
        print(record.msg)
        self.window.write_event_value("Emit", record.msg)

and do the update in the event loop, like

while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event == "Emit":
        window["-Output-"].print(values[event])

window.close()

When I click on the button, a method is called and running for a couple of seconds

Using multithread if it took long time to block the event loop, like window.perform_long_operation (window.start_thread), or threading.Thread.start.