Skip to content

Commit b3d0e4c

Browse files
author
David Erb
committed
adds server and client context
1 parent 5d30d5b commit b3d0e4c

File tree

4 files changed

+207
-1
lines changed

4 files changed

+207
-1
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import logging
2+
3+
logger = logging.getLogger(__name__)
4+
5+
6+
class ClientContextBase:
7+
"""
8+
Base class for client contexts.
9+
Provides some basic commmon housekeeping.
10+
"""
11+
12+
# ----------------------------------------------------------------------------------------
13+
def __init__(self, specification):
14+
self.__specification = specification
15+
self.__interface = None
16+
17+
# ----------------------------------------------------------------------------------------
18+
def get_specification(self):
19+
return self.__specification
20+
21+
def set_specification(self, specification):
22+
self.__specification = specification
23+
24+
specification = property(get_specification, set_specification)
25+
26+
# ----------------------------------------------------------------------------------------
27+
def get_interface(self):
28+
return self.__interface
29+
30+
def set_interface(self, interface):
31+
self.__interface = interface
32+
33+
interface = property(get_interface, set_interface)
34+
35+
# ----------------------------------------------------------------------------------------
36+
async def __aenter__(self):
37+
""" """
38+
39+
await self.aenter()
40+
41+
return self.interface
42+
43+
# ----------------------------------------------------------------------------------------
44+
async def __aexit__(self, type, value, traceback):
45+
""" """
46+
47+
await self.aexit()
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import logging
2+
3+
# Utilities.
4+
from dls_utilpack.callsign import callsign
5+
6+
# Base class for a Thing which has a name and traits.
7+
from dls_utilpack.thing import Thing
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class ServerContextBase(Thing):
13+
"""
14+
Base class for an "async with" context which can be wrapped around a server object.
15+
16+
Contains convenience methods common to all server contexts.
17+
18+
The server object reference is supplied to this object externally.
19+
20+
The server object must provide the follwing methods:
21+
- is_process_started()
22+
- is_process_alive()
23+
24+
"""
25+
26+
# ----------------------------------------------------------------------------------------
27+
def __init__(
28+
self,
29+
thing_type,
30+
specification=None,
31+
predefined_uuid=None,
32+
):
33+
Thing.__init__(
34+
self,
35+
thing_type,
36+
specification,
37+
predefined_uuid=predefined_uuid,
38+
)
39+
40+
# Reference to object which is a server, such as BaseAiohttp.
41+
self.server = None
42+
43+
# The context specification of the server's specification.
44+
self.context_specification = self.specification().get("context", {})
45+
46+
# ----------------------------------------------------------------------------------------
47+
async def is_process_started(self):
48+
""""""
49+
50+
if self.server is None:
51+
raise RuntimeError(f"{callsign(self)} a process has not been defined")
52+
53+
try:
54+
return await self.server.is_process_started()
55+
except Exception:
56+
raise RuntimeError(
57+
f"unable to determing process started for server {callsign(self.server)}"
58+
)
59+
60+
# ----------------------------------------------------------------------------------------
61+
async def is_process_alive(self):
62+
""""""
63+
64+
if self.server is None:
65+
raise RuntimeError(f"{callsign(self)} a process has not been defined")
66+
67+
try:
68+
return await self.server.is_process_alive()
69+
except Exception:
70+
raise RuntimeError(
71+
f"unable to determing dead or alive for server {callsign(self.server)}"
72+
)
73+
74+
# ----------------------------------------------------------------------------------------
75+
async def __aenter__(self):
76+
""" """
77+
78+
await self.aenter()
79+
80+
# ----------------------------------------------------------------------------------------
81+
async def __aexit__(self, type, value, traceback):
82+
""" """
83+
84+
await self.aexit(type, value, traceback)

src/dls_utilpack/thing.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ class Thing:
1717

1818
def __init__(self, thing_type: str, specification, predefined_uuid=None):
1919
self.__thing_type = thing_type
20-
self.__specification = specification
20+
21+
if specification is None:
22+
self.__specification = {}
23+
else:
24+
self.__specification = specification
25+
2126
self.__uuid = predefined_uuid
2227
if self.__uuid is None:
2328
self.__uuid = str(uuid.uuid4())

tests/test_server_context.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import logging
2+
3+
from dls_utilpack.server_context_base import ServerContextBase
4+
5+
# Base class for the tester.
6+
from tests.base_tester import BaseTester
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class Server:
12+
# Minimal methods required for a "server" to provide.
13+
async def is_process_alive(self):
14+
return True
15+
16+
async def is_process_started(self):
17+
return True
18+
19+
20+
class Context(ServerContextBase):
21+
# For testing.
22+
def __init__(self, thing_type, specification=None, predefined_uuid=None):
23+
ServerContextBase.__init__(
24+
self,
25+
thing_type,
26+
specification=specification,
27+
predefined_uuid=predefined_uuid,
28+
)
29+
30+
self.was_entered = 0
31+
self.was_exited = 0
32+
33+
# Minimal methods required for a "context" to provide.
34+
async def aenter(self):
35+
""" """
36+
self.was_entered += 1
37+
38+
async def aexit(self, type, value, traceback):
39+
""" """
40+
self.was_exited += 1
41+
42+
43+
# ----------------------------------------------------------------------------------------
44+
class TestServerContext(BaseTester):
45+
def test(self, constants, logging_setup, output_directory):
46+
""" """
47+
48+
self.main(constants, output_directory)
49+
50+
# ----------------------------------------------------------------------------------------
51+
async def _main_coroutine(
52+
self,
53+
constants,
54+
output_directory,
55+
):
56+
""" """
57+
58+
# Make the context.
59+
context = Context("some::thing")
60+
61+
# Assign the server.
62+
context.server = Server()
63+
64+
# Run the context.
65+
async with context:
66+
assert await context.is_process_started()
67+
assert await context.is_process_alive()
68+
69+
assert context.was_entered == 1
70+
assert context.was_exited == 1

0 commit comments

Comments
 (0)