From ad0fd8e833d1a04636a9c0149eed9f3ea41ce986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 4 Apr 2024 16:19:29 +0200 Subject: [PATCH] updates proxy class usage - ProxyClass class is inheriting from DeviceConnection and is only used for topmost proxy - classes of nested proxy objects are dynamically created to keep their component types - adds _initialise method to ProxyClassMixin as I cannot pass sio_client and loop to each component_class (initialising a class with multiple base classes will pass the arguments passed to the constructor to each initialiser function) --- src/pydase/client/client.py | 12 +++++++- src/pydase/client/proxy_loader.py | 51 ++++++++++++++++--------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/pydase/client/client.py b/src/pydase/client/client.py index ed26f61..0132b8e 100644 --- a/src/pydase/client/client.py +++ b/src/pydase/client/client.py @@ -5,7 +5,8 @@ from typing import TypedDict, cast import socketio # type: ignore -from pydase.client.proxy_loader import ProxyClass, ProxyLoader +import pydase.components +from pydase.client.proxy_loader import ProxyClassMixin, ProxyLoader from pydase.utils.serialization.deserializer import loads from pydase.utils.serialization.types import SerializedDataService, SerializedObject @@ -26,6 +27,15 @@ def asyncio_loop_thread(loop: asyncio.AbstractEventLoop) -> None: loop.run_forever() +class ProxyClass(ProxyClassMixin, pydase.components.DeviceConnection): + def __init__( + self, sio_client: socketio.AsyncClient, loop: asyncio.AbstractEventLoop + ) -> None: + ProxyClassMixin.__init__(self) + pydase.components.DeviceConnection.__init__(self) + self._initialise(sio_client=sio_client, loop=loop) + + class Client: def __init__(self, hostname: str = "localhost", port: int = 8001): self._hostname = hostname diff --git a/src/pydase/client/proxy_loader.py b/src/pydase/client/proxy_loader.py index a6a99a4..eca3fb1 100644 --- a/src/pydase/client/proxy_loader.py +++ b/src/pydase/client/proxy_loader.py @@ -5,9 +5,7 @@ from typing import TYPE_CHECKING, Any, cast import socketio # type: ignore -import pydase.components -import pydase.data_service -from pydase.utils.serialization.deserializer import loads +from pydase.utils.serialization.deserializer import Deserializer, loads from pydase.utils.serialization.serializer import dump from pydase.utils.serialization.types import SerializedObject @@ -56,14 +54,18 @@ class ProxyList(list[Any]): class ProxyClassMixin: - def __init__( + def __init__(self) -> None: + self._proxy_getters: dict[str, Callable[..., Any]] = {} + self._proxy_setters: dict[str, Callable[..., Any]] = {} + self._proxy_methods: dict[str, Callable[..., Any]] = {} + # declare before DataService init to avoid warning messaged + self._observers: dict[str, Any] = {} + + def _initialise( self, sio_client: socketio.AsyncClient, loop: asyncio.AbstractEventLoop, ) -> None: - self._proxy_getters: dict[str, Callable[..., Any]] = {} - self._proxy_setters: dict[str, Callable[..., Any]] = {} - self._proxy_methods: dict[str, Callable[..., Any]] = {} self._loop = loop self._sio = sio_client @@ -189,19 +191,6 @@ class ProxyClassMixin: self._proxy_getters[attr_name] = getter_proxy -class ProxyClass(pydase.data_service.DataService, ProxyClassMixin): - def __init__( - self, - sio_client: socketio.AsyncClient, - loop: asyncio.AbstractEventLoop, - ) -> None: - # declare before ProxyClassMixin init to avoid warning messaged - self._observers = {} - - ProxyClassMixin.__init__(self, sio_client=sio_client, loop=loop) - pydase.DataService.__init__(self) - - class ProxyLoader: @staticmethod def load_list_proxy( @@ -267,11 +256,25 @@ class ProxyLoader: sio_client: socketio.AsyncClient, loop: asyncio.AbstractEventLoop, ) -> Any: - proxy_class = ProxyClass(sio_client=sio_client, loop=loop) - ProxyLoader.update_data_service_proxy( - proxy_class=proxy_class, serialized_object=serialized_object + # Custom types like Components or DataService classes + component_class = cast( + type, Deserializer.get_component_class(serialized_object["type"]) ) - return proxy_class + class_bases = ( + ProxyClassMixin, + component_class, + ) + proxy_base_class: type[ProxyClassMixin] = type( + serialized_object["name"], # type: ignore + class_bases, + {}, + ) + proxy_class_instance = proxy_base_class() + proxy_class_instance._initialise(sio_client=sio_client, loop=loop) + ProxyLoader.update_data_service_proxy( + proxy_class=proxy_class_instance, serialized_object=serialized_object + ) + return proxy_class_instance @staticmethod def load_default(