Exceptions from coroutines do not become Tango exceptions
Dear pytango developers,
first of all thank you for all your efforts. I stumbled across the following unexpected behavior while developing a device server: when an exception is raised in an coroutine, the exception does not become a Tango exception and can't be catched by the client. Consider this minimal working example:
import asyncio
import tango
import tango.test_context
from tango.server import Device, command
class CoroServer(Device):
green_mode = tango.GreenMode.Asyncio
@command
def sync_bad_command(self):
tango.Except.throw_exception("Sync Failure", "", "")
@command
async def async_bad_command(self):
task = asyncio.create_task(self.coro_target())
async def coro_target(self):
tango.Except.throw_exception("Async Failure", "", "")
if __name__ == "__main__":
with tango.test_context.DeviceTestContext(CoroServer, process=True) as proxy:
try:
proxy.sync_bad_command()
except Exception as e:
print(e)
try:
proxy.async_bad_command()
except Exception as e:
print(e)
While the exception thrown by sync_bad_command()
is catched and printed, the exception thrown by async_bad_command()
is not catched in the dummy client test code but rather generates the following error message in the console:
Task exception was never retrieved
future: <Task finished name='Task-8' coro=<CoroServer.coro_target() done, defined at C:\Users\tvips\PycharmProjects\py_simpleemmenu\exc_test.py:19> exception=DevFailed(args = (DevError(desc = '', origin = '', reason = 'Async Failure', severity = tango._tango.ErrSeverity.ERR),))>
Traceback (most recent call last):
File "C:\Users\tvips\PycharmProjects\py_simpleemmenu\exc_test.py", line 20, in coro_target
tango.Except.throw_exception("Async Failure", "", "")
PyTango.DevFailed: DevFailed[
DevError[
desc =
origin =
reason = Async Failure
severity = ERR]
]
The exact same behavior is observed when the tango.Except.throw_exception
calls are replaced by raise Exception(...)
.
This issue applies to my following usecase: I am developing a device server for a detector where the acqusition time can easily exceed the timeouts specified in the Tango guidelines. The pytango documentation recommends off-loading the long work to a coroutine which is executed asynchronously in the event loop. However, the acqusition can fail, but this would not imply that the device is in a FAULT state, as it would still by fully operational. The Tango guidelines recommend that in these cases one should throw an exception rather than having the device make a transition into the FAULT state. With this open issue it is thus not possible to notify a client that a coroutine command has failed using an exception.
Thank you!