浏览代码

automatically await async results in ui.timer (#2859)

Falko Schindler 1 年之前
父节点
当前提交
429d67a7e6
共有 2 个文件被更改,包括 28 次插入17 次删除
  1. 4 3
      nicegui/elements/timer.py
  2. 24 14
      tests/test_timer.py

+ 4 - 3
nicegui/elements/timer.py

@@ -1,9 +1,10 @@
 import asyncio
 import time
 from contextlib import nullcontext
-from typing import Any, Callable, Optional
+from typing import Any, Callable, Optional, Awaitable
 
-from .. import background_tasks, core, helpers
+from .. import background_tasks, core
+from ..awaitable_response import AwaitableResponse
 from ..binding import BindableProperty
 from ..client import Client
 from ..element import Element
@@ -91,7 +92,7 @@ class Timer(Element, component='timer.js'):
         try:
             assert self.callback is not None
             result = self.callback()
-            if helpers.is_coroutine_function(self.callback):
+            if isinstance(result, Awaitable) and not isinstance(result, AwaitableResponse):
                 await result
         except Exception as e:
             core.app.handle_exception(e)

+ 24 - 14
tests/test_timer.py

@@ -77,20 +77,6 @@ def test_setting_visibility(screen: Screen, once: bool):
     screen.should_not_contain('Some Label')
 
 
-def test_awaiting_coroutine(screen: Screen):
-    user = {'name': 'John Doe'}
-
-    async def update_user():
-        await asyncio.sleep(0.1)
-        user['name'] = 'Jane Doe'
-
-    ui.timer(1, update_user)
-
-    screen.open('/')
-    screen.wait(1)
-    assert user['name'] == 'Jane Doe'
-
-
 def test_timer_on_deleted_container(screen: Screen):
     state = {'count': 0}
     with ui.row() as outer_container:
@@ -105,3 +91,27 @@ def test_timer_on_deleted_container(screen: Screen):
     count = state['count']
     screen.wait(0.5)
     assert state['count'] == count, 'timer is not running anymore after deleting the container'
+
+
+def test_different_callbacks(screen: Screen):
+    def sync_function():
+        ui.label('a synchronous function')
+
+    async def async_function():
+        await asyncio.sleep(0.1)
+        ui.label('an asynchronous function')
+
+    async def async_lambda(msg: str):
+        await asyncio.sleep(0.1)
+        ui.label(f'an asynchronous lambda: {msg}')
+
+    ui.timer(0.1, sync_function, once=True)
+    ui.timer(0.1, async_function, once=True)
+    ui.timer(0.1, lambda: ui.label('a synchronous lambda'), once=True)
+    ui.timer(0.1, lambda: async_lambda('Hi!'), once=True)
+
+    screen.open('/')
+    screen.should_contain('a synchronous function')
+    screen.should_contain('an asynchronous function')
+    screen.should_contain('a synchronous lambda')
+    screen.should_contain('an asynchronous lambda: Hi!')