Skip to content

Commit 1294694

Browse files
authored
Log exception in scan and command methods (#162)
1 parent c3f8d50 commit 1294694

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

src/fastcs/backend.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ async def _start_scan_tasks(
5656
):
5757
self._scan_tasks = {self._loop.create_task(coro()) for coro in coros}
5858

59+
for task in self._scan_tasks:
60+
task.add_done_callback(self._scan_done)
61+
62+
def _scan_done(self, task: asyncio.Task):
63+
try:
64+
task.result()
65+
except Exception as e:
66+
raise FastCSException(
67+
"Exception raised in scan method of "
68+
f"{self._controller.__class__.__name__}"
69+
) from e
70+
5971
def _stop_scan_tasks(self):
6072
for task in self._scan_tasks:
6173
if not task.done():

tests/test_backend.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastcs.controller import Controller
77
from fastcs.cs_methods import Command
88
from fastcs.datatypes import Int
9+
from fastcs.exceptions import FastCSException
910
from fastcs.wrappers import command, scan
1011

1112

@@ -127,3 +128,40 @@ async def test_wrapper():
127128

128129
assert len(backend._scan_tasks) == 1
129130
assert len(backend._initial_coros) == 2
131+
132+
133+
def test_scan_raises_exception_via_callback():
134+
class MyTestController(Controller):
135+
def __init__(self):
136+
super().__init__()
137+
138+
@scan(0.1)
139+
async def raise_exception(self):
140+
raise ValueError("Scan Exception")
141+
142+
controller = MyTestController()
143+
loop = asyncio.get_event_loop()
144+
backend = Backend(controller, loop)
145+
146+
exception_info = {}
147+
# This will intercept the exception raised in _scan_done
148+
loop.set_exception_handler(
149+
lambda _loop, context: exception_info.update(
150+
{"exception": context.get("exception")}
151+
)
152+
)
153+
154+
async def test_scan_wrapper():
155+
await backend.serve()
156+
# This allows scan time to run
157+
await asyncio.sleep(0.2)
158+
# _scan_done should raise an exception
159+
assert isinstance(exception_info["exception"], FastCSException)
160+
for task in backend._scan_tasks:
161+
internal_exception = task.exception()
162+
assert internal_exception
163+
# The task exception comes from scan method raise_exception
164+
assert isinstance(internal_exception, ValueError)
165+
assert "Scan Exception" == str(internal_exception)
166+
167+
loop.run_until_complete(test_scan_wrapper())

0 commit comments

Comments
 (0)