Skip to content

Commit 6136693

Browse files
committed
rename Renderer to Dispatcher
1 parent ee68f65 commit 6136693

File tree

8 files changed

+72
-76
lines changed

8 files changed

+72
-76
lines changed

docs/source/api.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Layout
2929
:members:
3030

3131

32-
Renderer
32+
Dispatcher
3333
--------
3434

3535
.. automodule:: idom.core.render

docs/source/core-concepts.rst

+17-17
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ ever be removed from the model. Then you'll just need to call and await a
7171
patch = await layout.render()
7272

7373
The layout also handles the triggering of event handlers. Normally this is done
74-
automatically by a :ref:`Renderer <Layout Renderer>`, but for now we'll do it manually.
74+
automatically by a :ref:`Dispatcher <Layout Dispatcher>`, but for now we'll do it manually.
7575
We can use a trick to hard-code the ``event_handler_id`` so we can pass it, and a fake
7676
event, to the layout's :meth:`~idom.core.layout.Layout.dispatch` method. Then we just
7777
have to re-render the layout and see what changed:
@@ -112,22 +112,22 @@ have to re-render the layout and see what changed:
112112
assert count_did_increment
113113

114114

115-
Layout Renderer
116-
---------------
115+
Layout Dispatcher
116+
-----------------
117117

118-
An :class:`~idom.core.render.AbstractRenderer` implementation is a relatively thin layer
118+
An :class:`~idom.core.dispatcher.AbstractDispatcher` implementation is a relatively thin layer
119119
of logic around a :class:`~idom.core.layout.Layout` which drives the triggering of
120120
events and layout updates by scheduling an asynchronous loop that will run forever -
121-
effectively animating the model. To execute the loop, the renderer's
122-
:meth:`~idom.core.render.AbstractRenderer.run` method accepts two callbacks. One is a
123-
"send" callback to which the renderer passes updates, while the other is "receive"
124-
callback that's called by the renderer to events it should execute.
121+
effectively animating the model. To execute the loop, the dispatcher's
122+
:meth:`~idom.core.dispatcher.AbstractDispatcher.run` method accepts two callbacks. One is a
123+
"send" callback to which the dispatcher passes updates, while the other is "receive"
124+
callback that's called by the dispatcher to events it should execute.
125125

126126
.. testcode::
127127

128128
import asyncio
129129

130-
from idom.core import SingleStateRenderer, EventHandler
130+
from idom.core import SingleStateDispatcher, EventHandler
131131
from idom.core.layout import LayoutEvent
132132

133133

@@ -137,7 +137,7 @@ callback that's called by the renderer to events it should execute.
137137
async def send(patch):
138138
sent_patches.append(patch)
139139
if len(sent_patches) == 5:
140-
# if we didn't cancel the renderer would continue forever
140+
# if we didn't cancel the dispatcher would continue forever
141141
raise asyncio.CancelledError()
142142

143143

@@ -152,26 +152,26 @@ callback that's called by the renderer to events it should execute.
152152
return event
153153

154154

155-
async with SingleStateRenderer(idom.Layout(ClickCount())) as renderer:
155+
async with SingleStateDispatcher(idom.Layout(ClickCount())) as dispatcher:
156156
context = None # see note below
157-
await renderer.run(send, recv, context)
157+
await dispatcher.run(send, recv, context)
158158

159159
assert len(sent_patches) == 5
160160

161161

162162
.. note::
163163

164164
``context`` is information that's specific to the
165-
:class:`~idom.core.render.AbstractRenderer` implementation. In the case of
166-
the :class:`~idom.core.render.SingleStateRenderer` it doesn't require any
167-
context. On the other hand the :class:`~idom.core.render.SharedStateRenderer`
165+
:class:`~idom.core.dispatcher.AbstractDispatcher` implementation. In the case of
166+
the :class:`~idom.core.render.SingleStateDispatcher` it doesn't require any
167+
context. On the other hand the :class:`~idom.core.render.SharedStateDispatcher`
168168
requires a client ID as its piece of contextual information.
169169

170170

171171
Layout Server
172172
-------------
173173

174-
The :ref:`Renderer <Layout Renderer>` allows you to animate the layout, but we still
174+
The :ref:`Dispatcher <Layout Dispatcher>` allows you to animate the layout, but we still
175175
need to get the models on the screen. One of the last steps in that journey is to send
176176
them over the wire. To do that you need an
177177
:class:`~idom.server.base.AbstractRenderServer` implementation. Right now we have a
@@ -188,7 +188,7 @@ starting to add support for asyncio like
188188
an `issue <https://github.com/rmorshea/idom/issues>`__.
189189

190190
In the case of our :class:`~idom.server.sanic.SanicRenderServer` types we have one
191-
implementation per built in :ref:`Renderer <Layout Renderer>`:
191+
implementation per built in :ref:`Dispatcher <Layout Dispatcher>`:
192192

193193
- :class:`idom.server.sanic.PerClientStateServer`
194194

idom/core/__init__.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from .element import element, Element, AbstractElement, ElementConstructor
22
from .events import event, Events, EventHandler
33
from .layout import Layout, Layout
4-
from .render import AbstractRenderer, SharedStateRenderer, SingleStateRenderer
4+
from .dispatcher import AbstractDispatcher, SharedStateDispatcher, SingleStateDispatcher
55
from .vdom import vdom
66

77
__all__ = [
88
"AbstractElement",
99
"Layout",
10-
"AbstractRenderer",
10+
"AbstractDispatcher",
1111
"element",
1212
"Element",
1313
"EventHandler",
@@ -17,6 +17,6 @@
1717
"hooks",
1818
"Layout",
1919
"vdom",
20-
"SharedStateRenderer",
21-
"SingleStateRenderer",
20+
"SharedStateDispatcher",
21+
"SingleStateDispatcher",
2222
]

idom/core/render.py renamed to idom/core/dispatcher.py

+8-12
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,8 @@
1919
RecvCoroutine = Callable[[], Awaitable[LayoutEvent]]
2020

2121

22-
class StopRendering(Exception):
23-
"""Raised to gracefully stop :meth:`AbstractRenderer.run`"""
24-
25-
26-
class AbstractRenderer(HasAsyncResources, abc.ABC):
27-
"""A base class for implementing :class:`~idom.core.layout.Layout` renderers."""
22+
class AbstractDispatcher(HasAsyncResources, abc.ABC):
23+
"""A base class for implementing :class:`~idom.core.layout.Layout` dispatchers."""
2824

2925
__slots__ = "_layout"
3026

@@ -73,11 +69,11 @@ async def _incoming(self, layout: Layout, context: Any, message: Any) -> None:
7369
...
7470

7571

76-
class SingleStateRenderer(AbstractRenderer):
77-
"""Each client of the renderer will get its own model.
72+
class SingleStateDispatcher(AbstractDispatcher):
73+
"""Each client of the dispatcher will get its own model.
7874
7975
..note::
80-
The ``context`` parameter of :meth:`SingleStateRenderer.run` should just
76+
The ``context`` parameter of :meth:`SingleStateDispatcher.run` should just
8177
be ``None`` since it's not used.
8278
"""
8379

@@ -95,11 +91,11 @@ async def _incoming(self, layout: Layout, context: Any, event: LayoutEvent) -> N
9591
return None
9692

9793

98-
class SharedStateRenderer(SingleStateRenderer):
99-
"""Each client of the renderer shares the same model.
94+
class SharedStateDispatcher(SingleStateDispatcher):
95+
"""Each client of the dispatcher shares the same model.
10096
10197
The client's ID is indicated by the ``context`` argument of
102-
:meth:`SharedStateRenderer.run`
98+
:meth:`SharedStateDispatcher.run`
10399
"""
104100

105101
__slots__ = "_update_queues", "_model_state"

idom/server/base.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
from idom.core.element import ElementConstructor, AbstractElement
77
from idom.core.layout import Layout, Layout
8-
from idom.core.render import (
9-
AbstractRenderer,
8+
from idom.core.dispatcher import (
9+
AbstractDispatcher,
1010
SendCoroutine,
1111
RecvCoroutine,
1212
)
@@ -31,7 +31,7 @@ class AbstractRenderServer(Generic[_App, _Config]):
3131
"""
3232

3333
_loop: AbstractEventLoop
34-
_renderer_type: Type[AbstractRenderer]
34+
_dispatcher_type: Type[AbstractDispatcher]
3535
_layout_type: Type[Layout] = Layout
3636

3737
def __init__(
@@ -113,7 +113,7 @@ def _run_application(
113113
raise NotImplementedError()
114114

115115
@abc.abstractmethod
116-
async def _run_renderer(
116+
async def _run_dispatcher(
117117
self,
118118
send: SendCoroutine,
119119
recv: RecvCoroutine,
@@ -131,12 +131,12 @@ def _update_config(self, old: _Config, new: _Config) -> _Config: # pragma: no c
131131
"""
132132
raise NotImplementedError()
133133

134-
def _make_renderer(
134+
def _make_dispatcher(
135135
self,
136136
parameters: Dict[str, Any],
137137
loop: Optional[AbstractEventLoop] = None,
138-
) -> AbstractRenderer:
139-
return self._renderer_type(self._make_layout(parameters, loop))
138+
) -> AbstractDispatcher:
139+
return self._dispatcher_type(self._make_layout(parameters, loop))
140140

141141
def _make_layout(
142142
self,

idom/server/sanic.py

+20-20
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from mypy_extensions import TypedDict
1010
from websockets import WebSocketCommonProtocol
1111

12-
from idom.core.render import (
13-
SingleStateRenderer,
14-
SharedStateRenderer,
12+
from idom.core.dispatcher import (
13+
SingleStateDispatcher,
14+
SharedStateDispatcher,
1515
SendCoroutine,
1616
RecvCoroutine,
1717
)
@@ -55,7 +55,7 @@ def _setup_application(self, app: Sanic, config: Config) -> None:
5555
cors_params = cors_config if isinstance(cors_config, dict) else {}
5656
CORS(app, **cors_params)
5757

58-
bp = Blueprint(f"idom_renderer_{id(self)}", url_prefix=config["url_prefix"])
58+
bp = Blueprint(f"idom_dispatcher_{id(self)}", url_prefix=config["url_prefix"])
5959
self._setup_blueprint_routes(bp, config)
6060
app.blueprint(bp)
6161

@@ -75,7 +75,7 @@ async def sock_recv() -> LayoutEvent:
7575
return LayoutEvent(event["target"], event["data"])
7676

7777
param_dict = {k: request.args.get(k) for k in request.args}
78-
await self._run_renderer(sock_send, sock_recv, param_dict)
78+
await self._run_dispatcher(sock_send, sock_recv, param_dict)
7979

8080
def handler_name(function: Any) -> str:
8181
return f"{blueprint.name}.{function.__name__}"
@@ -135,43 +135,43 @@ def _run_application(
135135
class PerClientStateServer(SanicRenderServer):
136136
"""Each client view will have its own state."""
137137

138-
_renderer_type = SingleStateRenderer
138+
_dispatcher_type = SingleStateDispatcher
139139

140-
async def _run_renderer(
140+
async def _run_dispatcher(
141141
self,
142142
send: SendCoroutine,
143143
recv: RecvCoroutine,
144144
parameters: Dict[str, Any],
145145
loop: Optional[asyncio.AbstractEventLoop] = None,
146146
) -> None:
147-
async with self._make_renderer(parameters, loop) as renderer:
148-
await renderer.run(send, recv, None)
147+
async with self._make_dispatcher(parameters, loop) as dispatcher:
148+
await dispatcher.run(send, recv, None)
149149

150150

151151
class SharedClientStateServer(SanicRenderServer):
152152
"""All connected client views will have shared state."""
153153

154-
_renderer_type = SharedStateRenderer
155-
_renderer: SharedStateRenderer
154+
_dispatcher_type = SharedStateDispatcher
155+
_dispatcher: SharedStateDispatcher
156156

157157
def _setup_application(self, app: Sanic, config: Config) -> None:
158-
app.listener("before_server_start")(self._activate_renderer)
159-
app.listener("before_server_stop")(self._deactivate_renderer)
158+
app.listener("before_server_start")(self._activate_dispatcher)
159+
app.listener("before_server_stop")(self._deactivate_dispatcher)
160160
super()._setup_application(app, config)
161161

162-
async def _activate_renderer(
162+
async def _activate_dispatcher(
163163
self, app: Sanic, loop: asyncio.AbstractEventLoop
164164
) -> None:
165-
self._renderer = cast(SharedStateRenderer, self._make_renderer({}, loop))
166-
await self._renderer.__aenter__()
165+
self._dispatcher = cast(SharedStateDispatcher, self._make_dispatcher({}, loop))
166+
await self._dispatcher.__aenter__()
167167

168-
async def _deactivate_renderer(
168+
async def _deactivate_dispatcher(
169169
self, app: Sanic, loop: asyncio.AbstractEventLoop
170170
) -> None: # pragma: no cover
171171
# this doesn't seem to get triffered during testing for some reason
172-
await self._renderer.__aexit__(None, None, None)
172+
await self._dispatcher.__aexit__(None, None, None)
173173

174-
async def _run_renderer(
174+
async def _run_dispatcher(
175175
self,
176176
send: SendCoroutine,
177177
recv: RecvCoroutine,
@@ -181,4 +181,4 @@ async def _run_renderer(
181181
if parameters:
182182
msg = f"SharedClientState server does not support per-client view parameters {parameters}"
183183
raise ValueError(msg)
184-
await self._renderer.run(send, recv, uuid.uuid4().hex, join=True)
184+
await self._dispatcher.run(send, recv, uuid.uuid4().hex, join=True)

tests/conftest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,10 @@ def fixturized_server_type(server_type):
220220
class ServerSavesLastError(server_type):
221221
"""A per-client-state server that updates the ``last_server_error`` fixture"""
222222

223-
async def _run_renderer(self, *args, **kwargs):
223+
async def _run_dispatcher(self, *args, **kwargs):
224224
self._config["last_server_error"].current = None
225225
try:
226-
await super()._run_renderer(*args, **kwargs)
226+
await super()._run_dispatcher(*args, **kwargs)
227227
except Exception as e:
228228
self._config["last_server_error"].current = e
229229

tests/test_core/test_render.py renamed to tests/test_core/test_dispatcher.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
import idom
88
from idom.core.layout import Layout, LayoutEvent
9-
from idom.core.render import SharedStateRenderer, AbstractRenderer
9+
from idom.core.dispatcher import SharedStateDispatcher, AbstractDispatcher
1010

1111

12-
async def test_shared_state_renderer():
12+
async def test_shared_state_dispatcher():
1313
done = asyncio.Event()
1414
changes_1 = []
1515
changes_2 = []
@@ -45,9 +45,9 @@ async def an_event():
4545

4646
return idom.html.div({"anEvent": an_event, "count": count})
4747

48-
async with SharedStateRenderer(Layout(Clickable())) as renderer:
49-
await renderer.run(send_1, recv_1, "1")
50-
await renderer.run(send_2, recv_2, "2")
48+
async with SharedStateDispatcher(Layout(Clickable())) as dispatcher:
49+
await dispatcher.run(send_1, recv_1, "1")
50+
await dispatcher.run(send_2, recv_2, "2")
5151

5252
expected_changes = [
5353
[
@@ -76,8 +76,8 @@ async def an_event():
7676
assert changes_1 == changes_2
7777

7878

79-
async def test_renderer_run_does_not_supress_non_cancel_errors():
80-
class RendererWithBug(AbstractRenderer):
79+
async def test_dispatcher_run_does_not_supress_non_cancel_errors():
80+
class DispatcherWithBug(AbstractDispatcher):
8181
async def _outgoing(self, layout, context):
8282
raise ValueError("this is a bug")
8383

@@ -95,12 +95,12 @@ async def recv():
9595
return {}
9696

9797
with pytest.raises(ExceptionGroup, match="this is a bug"):
98-
async with RendererWithBug(idom.Layout(AnyElement())) as renderer:
99-
await renderer.run(send, recv, None)
98+
async with DispatcherWithBug(idom.Layout(AnyElement())) as dispatcher:
99+
await dispatcher.run(send, recv, None)
100100

101101

102-
async def test_renderer_run_does_not_supress_non_stop_rendering_errors():
103-
class RendererWithBug(AbstractRenderer):
102+
async def test_dispatcher_run_does_not_supress_non_stop_rendering_errors():
103+
class DispatcherWithBug(AbstractDispatcher):
104104
async def _outgoing(self, layout, context):
105105
raise ValueError("this is a bug")
106106

@@ -118,5 +118,5 @@ async def recv():
118118
return {}
119119

120120
with pytest.raises(ExceptionGroup, match="this is a bug"):
121-
async with RendererWithBug(idom.Layout(AnyElement())) as renderer:
122-
await renderer.run(send, recv, None)
121+
async with DispatcherWithBug(idom.Layout(AnyElement())) as dispatcher:
122+
await dispatcher.run(send, recv, None)

0 commit comments

Comments
 (0)