-
Notifications
You must be signed in to change notification settings - Fork 1
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
Allow device plugins to offer asynchronous opening #682
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #682 +/- ##
==========================================
+ Coverage 84.97% 85.31% +0.34%
==========================================
Files 69 69
Lines 3461 3549 +88
==========================================
+ Hits 2941 3028 +87
- Misses 520 521 +1 ☔ View full report in Codecov by Sentry. |
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 haven't check the tests, but the actual code looks ok to me.
It is a bit difficult to follow who does what as there are a lot of classes knot together to handle the status of the devices, and the connection of the devices, etc. so I think that at some point you will need to write a thorough developers guide explaining all of these relationships and why they are the way they are.
I don't see where a new threads are created to open a device. Could you point me in the right place. Also, my only initial concern was updating the GUI in the main thread from messages sent from another thread, but I guess this is not a problem if you have tested it and it works.
cls, parameters: Mapping[str, str | tuple[str, Sequence]] = {} | ||
cls, | ||
parameters: Mapping[str, str | tuple[str, Sequence]] = {}, | ||
async_open: bool | 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.
What's the reason of being None
? Should be either async or not?
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.
If it's None
, then it just leaves the _device_async_open
property as whatever it was before, so if it was set by a parent class, it won't be overridden.
They still may need to set parameters etc.
…in in wrong module While we don't actually want users to do this, raising an error in this function in the case that a class is outside the plugins module just makes writing tests a pain. So let's replace the error with a warning.
Yeah, it's a bit of a tangle 😞. If I have time, I'll add a bit more documentation before merging this PR. Otherwise I'll do it later.
This part of the code doesn't actually create any threads. (I did consider an implementation where we left things the same as before, but just ran the That's a good point about updating the GUI from a different thread. It's not a problem for the devices I've been working on, because they will use |
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.
Code looks good, and the functionality sensibly implemented to me. Let's hope it works with the real devices!
Thanks for reviews 😄 |
Description
I think I've done enough tinkering with this now and should probably stop 😛.
Background
Currently, the process of opening devices (which can include making a USB connection, moving a motor, etc.) all takes place on the main thread. The advantage of this model is that it's simple to work with -- the frontend doesn't have to worry about any intermediate stage where a device is still initialising, but can't actually be used for anything. The disadvantage is that it means that either we have to "finish" the device opening process early (e.g. before we've received a response from a server) or block the main (GUI) thread until it completes, both of which have drawbacks (e.g. #668, #247, #415).
Implementation
The backend changes were not especially complicated. The frontend is informed that we've started connecting to a device with a new
device.before_opening
message. I've added another class parameter,async_open
, which device classes can use to indicate that they open asynchronously. It defaults toFalse
, so classes have to opt in to this new behaviour. (Currently I haven't implemented this for any actual devices, though I have tested it.) Device classes withasync_open==True
just need to explicitly callsignal_is_opened
when they've finished opening (in practice, this will be from another thread).Making the frontend work with these changes was a bit more fiddly. You should be able to disconnect from devices that are still connecting (though this might require some small changes to actual device code). I've added a new widget to show the connection status of individual devices to the device management dialog. Everything else should (hopefully) just work as before.
I'm afraid this PR is a little on the long side (sorry!) but a lot of the changes are to the tests, so I hope it's not too painful to review.
Closes #638.