-
Notifications
You must be signed in to change notification settings - Fork 74
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
Tidying up drivers #69
Comments
Thanks for opening a dedicated issue. As low hanging fruit and for the most self documenting value we should start with splitting up the hid module into an asyncio subpackage. Are you fine with this? I can help on this one if you like. |
Indeed. I don't want to mandate a particular API; I see the drivers as an "optional extra" to the library, rather than its core; I want the library to be useful in environments where these drivers aren't appropriate at all, for example running on MicroPython in an embedded controller. All the library code outside the drivers package needs to work whatever concurrency model the caller is using.
I feel strongly that the simple synchronous API should be a wrapper around the strictly more capable async one, and that driver authors shouldn't have to implement both. I have to assume some drivers will be making use of threads internally (to wait for communication from their devices using a blocking call, for example) and it needs to be documented how the callback from the driver is handled: what thread is the code running in, and how thread-safe does the caller's code have to be?
Yes. How should we refer to these? "asyncio" and "threaded"? I think it would be useful to write a threaded wrapper for asyncio-based drivers: run the asyncio event loop in a separate thread and pass commands to it. Writing an asyncio-based wrapper for threaded drivers should also be possible.
Possibly, although since this code is generally a very small part of the driver I'm not sure how much there is to be gained by doing so. I think it would make the package structure more complicated.
Yes, I need to split it up: I'm going to add a simple asyncio driver that talks to DaliServer and it wouldn't make sense for that to be in the
My main issue with it is I feel there are too many API layers. I don't see what's gained by splitting it up into so many base classes. It's encouraging driver authors to write the "sync" version of their driver first (eg. the Apart from rearranging the drivers code, there are other things I think we should do to make finding and using drivers easier in application code. I'll open a separate issue for that, because it's largely unrelated to how the driver code is organised. |
The idea behind the design was to have a similar concept like transport and protocol https://docs.python.org/3/library/asyncio-protocol.html, https://twistedmatrix.com/documents/19.10.0/api/twisted.internet.protocol.Protocol.html with a unified API for sending and receiving DALI frames. The several "transports" are represented by the Backend and Listener implementations while the "protocols" are implemented as sync and async DALIDriver objects.
Valid point. We should merge Backend/Listener and SyncDALIDriver/AsyncDALIDriver APIs. If a device is not able to listen to the bus an error should be raised.
I totally agree. As stated in another issue I'm thinking about a driver registry/factory. It may look like so class driver:
"""Driver registry and factory"""
registry = dict()
def __init__(self, name):
self.name = name
def __call__(self, driver):
self.registry[self.name] = driver
@classmethod
def list_drivers(cls):
for name, driver in cls.registry.items():
yield (name, cls.title)
@classmethod
def create(cls, name, **kw):
return cls[name](**kw)
@driver('my_driver')
class MyDriver(DALIDriver):
title = 'My Driver' We also should add some metadata to the driver implementation like a title and the driver capabilities, e.g. whether the driver supports listening to the bus. |
While discussing #74, the question arises whether read and write operations to the backend need a timeout per cycle or whether we might change read and write timeouts to be instance based. Is there a real world use case where a read or write operation needs a dedicated timeout? |
Hi folks, is there still appetite for some unifying work here? I'd be keen to contribute. As a new user I found the mix of different APIs in the examples very confusing, especially as the serial and hid drivers both seem to be async but their API differs? (eg. async vs. sync Is documenting the existing API still the most valuable place to start? Having written a couple of drivers now I feel like this would be a helpful jumping-off point for any changes. I think you have the seed of a neat driver-finding interface hiding in the serial driver code already; I quite like the URI approach you have taken there. pySerial uses URIs quite nicely - when my interface had a serial driver I could open |
Comments originally from @rnixx in #68:
Hi Stephen,
I don't think we should talk about a "winning" API. Actually we have 2 approaches. The "old style" implementation in
dali.driver.base
, with straight forward sync API and async implementation with callbacks. And the asyncio based implementation which uses the "modern" way of life. Both have their value and usecases. And finally there's the daliserver module which needs to be refactored to one kind of a driver or another, or both.What we have in the driver package is some kind of a mess. Here are some thoughts from my side:
This is what the hid module may be split up to:
I always felt you do not like the driver API I wrote very much. Maybe I'm wrong, either way I'm totally fine with this. I am not able to switch over to asyncio based main loop anytime soon, and I think other people also will or cannot use asyncio for one reason or another. Therefor we should just cleanup the package and document what's there and why.
The text was updated successfully, but these errors were encountered: