sirk390 / wxasync

asyncio support for wxpython
MIT License
76 stars 9 forks source link

StartCoroutine fails if called from OnInit() in 0.42 #12

Closed abulka closed 3 years ago

abulka commented 3 years ago

Launching this demo repro app using wxasync 0.41 works OK. Under 0.42 it fails with an error coroutine 'MainApp.async_callback' was never awaited

import wx
import time
from wxasync import AsyncBind, WxAsyncApp, StartCoroutine
import asyncio
from asyncio.events import get_event_loop
import wx.lib.newevent

SomeNewEvent, EVT_SOME_NEW_EVENT = wx.lib.newevent.NewEvent()

class MainApp(WxAsyncApp):

    def OnInit(self):
        self.frame = wx.Frame(None, -1, "test",)
        self.frame.CreateStatusBar()
        self.frame.Show(True)
        StartCoroutine(self.async_callback, self)
        return True

    async def async_callback(self):
        self.frame.SetStatusText("Button clicked")
        await asyncio.sleep(1)
        self.frame.SetStatusText("Working")
        await asyncio.sleep(1)
        self.frame.SetStatusText("Completed")

def main_async():
    application = MainApp(0)
    loop = get_event_loop()
    loop.run_until_complete(application.MainLoop())

if __name__ == "__main__":
    main_async()

Under wxasync version 0.42 I get

$ python repro042_bug.py 
Traceback (most recent call last):
  File "/Users/Andy/Devel/pynsource/src/repro042_bug.py", line 25, in OnInit
    StartCoroutine(self.async_callback, self)
  File "/Users/Andy/Devel/pynsource/src/wxasync042.py", line 108, in StartCoroutine
    app.StartCoroutine(coroutine, obj)
  File "/Users/Andy/Devel/pynsource/src/wxasync042.py", line 66, in StartCoroutine
    obj.Bind(wx.EVT_WINDOW_DESTROY, lambda event: self.OnDestroy(event, obj), obj) # BUG!!
  File "/Users/andy/.pyenv/versions/3.9.5/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/wx/core.py", line 1456, in _EvtHandler_Bind
    assert source is None or hasattr(source, 'GetId')
AssertionError
OnInit returned false, exiting...
sys:1: RuntimeWarning: coroutine 'MainApp.async_callback' was never awaited

caused by the following line of code in wxasync 7c7c5fe7559e83c47b4fd7d0007a92f7ef0e3b80

if obj not in self.BoundObjects:
    self.BoundObjects[obj] = defaultdict(list)
    obj.Bind(wx.EVT_WINDOW_DESTROY, lambda event: self.OnDestroy(event, obj), obj) # <--- cause of the crash

This is causing problems downstream in my app Pynsource.

sirk390 commented 3 years ago

Hi Andy, I've checked. It is because you call "StartCoroutine" on the MainApp. You should call it on the wx.Window instead. Replace:

     StartCoroutine(self.async_callback, self)       

by:

     StartCoroutine(self.async_callback, self.frame)       

I need to add the same exception check in "StartCoroutine" that is already in "AsyncBind" to make it more clear.

        if not isinstance(object, wx.Window):
            raise Exception("object must be a wx.Window")

Tell me if this solves your issue.

abulka commented 3 years ago

Hi,

Thanks for the quick response. Yes changing the second parameter to self.frame fixes the problem.

Curious how my app ever worked properly with the wrong parameter type being passed in by me before!, but happy I have a fix now.