-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: add Client.apply method, adjust TaskStatus to properly capture exceptions #53
Conversation
…uarantee TaskStatus objects are returned
for pv, data in zip(pv_list, data_list): | ||
logger.debug(f'Putting {pv} = {data}') | ||
status: TaskStatus = self.cl.put(pv, data) | ||
if status.exception(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is status
guaranteed to be complete after self.cl.put
returns it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does currently, since we asyncio.run
and block until the coroutine is finished. I'm not entirely convinced this is the best way to do things, but returning the status immediately would require us either
- be in an async context
- run the event loop in a separate thread (ophyd style).
I've been ok with this for now since we have the ability to run parallel puts (and wait on all of them), but it has been something I've been pondering changing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is totally ok, I wanted to make sure you hadn't skip a wait
call here (since wait
was added in this PR).
It's not so strange to require more nuanced asynchronous behavior to be done in an async context.
return | ||
|
||
if isinstance(entry, Setpoint): | ||
return [self.cl.put(entry.pv_name, entry.data)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the extra wrapping of list/not list here, I have to wonder if it would have been simpler for put
to always return a list of statuses, even if we only put one PV
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had this thought too. In the end I decided that if I, as a user of the Client
, put to a single PV and had to index into a single-element list, I'd be annoyed.
But maybe the users and I can just deal with it 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way is probably ok, your explanation here makes sense to me
@@ -57,6 +59,27 @@ def success(self) -> bool: | |||
and self.task.exception() is None | |||
) | |||
|
|||
def wait(self, timeout=None) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small documentation thing: you've added this wait
function here and not documented its inclusion in the release notes or in the PR text. It's also not used anywhere outside the test suite yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I'd need it, then I realized the full ramifications of the statuses I'd created 😆
Co-authored-by: Devan Agrawal <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with this!
Alright, merging and moving along |
Description
TaskStatus
to actually capture exceptions, instead of propagating themMotivation and Context
closes #7
Assorted thoughts
TaskStatus
was built to hold exceptions raised in the coroutines they wrap, but were propagating them to the calling context. This was caused by our used ofasyncio.gather
, which needed thereturn_exceptions=True
kwarg.asyncio
has various ways of handling and propagating exceptions, we just needed to choose the right one for us.How Has This Been Tested?
Basic unit test added
Where Has This Been Documented?
This PR, docstrings etc
Pre-merge checklist
docs/pre-release-notes.sh
and created a pre-release documentation page