Browse Source

kivy: fix threading issue for window.show_error

related: 5e0df77df6

kivy 2.1 seemingly became more sensitive to threading issues.
This used to work on kivy 2.0 and older, but 2.1 is complaining.

```
E | lnworker.LNWallet.[default_wallet] | Exception in pay_invoice: TypeError('Cannot create graphics instruction outside the main Kivy thread')
Traceback (most recent call last):
  File "...\electrum\util.py", line 1184, in wrapper
    return await func(*args, **kwargs)
  File "...\electrum\lnworker.py", line 1178, in pay_invoice
    util.trigger_callback('payment_succeeded', self.wallet, key)
  File "...\electrum\util.py", line 1633, in trigger_callback
    callback(*args)
  File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
    self.show_info(_('Payment succeeded') + '\n\n' + description)
  File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
    self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
  File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
    self.show_info_bubble(text=error, icon=icon, width=width,
  File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
    info_bubble = self.info_bubble = Factory.InfoBubble()
  File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
    self._arrow_layout = BoxLayout()
  File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
    super(BoxLayout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
    super(Layout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
    self.canvas = Canvas(opacity=self.opacity)
  File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
  File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
  File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
E | gui.kivy.uix.dialogs.crash_reporter.ExceptionHook | exception caught by crash reporter
Traceback (most recent call last):
  File "...\electrum\gui\kivy\uix\screens.py", line 419, in pay_thread
    fut.result()
  File "...\Python310\lib\concurrent\futures\_base.py", line 446, in result
    return self.__get_result()
  File "...\Python310\lib\concurrent\futures\_base.py", line 391, in __get_result
    raise self._exception
  File "...\electrum\util.py", line 1184, in wrapper
    return await func(*args, **kwargs)
  File "...\electrum\lnworker.py", line 1178, in pay_invoice
    util.trigger_callback('payment_succeeded', self.wallet, key)
  File "...\electrum\util.py", line 1633, in trigger_callback
    callback(*args)
  File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
    self.show_info(_('Payment succeeded') + '\n\n' + description)
  File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
    self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
  File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
    self.show_info_bubble(text=error, icon=icon, width=width,
  File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
    info_bubble = self.info_bubble = Factory.InfoBubble()
  File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
    self._arrow_layout = BoxLayout()
  File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
    super(BoxLayout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
    super(Layout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
    self.canvas = Canvas(opacity=self.opacity)
  File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
  File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
  File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...\electrum\util.py", line 1128, in run_with_except_hook
    run_original(*args2, **kwargs2)
  File "...\Python310\lib\threading.py", line 946, in run
    self._target(*self._args, **self._kwargs)
  File "...\electrum\gui\kivy\uix\screens.py", line 421, in pay_thread
    self.app.show_error(repr(e))
  File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
    self.show_info_bubble(text=error, icon=icon, width=width,
  File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
    info_bubble = self.info_bubble = Factory.InfoBubble()
  File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
    self._arrow_layout = BoxLayout()
  File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
    super(BoxLayout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
    super(Layout, self).__init__(**kwargs)
  File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
    self.canvas = Canvas(opacity=self.opacity)
  File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
  File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
  File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
 Exception in thread Thread-2 (pay_thread):
 Traceback (most recent call last):
   File "...\electrum\gui\kivy\uix\screens.py", line 419, in pay_thread
     fut.result()
   File "...\Python310\lib\concurrent\futures\_base.py", line 446, in result
     return self.__get_result()
   File "...\Python310\lib\concurrent\futures\_base.py", line 391, in __get_result
     raise self._exception
   File "...\electrum\util.py", line 1184, in wrapper
     return await func(*args, **kwargs)
   File "...\electrum\lnworker.py", line 1178, in pay_invoice
     util.trigger_callback('payment_succeeded', self.wallet, key)
   File "...\electrum\util.py", line 1633, in trigger_callback
     callback(*args)
   File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
     self.show_info(_('Payment succeeded') + '\n\n' + description)
   File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
     self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
   File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
     self.show_info_bubble(text=error, icon=icon, width=width,
   File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
     info_bubble = self.info_bubble = Factory.InfoBubble()
   File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
     self._arrow_layout = BoxLayout()
   File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
     super(BoxLayout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
     super(Layout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
     self.canvas = Canvas(opacity=self.opacity)
   File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
   File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
   File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
 TypeError: Cannot create graphics instruction outside the main Kivy thread

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "...\electrum\util.py", line 1128, in run_with_except_hook
     run_original(*args2, **kwargs2)
   File "...\Python310\lib\threading.py", line 946, in run
     self._target(*self._args, **self._kwargs)
   File "...\electrum\gui\kivy\uix\screens.py", line 421, in pay_thread
     self.app.show_error(repr(e))
   File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
     self.show_info_bubble(text=error, icon=icon, width=width,
   File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
     info_bubble = self.info_bubble = Factory.InfoBubble()
   File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
     self._arrow_layout = BoxLayout()
   File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
     super(BoxLayout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
     super(Layout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
     self.canvas = Canvas(opacity=self.opacity)
   File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
   File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
   File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
 TypeError: Cannot create graphics instruction outside the main Kivy thread

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "...\Python310\lib\threading.py", line 1009, in _bootstrap_inner
     self.run()
   File "...\electrum\util.py", line 1130, in run_with_except_hook
     sys.excepthook(*sys.exc_info())
   File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 188, in <lambda>
     sys.excepthook = lambda exctype, value, tb: self.handle_exception(value)
   File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 199, in handle_exception
     e = CrashReporter(self.main_window, *exc_info)
   File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 100, in __init__
     Factory.Popup.__init__(self)
   File "...\Python310\site-packages\kivy\uix\modalview.py", line 195, in __init__
     super(ModalView, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\anchorlayout.py", line 68, in __init__
     super(AnchorLayout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
     super(Layout, self).__init__(**kwargs)
   File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
     self.canvas = Canvas(opacity=self.opacity)
   File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
   File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
   File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
 TypeError: Cannot create graphics instruction outside the main Kivy thread

```
patch-4
SomberNight 3 years ago
parent
commit
1f6bd9a694
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 13
      electrum/gui/kivy/main_window.py

13
electrum/gui/kivy/main_window.py

@ -414,6 +414,7 @@ class ElectrumWindow(App, Logger, EventListener):
self.password = None
self._use_single_password = False
self.resume_dialog = None
self.gui_thread = threading.current_thread()
App.__init__(self)#, **kwargs)
Logger.__init__(self)
@ -1100,6 +1101,17 @@ class ElectrumWindow(App, Logger, EventListener):
return
self.qr_dialog(label.name, label.data, show_text_with_qr)
def scheduled_in_gui_thread(func):
"""Decorator to ensure that func runs in the GUI thread.
Note: the return value is swallowed!
"""
def wrapper(self: 'ElectrumWindow', *args, **kwargs):
if threading.current_thread() == self.gui_thread:
func(self, *args, **kwargs)
else:
Clock.schedule_once(lambda dt: func(self, *args, **kwargs))
return wrapper
def show_error(self, error, width='200dp', pos=None, arrow_pos=None,
exit=False, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/error', duration=0,
modal=False):
@ -1117,6 +1129,7 @@ class ElectrumWindow(App, Logger, EventListener):
duration=duration, modal=modal, exit=exit, pos=pos,
arrow_pos=arrow_pos)
@scheduled_in_gui_thread
def show_info_bubble(self, text=_('Hello World'), pos=None, duration=0,
arrow_pos='bottom_mid', width=None, icon='', modal=False, exit=False):
'''Method to show an Information Bubble

Loading…
Cancel
Save