diff --git a/src/dls_utilpack/client_context_base.py b/src/dls_utilpack/client_context_base.py new file mode 100644 index 0000000..3149b62 --- /dev/null +++ b/src/dls_utilpack/client_context_base.py @@ -0,0 +1,47 @@ +import logging + +logger = logging.getLogger(__name__) + + +class ClientContextBase: + """ + Base class for client contexts. + Provides some basic commmon housekeeping. + """ + + # ---------------------------------------------------------------------------------------- + def __init__(self, specification): + self.__specification = specification + self.__interface = None + + # ---------------------------------------------------------------------------------------- + def get_specification(self): + return self.__specification + + def set_specification(self, specification): + self.__specification = specification + + specification = property(get_specification, set_specification) + + # ---------------------------------------------------------------------------------------- + def get_interface(self): + return self.__interface + + def set_interface(self, interface): + self.__interface = interface + + interface = property(get_interface, set_interface) + + # ---------------------------------------------------------------------------------------- + async def __aenter__(self): + """ """ + + await self.aenter() + + return self.interface + + # ---------------------------------------------------------------------------------------- + async def __aexit__(self, type, value, traceback): + """ """ + + await self.aexit() diff --git a/src/dls_utilpack/server_context_base.py b/src/dls_utilpack/server_context_base.py new file mode 100644 index 0000000..dfa561f --- /dev/null +++ b/src/dls_utilpack/server_context_base.py @@ -0,0 +1,84 @@ +import logging + +# Utilities. +from dls_utilpack.callsign import callsign + +# Base class for a Thing which has a name and traits. +from dls_utilpack.thing import Thing + +logger = logging.getLogger(__name__) + + +class ServerContextBase(Thing): + """ + Base class for an "async with" context which can be wrapped around a server object. + + Contains convenience methods common to all server contexts. + + The server object reference is supplied to this object externally. + + The server object must provide the follwing methods: + - is_process_started() + - is_process_alive() + + """ + + # ---------------------------------------------------------------------------------------- + def __init__( + self, + thing_type, + specification=None, + predefined_uuid=None, + ): + Thing.__init__( + self, + thing_type, + specification, + predefined_uuid=predefined_uuid, + ) + + # Reference to object which is a server, such as BaseAiohttp. + self.server = None + + # The context specification of the server's specification. + self.context_specification = self.specification().get("context", {}) + + # ---------------------------------------------------------------------------------------- + async def is_process_started(self): + """""" + + if self.server is None: + raise RuntimeError(f"{callsign(self)} a process has not been defined") + + try: + return await self.server.is_process_started() + except Exception: + raise RuntimeError( + f"unable to determing process started for server {callsign(self.server)}" + ) + + # ---------------------------------------------------------------------------------------- + async def is_process_alive(self): + """""" + + if self.server is None: + raise RuntimeError(f"{callsign(self)} a process has not been defined") + + try: + return await self.server.is_process_alive() + except Exception: + raise RuntimeError( + f"unable to determing dead or alive for server {callsign(self.server)}" + ) + + # ---------------------------------------------------------------------------------------- + async def __aenter__(self): + """ """ + + await self.aenter() + + # ---------------------------------------------------------------------------------------- + async def __aexit__(self, type, value, traceback): + """ """ + + await self.aexit(type, value, traceback) diff --git a/src/dls_utilpack/thing.py b/src/dls_utilpack/thing.py index 357d473..911fec8 100644 --- a/src/dls_utilpack/thing.py +++ b/src/dls_utilpack/thing.py @@ -17,7 +17,12 @@ class Thing: def __init__(self, thing_type: str, specification, predefined_uuid=None): self.__thing_type = thing_type - self.__specification = specification + + if specification is None: + self.__specification = {} + else: + self.__specification = specification + self.__uuid = predefined_uuid if self.__uuid is None: self.__uuid = str(uuid.uuid4()) diff --git a/tests/test_server_context.py b/tests/test_server_context.py new file mode 100644 index 0000000..3d26cf9 --- /dev/null +++ b/tests/test_server_context.py @@ -0,0 +1,70 @@ +import logging + +from dls_utilpack.server_context_base import ServerContextBase + +# Base class for the tester. +from tests.base_tester import BaseTester + +logger = logging.getLogger(__name__) + + +class Server: + # Minimal methods required for a "server" to provide. + async def is_process_alive(self): + return True + + async def is_process_started(self): + return True + + +class Context(ServerContextBase): + # For testing. + def __init__(self, thing_type, specification=None, predefined_uuid=None): + ServerContextBase.__init__( + self, + thing_type, + specification=specification, + predefined_uuid=predefined_uuid, + ) + + self.was_entered = 0 + self.was_exited = 0 + + # Minimal methods required for a "context" to provide. + async def aenter(self): + """ """ + self.was_entered += 1 + + async def aexit(self, type, value, traceback): + """ """ + self.was_exited += 1 + + +# ---------------------------------------------------------------------------------------- +class TestServerContext(BaseTester): + def test(self, constants, logging_setup, output_directory): + """ """ + + self.main(constants, output_directory) + + # ---------------------------------------------------------------------------------------- + async def _main_coroutine( + self, + constants, + output_directory, + ): + """ """ + + # Make the context. + context = Context("some::thing") + + # Assign the server. + context.server = Server() + + # Run the context. + async with context: + assert await context.is_process_started() + assert await context.is_process_alive() + + assert context.was_entered == 1 + assert context.was_exited == 1