|
@@ -1,6 +1,7 @@
|
|
from __future__ import annotations
|
|
from __future__ import annotations
|
|
|
|
|
|
import asyncio
|
|
import asyncio
|
|
|
|
+import inspect
|
|
import time
|
|
import time
|
|
import uuid
|
|
import uuid
|
|
from contextlib import contextmanager
|
|
from contextlib import contextmanager
|
|
@@ -13,12 +14,11 @@ from fastapi.templating import Jinja2Templates
|
|
|
|
|
|
from nicegui import json
|
|
from nicegui import json
|
|
|
|
|
|
-from . import background_tasks, binding, core, outbox
|
|
|
|
|
|
+from . import background_tasks, binding, core, helpers, outbox
|
|
from .awaitable_response import AwaitableResponse
|
|
from .awaitable_response import AwaitableResponse
|
|
from .dependencies import generate_resources
|
|
from .dependencies import generate_resources
|
|
from .element import Element
|
|
from .element import Element
|
|
from .favicon import get_favicon_url
|
|
from .favicon import get_favicon_url
|
|
-from .helpers import safe_invoke
|
|
|
|
from .logging import log
|
|
from .logging import log
|
|
from .version import __version__
|
|
from .version import __version__
|
|
|
|
|
|
@@ -201,9 +201,9 @@ class Client:
|
|
self._disconnect_task.cancel()
|
|
self._disconnect_task.cancel()
|
|
self._disconnect_task = None
|
|
self._disconnect_task = None
|
|
for t in self.connect_handlers:
|
|
for t in self.connect_handlers:
|
|
- safe_invoke(t, self)
|
|
|
|
|
|
+ self.safe_invoke(t)
|
|
for t in core.app._connect_handlers: # pylint: disable=protected-access
|
|
for t in core.app._connect_handlers: # pylint: disable=protected-access
|
|
- safe_invoke(t, self)
|
|
|
|
|
|
+ self.safe_invoke(t)
|
|
|
|
|
|
def handle_disconnect(self) -> None:
|
|
def handle_disconnect(self) -> None:
|
|
"""Wait for the browser to reconnect; invoke disconnect handlers if it doesn't."""
|
|
"""Wait for the browser to reconnect; invoke disconnect handlers if it doesn't."""
|
|
@@ -213,12 +213,12 @@ class Client:
|
|
else:
|
|
else:
|
|
delay = core.app.config.reconnect_timeout # pylint: disable=protected-access
|
|
delay = core.app.config.reconnect_timeout # pylint: disable=protected-access
|
|
await asyncio.sleep(delay)
|
|
await asyncio.sleep(delay)
|
|
- if not self.shared:
|
|
|
|
- self.delete()
|
|
|
|
for t in self.disconnect_handlers:
|
|
for t in self.disconnect_handlers:
|
|
- safe_invoke(t, self)
|
|
|
|
|
|
+ self.safe_invoke(t)
|
|
for t in core.app._disconnect_handlers: # pylint: disable=protected-access
|
|
for t in core.app._disconnect_handlers: # pylint: disable=protected-access
|
|
- safe_invoke(t, self)
|
|
|
|
|
|
+ self.safe_invoke(t)
|
|
|
|
+ if not self.shared:
|
|
|
|
+ self.delete()
|
|
self._disconnect_task = background_tasks.create(handle_disconnect())
|
|
self._disconnect_task = background_tasks.create(handle_disconnect())
|
|
|
|
|
|
def handle_event(self, msg: Dict) -> None:
|
|
def handle_event(self, msg: Dict) -> None:
|
|
@@ -235,6 +235,25 @@ class Client:
|
|
"""Store the result of a JavaScript command."""
|
|
"""Store the result of a JavaScript command."""
|
|
self.waiting_javascript_commands[msg['request_id']] = msg['result']
|
|
self.waiting_javascript_commands[msg['request_id']] = msg['result']
|
|
|
|
|
|
|
|
+ def safe_invoke(self, func: Union[Callable[..., Any], Awaitable]) -> None:
|
|
|
|
+ """Invoke the potentially async function in the client context and catch any exceptions."""
|
|
|
|
+ try:
|
|
|
|
+ if isinstance(func, Awaitable):
|
|
|
|
+ async def func_with_client():
|
|
|
|
+ with self:
|
|
|
|
+ await func
|
|
|
|
+ background_tasks.create(func_with_client())
|
|
|
|
+ else:
|
|
|
|
+ with self:
|
|
|
|
+ result = func(self) if len(inspect.signature(func).parameters) == 1 else func()
|
|
|
|
+ if helpers.is_coroutine_function(func):
|
|
|
|
+ async def result_with_client():
|
|
|
|
+ with self:
|
|
|
|
+ await result
|
|
|
|
+ background_tasks.create(result_with_client())
|
|
|
|
+ except Exception as e:
|
|
|
|
+ core.app.handle_exception(e)
|
|
|
|
+
|
|
def remove_elements(self, elements: Iterable[Element]) -> None:
|
|
def remove_elements(self, elements: Iterable[Element]) -> None:
|
|
"""Remove the given elements from the client."""
|
|
"""Remove the given elements from the client."""
|
|
binding.remove(elements, Element)
|
|
binding.remove(elements, Element)
|