diff --git a/deltachat-rpc-client/README.md b/deltachat-rpc-client/README.md index 4b7503fce..d8f99a4bf 100644 --- a/deltachat-rpc-client/README.md +++ b/deltachat-rpc-client/README.md @@ -48,3 +48,7 @@ $ python 'awesome' >>> rpc.close() ``` + +## Usage from async code + +See the [echobot_async.py](./examples/echobot_async.py) example. diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/rpc.py b/deltachat-rpc-client/src/deltachat_rpc_client/rpc.py index 4a181c528..5abc0be93 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/rpc.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/rpc.py @@ -1,3 +1,4 @@ +import asyncio import json import logging import os @@ -35,6 +36,10 @@ class Rpc: self.writer_thread: Thread self.events_thread: Thread + def get_async_rpc(self) -> "AsyncRpc": + """Get asynchronous wrapper to use the RPC methods from async code.""" + return AsyncRpc(self) + def start(self) -> None: if sys.version_info >= (3, 11): self.process = subprocess.Popen( @@ -84,6 +89,13 @@ class Rpc: def __exit__(self, _exc_type, _exc, _tb): self.close() + async def __aenter__(self): + self.__enter__() + return AsyncRpc(self) + + async def __aexit__(self, _exc_type, _exc, _tb): + self.__exit__(_exc_type, _exc, _tb) + def reader_loop(self) -> None: try: while True: @@ -165,3 +177,19 @@ class Rpc: return None return method + + +class AsyncRpc: + def __init__(self, sync_rpc: Rpc) -> None: + self._sync_rpc = sync_rpc + + def __getattr__(self, attr: str) -> Any: + sync_method = getattr(self._sync_rpc, attr) + if sync_method: + + async def method(*args) -> Any: + loop = asyncio.get_event_loop() + return await loop.run_in_executor(None, sync_method, *args) + + return method + return None