Skip to content

Commit

Permalink
zauberzeug#338 add lazy element-to-dict conversion (but not _too_ lazy)
Browse files Browse the repository at this point in the history
  • Loading branch information
falkoschindler committed Feb 8, 2023
1 parent 060f79d commit 1c6ce75
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 26 deletions.
50 changes: 39 additions & 11 deletions nicegui/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __enter__(self):
def __exit__(self, *_):
self.default_slot.__exit__(*_)

def to_dict(self) -> Dict:
def _collect_event_dict(self) -> Dict[str, Dict]:
events: Dict[str, Dict] = {}
for listener in self._event_listeners:
words = listener.type.split('.')
Expand All @@ -71,16 +71,44 @@ def to_dict(self) -> Dict:
'args': list(set(events.get(listener.type, {}).get('args', []) + listener.args)),
'throttle': min(events.get(listener.type, {}).get('throttle', float('inf')), listener.throttle),
}
return {
'id': self.id,
'tag': self.tag,
'class': self._classes,
'style': self._style,
'props': self._props,
'events': events,
'text': self._text,
'slots': {name: [child.id for child in slot.children] for name, slot in self.slots.items()},
}
return events

def _collect_slot_dict(self) -> Dict[str, List[int]]:
return {name: [child.id for child in slot.children] for name, slot in self.slots.items()}

def to_dict(self, *keys: str) -> Dict:
if not keys:
return {
'id': self.id,
'tag': self.tag,
'class': self._classes,
'style': self._style,
'props': self._props,
'text': self._text,
'slots': self._collect_slot_dict(),
'events': self._collect_event_dict(),
}
dict_: Dict[str, Any] = {}
for key in keys:
if key == 'id':
dict_['id'] = self.id
elif key == 'tag':
dict_['tag'] = self.tag
elif key == 'class':
dict_['class'] = self._classes
elif key == 'style':
dict_['style'] = self._style
elif key == 'props':
dict_['props'] = self._props
elif key == 'text':
dict_['text'] = self._text
elif key == 'slots':
dict_['slots'] = self._collect_slot_dict()
elif key == 'events':
dict_['events'] = self._collect_event_dict()
else:
raise ValueError(f'Unknown key {key}')
return dict_

def classes(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None):
'''HTML classes to modify the look of the element.
Expand Down
42 changes: 30 additions & 12 deletions nicegui/outbox.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import asyncio
from collections import deque
from typing import TYPE_CHECKING, Any, Deque, Tuple
from typing import TYPE_CHECKING, Any, Deque, Dict, Set, Tuple

from . import globals

Expand All @@ -13,26 +13,44 @@
queue: Deque['MessageGroup'] = deque()


def enqueue_update(element: 'Element') -> None:
if queue:
client_id, message_type, argument = queue[-1]
if client_id == element.client.id and message_type == 'update':
elements: Deque[Element] = argument
elements.append(element)
return
queue.append((element.client.id, 'update', deque([element])))
def enqueue_update(element: 'Element', *attributes: str) -> None:
client_id, message_type, data = queue[-1] if queue else (None, None, None)
if client_id != element.client.id or message_type != 'update':
# add new message group
queue.append((element.client.id, 'update', {element.id: (element, set())}))
return
elements: Dict[int, Tuple[Element, Set]] = data
if element.id not in elements:
# add new element to message group
elements[element.id] = [element, set()]
return
if attributes:
# enqueue single attributes
elements[element.id][1].update(attributes)
else:
# enqueue all attributes
elements[element.id][1].clear()


def enqueue_message(message_type: 'MessageType', data: Any, client_id: 'ClientId') -> None:
_convert_elements_to_dicts()
queue.append((client_id, message_type, data))


async def loop() -> None:
while True:
while queue:
_convert_elements_to_dicts()
client_id, message_type, data = queue.popleft()
if message_type == 'update':
messages: Deque[Element] = data
data = {'elements': {e.id: e.to_dict() for e in messages}}
await globals.sio.emit(message_type, data, room=client_id)
await asyncio.sleep(0.01)


def _convert_elements_to_dicts() -> None:
_, message_type, data = queue[-1] if queue else (None, None, None)
if message_type == 'update':
elements: Dict[int, Tuple[Element, Set]] = data
for id, value in elements.items():
if len(value) == 2:
element, attributes = value
elements[id] = element.to_dict(*attributes)
4 changes: 1 addition & 3 deletions nicegui/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,7 @@
window.socket.on("disconnect", () => {
document.getElementById('popup').style.opacity = 1;
});
window.socket.on("update", (msg) => {
Object.entries(msg.elements).forEach(([id, element]) => this.elements[element.id] = element);
});
window.socket.on("update", (msg) => Object.entries(msg).forEach(([id, el]) => this.elements[el.id] = el));
window.socket.on("run_method", (msg) => getElement(msg.id)?.[msg.name](...msg.args));
window.socket.on("run_javascript", (msg) => runJavascript(msg['code'], msg['request_id']));
window.socket.on("open", (msg) => (location.href = msg));
Expand Down

0 comments on commit 1c6ce75

Please sign in to comment.