apprise: `notify` fails if used while an existing asyncio loop is running
📣 Notification Service(s) Impacted N/A
🐞 Describe the bug
notify
(incorrectly) assumes that if it has been called synchronously and a plugin is asynchronous that this means there is no asyncio loop running and attempts to create a new one.
An error occurs because it tries to run run_until_complete
but the loop is already running.
💡 Screenshots and Logs Sample code:
import apprise
import asyncio
url = "macosx://"
a = apprise.Apprise()
a.add(url)
def do_a_thing():
# Do some regular synchronous code
a.notify("Test")
async def main():
while True:
do_a_thing()
await asyncio.sleep(1)
asyncio.run(main())
Error Log:
python test.py
Traceback (most recent call last):
File "/Users/seb/git/unifi-protect-backup/unifi_protect_backup/test.py", line 21, in <module>
asyncio.run(main())
File "/Users/seb/.asdf/installs/python/3.9.1/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Users/seb/.asdf/installs/python/3.9.1/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/Users/seb/git/unifi-protect-backup/unifi_protect_backup/test.py", line 17, in main
do_a_thing()
File "/Users/seb/git/unifi-protect-backup/unifi_protect_backup/test.py", line 12, in do_a_thing
a.notify("Test")
File "/Users/seb/Library/Caches/pypoetry/virtualenvs/unifi-protect-backup-A6mUIT2g-py3.9/lib/python3.9/site-packages/apprise/Apprise.py", line 447, in notify
async_result = loop.run_until_complete(all_cor)
File "/Users/seb/.asdf/installs/python/3.9.1/lib/python3.9/asyncio/base_events.py", line 618, in run_until_complete
self._check_running()
File "/Users/seb/.asdf/installs/python/3.9.1/lib/python3.9/asyncio/base_events.py", line 578, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
sys:1: RuntimeWarning: coroutine 'Apprise._async_notify_all' was never awaited
sys:1: RuntimeWarning: coroutine 'NotifyBase.async_notify' was never awaited
💻 Your System Details:
- OS: MacOS
- Python Version: 3.9.1
🔮 Additional context The code also tries to change the debug settings of the loop which it shouldn’t do if there is a loop in place already as this may have undesired consequences on the rest of the application.
It is not always possible to use async_notify
if, like in the example, the notification needs to be called in a synchronous context. While the above example would be trivial to change to work, my target usecase is much more complicated and using async_notify
is simply not an option.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 17 (12 by maintainers)
The way
nest_asyncio
works is that it monkey patches asyncio, so all I needed to do was call it once somewhere once in the part of the code I do control. The rest of the code remained untouched and would fail previously.In my usecase I am hooking apprise into the logging framework of python so I cant control the way that framework calls into my custom logging handler. But I can call
nest_asyncio
at the start of my code.Having said all that, it’s definitely not a silver bullet, something about the combination ofnest_asyncio
andaiorun
(which I use to bootstrap my application) breaks and I can no longer quit the application. Not an issue for apprise per-se but good to know it has drawbacks.Edit: I just wasn’t calling it early enough it seems