hardbyte / hardbyte/python-can

Async Listener

Offen
#1,626 2 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen
enhancement
Vorherrschende Sprache
Python
Sterne
1.6k
Forks
697
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### Issue description

Currently, `Listener` objects are asyncio-ready but are not truely async.

Let me first clarify that `AsyncBufferedReader` is not a truely-async listener, it is a sync listener (sync `on_message_received` and `on_error` methods) that exposes an async buffer through the `get_message` method. It is pretty useful for a lot of cases but this is not the target of this feature request. A truely-async listener would allow for async `on_message_received` and `on_error` definitions.

Disclaimer: I haven't inspected the whole code so I'm not sure if there is anything of the underlying architecture that makes this kind of truely-async listeners an issue.

And what do I mean by "asyncio-ready" in the first sentence? `Notifier._on_message_available` is called when a new message can be received. `Notifier.listeners` can either be `Listener` instances or direct callbacks. Either way they are called, and if they return a coroutine (and the notifier was passed a loop), it will scheduler the corresponding task:

https://github.com/hardbyte/python-can/blob/dc0ae68acb28f01a503e084718cfa2acf39d1e16/can/notifier.py#L134-L143

Async callbacks can be provided to make use of this feature, but `Listener.__call__` never returns a coroutine:

https://github.com/hardbyte/python-can/blob/dc0ae68acb28f01a503e084718cfa2acf39d1e16/can/listener.py#L42-L43

### Solutions

Returning the result of `self.on_message_received` instead of implicitly returning `None` would work for both versions:

```py
def __call__(self, msg: Message):
return self.on_message_received(msg)
```

In the sync version, `self.on_message_receive(msg)` returns `None`, while the async version will return the coroutine, which is exactly the desired behavior. Regaring type-hinting of the result, `Optional[asyncio.coroutine]` works up to Python 3.9, not sure what should be the 3.10 one as `asyncio.coroutine` is no longer a thing.

I see two ways of providing a truely-async Listener:
1. Creating a new `AsyncListener` with the above version of `__call__`, and async signatures for `on_message_received` and `on_error`.
2. Updating the `Listener` class with the above version of `__call__`.

### Alternatives

Meanwhile, the user can always modify the `__call__` method of the subclass of `Listener` to the one provided above and it will work. I still think this should be provided to the user and not expected from him to discover that he needs to change that magic method of the subclass.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.