66
77import asyncio
88import inspect
9+ import time
910from typing import Callable , Optional
1011
1112from basemkit .persistent_log import Log
13+ from ngwidgets .progress import Progressbar
1214from nicegui import background_tasks
15+ from nicegui import run
1316
1417# optional generic Progressbar tqdm or nicegui.ui
15- from ngwidgets .progress import Progressbar
16-
17-
1818class TaskRunner :
1919 """
2020 A robust background task runner that supports:
@@ -29,12 +29,50 @@ def __init__(self, timeout: float = 20.0, progress: Optional[Progressbar] = None
2929 self .timeout = timeout
3030 self .progress = progress
3131 self .log = Log ()
32+ self .start_time = None
33+ self .stop_time = None
34+ self .task_name = "?"
35+
36+ def set_name (self , func : Callable ):
37+ """Set task name from function"""
38+ self .task_name = getattr (func , '__name__' , '?' )
39+
40+ def get_status (self ) -> str :
41+ """Get formatted status string with timing information"""
42+ if not self .start_time :
43+ status = 'Ready'
44+ else :
45+ elapsed = self .get_elapsed_time ()
46+ start_str = time .strftime ('%H:%M:%S' , time .localtime (self .start_time ))
47+
48+ if self .is_running ():
49+ status = f'Running "{ self .task_name } " for { elapsed :.1f} s since { start_str } '
50+ elif self .stop_time :
51+ stop_str = time .strftime ('%H:%M:%S' , time .localtime (self .stop_time ))
52+ status = f'Completed "{ self .task_name } " in { elapsed :.1f} s ({ start_str } -{ stop_str } )'
53+ else :
54+ status = f'Interrupted "{ self .task_name } " after { elapsed :.1f} s from { start_str } '
55+
56+ return status
57+
58+ def get_elapsed_time (self ) -> float :
59+ """Get elapsed time in seconds since task started"""
60+ elapsed = 0.0
61+ if self .start_time :
62+ if self .is_running ():
63+ elapsed = time .time () - self .start_time
64+ elif self .stop_time :
65+ elapsed = self .stop_time - self .start_time
66+ return elapsed
3267
3368 def cancel_running (self ):
3469 if self .task and not self .task .done ():
3570 self .task .cancel ()
36- if self .progress :
37- self .progress .reset ()
71+ if self .progress :
72+ self .progress .reset ()
73+ # Reset timing when cancelled
74+ self .start_time = None
75+ self .stop_time = None
3876
3977 def is_running (self ) -> bool :
4078 running = self .task and not self .task .done ()
@@ -65,9 +103,12 @@ def run_blocking(self, blocking_func: Callable, *args, **kwargs):
65103 blocking_func
66104 ):
67105 raise TypeError ("run_blocking expects a sync function, not async." )
68-
106+ self . set_name ( blocking_func )
69107 async def wrapper ():
70- await asyncio .to_thread (blocking_func , * args , ** kwargs )
108+ # this would be the native asyncio call
109+ # await asyncio.to_thread(blocking_func, *args, **kwargs)
110+ # we use nicegui managed threads
111+ await run .io_bound (blocking_func , * args , ** kwargs )
71112
72113 self ._start (wrapper )
73114
@@ -82,6 +123,7 @@ def run_async_wrapping_blocking(self, coro_func: Callable[[], asyncio.Future]):
82123 raise TypeError (
83124 "run_async_wrapping_blocking expects an async def function."
84125 )
126+ self .set_name (coro_func )
85127 self ._start (coro_func )
86128
87129 def run_async (self , coro_func : Callable [..., asyncio .Future ], * args , ** kwargs ):
@@ -94,10 +136,12 @@ def run_async(self, coro_func: Callable[..., asyncio.Future], *args, **kwargs):
94136 """
95137 if not inspect .iscoroutinefunction (coro_func ):
96138 raise TypeError ("run_async expects an async def function (not called yet)." )
139+ self .set_name (coro_func )
97140 self ._start (coro_func , * args , ** kwargs )
98141
99142 def _start (self , coro_func : Callable [..., asyncio .Future ], * args , ** kwargs ):
100143 self .cancel_running ()
144+ self .start_time = time .time ()
101145
102146 async def wrapped ():
103147 try :
@@ -116,5 +160,6 @@ async def wrapped():
116160 finally :
117161 if self .progress :
118162 self .progress .update_value (self .progress .total )
163+ self .stop_time = time .time ()
119164
120165 self .task = background_tasks .create (wrapped ())
0 commit comments