-
-
Notifications
You must be signed in to change notification settings - Fork 394
Description
Full code at the end but here's the 'interesting' snippet that causes trouble when run in guest mode. Tests run with Python 3.8.3 in Linux and 08fca2a.
async def mine():
global cscope
widget = QtWidgets.QWidget()
with trio.CancelScope() as cscope:
app.lastWindowClosed.connect(cscope.cancel)
widget.show()
return 1With just widget.show() I get:
/home/altendky/repos/trio/trio/_core/_run.py:2161: RuntimeWarning: Trio guest run got abandoned without properly finishing... weird stuff might happen
warnings.warn(With app.lastWindowClosed.connect(cscope.cancel) and widget.show() I get:
StopIteration: 1
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/altendky/repos/trio/trio/_core/_ki.py", line 159, in wrapper
locals()
SystemError: <built-in function locals> returned a result with an error set
/home/altendky/repos/trio/trio/_core/_run.py:2161: RuntimeWarning: Trio guest run got abandoned without properly finishing... weird stuff might happen
warnings.warn(I've tried to recreate the error without PyQt by just putting the scope cancellation further out but it results in no issues. I thought maybe PyQt was holding onto a reference to a no longer valid object but global cscope didn't avoid the SystemError. The same SystemError occurs back to the original commit in #1551, at least there and a few spot checks along the way.
I just bothered to follow the why-not-pyside2 link https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1313 and at least the StopIteration and SystemError are similar albeit against a different function call.
This isn't any sort of a blocker, just a thing where you have to be careful to disconnect a signal.
Thanks again for guest mode. Someday I'll do something more than a trivial demo with it. :]
Full example source
import trio
import sys
from outcome import Error
import traceback
# Can't use PySide2 currently because of
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1313
from PyQt5 import QtCore, QtWidgets
async def mine():
global cscope
widget = QtWidgets.QWidget()
with trio.CancelScope() as cscope:
app.lastWindowClosed.connect(cscope.cancel)
widget.show()
return 1
app = QtWidgets.QApplication(sys.argv)
# This is substantially faster than using a signal... for some reason Qt
# signal dispatch is really slow (and relies on events underneath anyway, so
# this is strictly less work)
REENTER_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
class ReenterEvent(QtCore.QEvent):
pass
class Reenter(QtCore.QObject):
def event(self, event):
event.fn()
return False
reenter = Reenter()
def run_sync_soon_threadsafe(fn):
event = ReenterEvent(REENTER_EVENT)
event.fn = fn
app.postEvent(reenter, event)
def done_callback(outcome):
print(f"Outcome: {outcome}")
if isinstance(outcome, Error):
exc = outcome.error
traceback.print_exception(type(exc), exc, exc.__traceback__)
app.quit()
trio.lowlevel.start_guest_run(
mine,
run_sync_soon_threadsafe=run_sync_soon_threadsafe,
done_callback=done_callback,
)
app.exec_()