Responsible for "rendering" components. That is, turning them into VDOM.
| 52 | |
| 53 | |
| 54 | class Layout: |
| 55 | """Responsible for "rendering" components. That is, turning them into VDOM.""" |
| 56 | |
| 57 | __slots__: tuple[str, ...] = ( |
| 58 | "root", |
| 59 | "_event_handlers", |
| 60 | "_rendering_queue", |
| 61 | "_render_tasks", |
| 62 | "_render_tasks_ready", |
| 63 | "_root_life_cycle_state_id", |
| 64 | "_model_states_by_life_cycle_state_id", |
| 65 | ) |
| 66 | |
| 67 | if not hasattr(abc.ABC, "__weakref__"): # nocov |
| 68 | __slots__ += ("__weakref__",) |
| 69 | |
| 70 | def __init__(self, root: ComponentType) -> None: |
| 71 | super().__init__() |
| 72 | if not isinstance(root, ComponentType): |
| 73 | msg = f"Expected a ComponentType, not {type(root)!r}." |
| 74 | raise TypeError(msg) |
| 75 | self.root = root |
| 76 | |
| 77 | async def __aenter__(self) -> Layout: |
| 78 | # create attributes here to avoid access before entering context manager |
| 79 | self._event_handlers: EventHandlerDict = {} |
| 80 | self._render_tasks: set[Task[LayoutUpdateMessage]] = set() |
| 81 | self._render_tasks_ready: Semaphore = Semaphore(0) |
| 82 | |
| 83 | self._rendering_queue: _ThreadSafeQueue[_LifeCycleStateId] = _ThreadSafeQueue() |
| 84 | root_model_state = _new_root_model_state(self.root, self._schedule_render_task) |
| 85 | |
| 86 | self._root_life_cycle_state_id = root_id = root_model_state.life_cycle_state.id |
| 87 | self._model_states_by_life_cycle_state_id = {root_id: root_model_state} |
| 88 | self._schedule_render_task(root_id) |
| 89 | |
| 90 | return self |
| 91 | |
| 92 | async def __aexit__(self, *exc: object) -> None: |
| 93 | root_csid = self._root_life_cycle_state_id |
| 94 | root_model_state = self._model_states_by_life_cycle_state_id[root_csid] |
| 95 | |
| 96 | for t in self._render_tasks: |
| 97 | t.cancel() |
| 98 | try: |
| 99 | await t |
| 100 | except CancelledError: |
| 101 | pass |
| 102 | |
| 103 | await self._unmount_model_states([root_model_state]) |
| 104 | |
| 105 | # delete attributes here to avoid access after exiting context manager |
| 106 | del self._event_handlers |
| 107 | del self._rendering_queue |
| 108 | del self._root_life_cycle_state_id |
| 109 | del self._model_states_by_life_cycle_state_id |
| 110 | |
| 111 | async def deliver(self, event: LayoutEventMessage) -> None: |
no outgoing calls