You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The aiohttp_fetch.py example file makes use of the @asyncSlot() decorator to allow passing the on_btnFetch_clicked async function to the .connect method of a button.
Under the covers, @asyncSlot() is just creating a Task object using asyncio.ensure_future(). In the documentation for that function, it says "Save a reference to the result of this function, to avoid a task disappearing mid-execution.". It seems that the example code does not do this, so may be liable for garbage-collection issues if the now reference-less task is cleaned up unexpectedly.
Is there a preferred pattern to use for these decorators? Or can the decorator be modified to keep a reference to the Task that is created?
The text was updated successfully, but these errors were encountered:
I've run into this issue, which results asyncSlot callbacks being cancelled unexpectedly. My solution is to patch the asyncSlot function to use the workaround suggested by the create_task docs:
importasyncioimportfunctoolsimportinspectimportsysfromPyQt5.QtCoreimportpyqtSlotbackground_tasks=set()
defasyncSlot(*args, **kwargs):
"""Make a Qt async slot run on asyncio loop. Patched version of qasync.asyncSlot that keeps references to tasks, so that they don't get garbage collected. """def_error_handler(task):
try:
task.result()
exceptException:
sys.excepthook(*sys.exc_info())
finally:
background_tasks.discard(task)
defouter_decorator(fn):
@pyqtSlot(*args, **kwargs)@functools.wraps(fn)defwrapper(*args, **kwargs):
# Qt ignores trailing args from a signal but python does# not so inspect the slot signature and if it's not# callable try removing args until it is.task=Nonewhilelen(args):
try:
inspect.signature(fn).bind(*args, **kwargs)
exceptTypeError:
iflen(args):
# Only convert args to a list if we need to pop()args=list(args)
args.pop()
continueelse:
task=asyncio.ensure_future(fn(*args, **kwargs))
task.add_done_callback(_error_handler)
background_tasks.add(task)
breakiftaskisNone:
raiseTypeError("asyncSlot was not callable from Signal. Potential signature mismatch.")
returntaskreturnwrapperreturnouter_decorator
If this is an acceptable way of fixing this bug, I'd be happy to open a PR.
The aiohttp_fetch.py example file makes use of the
@asyncSlot()
decorator to allow passing theon_btnFetch_clicked
async function to the.connect
method of a button.Under the covers,
@asyncSlot()
is just creating aTask
object usingasyncio.ensure_future()
. In the documentation for that function, it says "Save a reference to the result of this function, to avoid a task disappearing mid-execution.". It seems that the example code does not do this, so may be liable for garbage-collection issues if the now reference-less task is cleaned up unexpectedly.Is there a preferred pattern to use for these decorators? Or can the decorator be modified to keep a reference to the Task that is created?
The text was updated successfully, but these errors were encountered: