Skip to content

Commit 40d3a90

Browse files
committed
no need for raw coro to set/unset current hook
since element updates are processed sequentially and not in parallel we don't need the dynamic setting/unsetting or the current hook. in the future we may need to return to that approach, but for now sequential updates are simpler, more performant when processing individual updates (since no logic between each yield), and maybe more aligned with how React works.
1 parent 33c37b5 commit 40d3a90

File tree

4 files changed

+23
-41
lines changed

4 files changed

+23
-41
lines changed

idom/core/layout.py

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import abc
22
import asyncio
3-
from types import coroutine
43
from typing import (
54
List,
65
Dict,
@@ -125,8 +124,11 @@ async def _create_layout_update(self, element: AbstractElement) -> LayoutUpdate:
125124

126125
async def _render_element(self, element_state: ElementState) -> Dict[str, Any]:
127126
try:
128-
# BUG: https://github.com/python/mypy/issues/9256
129-
raw_model = await _render_with_life_cycle_hook(element_state) # type: ignore
127+
element_state.life_cycle_hook.set_current()
128+
try:
129+
raw_model = await element_state.element_obj.render()
130+
finally:
131+
element_state.life_cycle_hook.unset_current()
130132

131133
if isinstance(raw_model, AbstractElement):
132134
raw_model = {"tagName": "div", "children": [raw_model]}
@@ -209,10 +211,6 @@ def _create_element_state(
209211
life_cycle_hook=LifeCycleHook(element, self.update),
210212
)
211213

212-
def _reset_element_state(self, element_state: ElementState) -> None:
213-
self._clear_element_state_event_handlers(element_state)
214-
self._delete_element_state_children(element_state)
215-
216214
def _delete_element_state(self, element_state: ElementState) -> None:
217215
self._clear_element_state_event_handlers(element_state)
218216
self._delete_element_state_children(element_state)
@@ -252,26 +250,6 @@ def __repr__(self) -> str:
252250
return f"{type(self).__name__}({self.root})"
253251

254252

255-
@coroutine
256-
def _render_with_life_cycle_hook(element_state: ElementState) -> Iterator[None]:
257-
"""Render an element which may use hooks.
258-
259-
We use a coroutine here because we need to know when control is yielded
260-
back to the event loop since it might switch to render a different element.
261-
"""
262-
gen = element_state.element_obj.render().__await__()
263-
try:
264-
while True:
265-
element_state.life_cycle_hook.set_current()
266-
value = next(gen)
267-
element_state.life_cycle_hook.unset_current()
268-
yield value
269-
except StopIteration as error:
270-
return error.value
271-
finally:
272-
element_state.life_cycle_hook.unset_current()
273-
274-
275253
class _ElementQueue:
276254

277255
__slots__ = "_queue", "_pending"

tests/test_core/test_hooks.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from idom.core.element import element
21
import re
32

43
import pytest

tests/test_core/test_layout.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import gc
3+
import re
34
from weakref import finalize
45

56
import pytest
@@ -26,6 +27,21 @@ def test_layout_expects_abstract_element():
2627
idom.Layout(idom.html.div())
2728

2829

30+
def test_not_open_layout_update_logs_error(caplog):
31+
@idom.element
32+
async def Element():
33+
...
34+
35+
element = Element()
36+
layout = idom.Layout(element)
37+
layout.update(element)
38+
39+
assert re.match(
40+
"Did not update .*? - resources of .*? are closed",
41+
next(iter(caplog.records)).msg,
42+
)
43+
44+
2945
async def test_simple_layout():
3046
set_state_hook = idom.Ref(None)
3147

tests/test_core/test_render.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@
99
from idom.core.render import SharedStateRenderer, AbstractRenderer
1010

1111

12-
import asyncio
13-
from asyncio.exceptions import CancelledError
14-
15-
import pytest
16-
from anyio.exceptions import ExceptionGroup
17-
18-
import idom
19-
from idom.core.layout import Layout, LayoutEvent
20-
from idom.core.render import SharedStateRenderer, AbstractRenderer
21-
22-
2312
async def test_shared_state_renderer():
2413
done = asyncio.Event()
2514
changes_1 = []
@@ -37,14 +26,14 @@ async def recv_1():
3726
return events_to_inject.pop(0)
3827
except IndexError:
3928
done.set()
40-
raise CancelledError()
29+
raise asyncio.CancelledError()
4130

4231
async def send_2(patch):
4332
changes_2.append(patch.changes)
4433

4534
async def recv_2():
4635
await done.wait()
47-
raise CancelledError()
36+
raise asyncio.CancelledError()
4837

4938
@idom.element
5039
async def Clickable():

0 commit comments

Comments
 (0)