Browse Source

#285 let generic event handler use handle_event

Falko Schindler 2 years ago
parent
commit
b825ee97da
3 changed files with 18 additions and 14 deletions
  1. 3 4
      nicegui/element.py
  2. 10 7
      nicegui/events.py
  3. 5 3
      nicegui/helpers.py

+ 3 - 4
nicegui/element.py

@@ -3,11 +3,12 @@ from __future__ import annotations
 import shlex
 from abc import ABC
 from copy import deepcopy
-from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Optional, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union
 
 from . import background_tasks, binding, globals
 from .elements.mixins.visibility import Visibility
 from .event_listener import EventListener
+from .events import handle_event
 from .slot import Slot
 
 if TYPE_CHECKING:
@@ -158,9 +159,7 @@ class Element(ABC, Visibility):
     def handle_event(self, msg: Dict) -> None:
         for listener in self._event_listeners:
             if listener.type == msg['type']:
-                result = listener.handler(msg)
-                if isinstance(result, Awaitable):
-                    background_tasks.create(result)
+                handle_event(listener.handler, msg, sender=self)
 
     def collect_descendant_ids(self) -> List[int]:
         '''includes own ID as first element'''

+ 10 - 7
nicegui/events.py

@@ -1,21 +1,21 @@
 import traceback
 from dataclasses import dataclass
 from inspect import signature
-from typing import TYPE_CHECKING, Any, BinaryIO, Callable, List, Optional
+from typing import TYPE_CHECKING, Any, BinaryIO, Callable, List, Optional, Union
 
 from . import background_tasks, globals
 from .async_updater import AsyncUpdater
-from .client import Client
 from .helpers import is_coroutine
 
 if TYPE_CHECKING:
+    from .client import Client
     from .element import Element
 
 
 @dataclass
 class EventArguments:
     sender: 'Element'
-    client: Client
+    client: 'Client'
 
 
 @dataclass
@@ -259,17 +259,20 @@ class KeyEventArguments(EventArguments):
     modifiers: KeyboardModifiers
 
 
-def handle_event(handler: Optional[Callable], arguments: EventArguments) -> None:
+def handle_event(handler: Optional[Callable],
+                 arguments: Union[EventArguments, dict], *,
+                 sender: Optional['Element'] = None) -> None:
     try:
         if handler is None:
             return
         no_arguments = not signature(handler).parameters
-        assert arguments.sender.parent_slot is not None
-        with arguments.sender.parent_slot:
+        sender = arguments.sender if isinstance(arguments, EventArguments) else sender
+        assert sender.parent_slot is not None
+        with sender.parent_slot:
             result = handler() if no_arguments else handler(arguments)
         if is_coroutine(handler):
             async def wait_for_result():
-                with arguments.sender.parent_slot:
+                with sender.parent_slot:
                     await AsyncUpdater(result)
             if globals.loop and globals.loop.is_running():
                 background_tasks.create(wait_for_result(), name=str(handler))

+ 5 - 3
nicegui/helpers.py

@@ -2,10 +2,12 @@ import asyncio
 import functools
 import inspect
 from contextlib import nullcontext
-from typing import Any, Awaitable, Callable, Optional, Union
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Optional, Union
 
 from . import background_tasks, globals
-from .client import Client
+
+if TYPE_CHECKING:
+    from .client import Client
 
 
 def is_coroutine(object: Any) -> bool:
@@ -14,7 +16,7 @@ def is_coroutine(object: Any) -> bool:
     return asyncio.iscoroutinefunction(object)
 
 
-def safe_invoke(func: Union[Callable, Awaitable], client: Optional[Client] = None) -> None:
+def safe_invoke(func: Union[Callable, Awaitable], client: Optional['Client'] = None) -> None:
     try:
         if isinstance(func, Awaitable):
             async def func_with_client():