Skip to content

Commit

Permalink
strip down test tooling
Browse files Browse the repository at this point in the history
only provide the bare minimum
  • Loading branch information
rmorshea committed Jan 8, 2021
1 parent 9aa5183 commit 4cac83b
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 313 deletions.
14 changes: 13 additions & 1 deletion idom/server/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import abc
from asyncio import AbstractEventLoop, new_event_loop, set_event_loop, get_event_loop
from typing import TypeVar, Dict, Any, Tuple, Type, Optional, Generic, TypeVar
from threading import Thread
from threading import Thread, Event

from idom.core.element import ElementConstructor
from idom.core.layout import Layout, Layout
Expand Down Expand Up @@ -33,6 +33,7 @@ class AbstractRenderServer(Generic[_App, _Config]):
_loop: AbstractEventLoop
_dispatcher_type: Type[AbstractDispatcher]
_layout_type: Type[Layout] = Layout
_daemon_server_did_start: Event

def __init__(
self,
Expand Down Expand Up @@ -76,6 +77,9 @@ def run_in_thread() -> None:

thread = Thread(target=run_in_thread, daemon=True)
thread.start()

self._wait_until_daemon_server_start()

return thread

def register(self: _Self, app: Optional[_App]) -> _Self:
Expand Down Expand Up @@ -141,3 +145,11 @@ def _make_layout(
params: Dict[str, Any],
) -> Layout:
return self._layout_type(self._make_root_element(**params))

def _wait_until_daemon_server_start(self):
try:
self._daemon_server_did_start.wait(timeout=5)
except AttributeError: # pragma: no cover
raise NotImplementedError(
f"Server implementation {self} did not define a server started thread event"
)
63 changes: 36 additions & 27 deletions idom/server/prefab.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,31 @@ def run(
server_type: Optional[Type[_S]] = _find_default_server_type(),
host: str = "127.0.0.1",
port: Optional[int] = None,
server_options: Optional[Any] = None,
run_options: Optional[Dict[str, Any]] = None,
daemon: bool = False,
server_config: Optional[Any] = None,
run_kwargs: Optional[Dict[str, Any]] = None,
app: Optional[Any] = None,
daemon: bool = False,
) -> _S:
"""A utility for quickly running a render server with minimal boilerplate
Parameters:
element: The root of the view.
server_type: What server to run. Defaults to a builtin implementation if available.
host: The host string.
port: The port number. Defaults to a dynamically discovered available port.
server_options: Options passed to configure the server.
run_options: Options passed to the server to run it.
daemon: Whether the server should be run in a daemon thread.
app: Register the server to an existing application and run that.
element:
The root of the view.
server_type:
What server to run. Defaults to a builtin implementation if available.
host:
The host string.
port:
The port number. Defaults to a dynamically discovered available port.
server_config:
Options passed to configure the server.
run_kwargs:
Keyword arguments passed to the :meth:`~AbstractRenderServer.daemon`
or :meth:`~AbstractRenderServer.run` method of the server
app:
Register the server to an existing application and run that.
daemon:
Whether the server should be run in a daemon thread.
Returns:
The server instance. This isn't really useful unless the server is spawned
Expand All @@ -55,13 +64,13 @@ def run(
if port is None: # pragma: no cover
port = find_available_port(host)

server = server_type(element, server_options)
server = server_type(element, server_config)

if app is not None:
server.register(app)

run_server = server.run if not daemon else server.daemon
run_server(host, port, **(run_options or {}))
run_server(host, port, **(run_kwargs or {}))

return server

Expand All @@ -70,8 +79,8 @@ def multiview_server(
server_type: Type[_S],
host: str = "127.0.0.1",
port: Optional[int] = None,
server_options: Optional[Any] = None,
run_options: Optional[Dict[str, Any]] = None,
server_config: Optional[Any] = None,
run_kwargs: Optional[Dict[str, Any]] = None,
app: Optional[Any] = None,
) -> Tuple[MultiViewMount, _S]:
"""Set up a server where views can be dynamically added.
Expand All @@ -84,8 +93,8 @@ def multiview_server(
server: The server type to start up as a daemon
host: The server hostname
port: The server port number
server_options: Value passed to :meth:`AbstractRenderServer.configure`
run_options: Keyword args passed to :meth:`AbstractRenderServer.daemon`
server_config: Value passed to :meth:`AbstractRenderServer.configure`
run_kwargs: Keyword args passed to :meth:`AbstractRenderServer.daemon`
app: Optionally provide a prexisting application to register to
Returns:
Expand All @@ -99,8 +108,8 @@ def multiview_server(
server_type,
host,
port,
server_options=server_options,
run_options=run_options,
server_config=server_config,
run_kwargs=run_kwargs,
daemon=True,
app=app,
)
Expand All @@ -112,10 +121,10 @@ def hotswap_server(
server_type: Type[_S],
host: str = "127.0.0.1",
port: Optional[int] = None,
server_options: Optional[Any] = None,
run_options: Optional[Dict[str, Any]] = None,
sync_views: bool = True,
server_config: Optional[Any] = None,
run_kwargs: Optional[Dict[str, Any]] = None,
app: Optional[Any] = None,
sync_views: bool = False,
) -> Tuple[MountFunc, _S]:
"""Set up a server where views can be dynamically swapped out.
Expand All @@ -127,10 +136,10 @@ def hotswap_server(
server: The server type to start up as a daemon
host: The server hostname
port: The server port number
server_options: Value passed to :meth:`AbstractRenderServer.configure`
run_options: Keyword args passed to :meth:`AbstractRenderServer.daemon`
sync_views: Whether to update all displays with newly mounted elements
server_config: Value passed to :meth:`AbstractRenderServer.configure`
run_kwargs: Keyword args passed to :meth:`AbstractRenderServer.daemon`
app: Optionally provide a prexisting application to register to
sync_views: Whether to update all displays with newly mounted elements
Returns:
The server instance and a function for swapping views.
Expand All @@ -143,8 +152,8 @@ def hotswap_server(
server_type,
host,
port,
server_options=server_options,
run_options=run_options,
server_config=server_config,
run_kwargs=run_kwargs,
daemon=True,
app=app,
)
Expand Down
18 changes: 15 additions & 3 deletions idom/server/sanic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import json
import uuid
from threading import Event, Thread

from typing import Tuple, Any, Dict, Union, cast

Expand Down Expand Up @@ -31,6 +32,10 @@ class Config(TypedDict, total=False):
class SanicRenderServer(AbstractRenderServer[Sanic, Config]):
"""Base ``sanic`` extension."""

def daemon(self, *args: Any, **kwargs: Any) -> Thread:
self._daemon_server_did_start = Event()
return super().daemon(*args, **kwargs)

def _stop(self) -> None:
self.application.stop()

Expand Down Expand Up @@ -59,6 +64,11 @@ def _setup_application(self, app: Sanic, config: Config) -> None:
self._setup_blueprint_routes(bp, config)
app.blueprint(bp)

async def server_did_start(app: Sanic, loop: asyncio.AbstractEventLoop) -> None:
self._daemon_server_did_start.set()

app.register_listener(server_did_start, "after_server_start")

def _setup_blueprint_routes(self, blueprint: Blueprint, config: Config) -> None:
"""Add routes to the application blueprint"""

Expand All @@ -84,7 +94,9 @@ async def sock_recv() -> LayoutEvent:

@blueprint.route("/") # type: ignore
def redirect_to_index(request: request.Request) -> response.HTTPResponse:
return response.redirect(f"{blueprint.url_prefix}/client/index.html")
return response.redirect(
f"{blueprint.url_prefix}/client/index.html?{request.query_string}"
)

def _run_application(
self, app: Sanic, config: Config, args: Tuple[Any, ...], kwargs: Dict[str, Any]
Expand Down Expand Up @@ -129,8 +141,8 @@ class SharedClientStateServer(SanicRenderServer):
_dispatcher: SharedViewDispatcher

def _setup_application(self, app: Sanic, config: Config) -> None:
app.listener("before_server_start")(self._activate_dispatcher)
app.listener("before_server_stop")(self._deactivate_dispatcher)
app.register_listener(self._activate_dispatcher, "before_server_start")
app.register_listener(self._deactivate_dispatcher, "before_server_stop")
super()._setup_application(app, config)

async def _activate_dispatcher(
Expand Down
Loading

0 comments on commit 4cac83b

Please sign in to comment.