Spaces:
Running
Running
import time | |
from concurrent.futures import ThreadPoolExecutor | |
from contextlib import contextmanager | |
import numpy as np | |
import panel as pn | |
import param | |
from asyncio import wrap_future | |
class ProgressExtMod(pn.viewable.Viewer): | |
"""A custom component for easy progress reporting""" | |
completed = param.Integer(default=0) | |
bar_color = param.String(default="info") | |
num_tasks = param.Integer(default=100, bounds=(1, None)) | |
# @param.depends('completed', 'num_tasks') | |
def value(self) -> int: | |
"""Returns the progress value | |
Returns: | |
int: The progress value | |
""" | |
return int(100 * (self.completed / self.num_tasks)) | |
def reset(self): | |
"""Resets the value and message""" | |
# Please note the order matters as the Widgets updates two times. One for each change | |
self.completed = 0 | |
def __panel__(self): | |
return self.view | |
def view(self): | |
"""View the widget | |
Returns: | |
pn.viewable.Viewable: Add this to your app to see the progress reported | |
""" | |
if self.value: | |
return pn.widgets.Progress( | |
active=True, value=self.value, align="center", sizing_mode="stretch_width" | |
) | |
return None | |
def increment(self): | |
"""Increments the value | |
Can be used as context manager or decorator | |
Yields: | |
None: Nothing is yielded | |
""" | |
self.completed += 1 | |
yield | |
if self.completed == self.num_tasks: | |
self.reset() | |
executor = ThreadPoolExecutor(max_workers=2) # pylint: disable=consider-using-with | |
progress = ProgressExtMod() | |
class AsyncComponent(pn.viewable.Viewer): | |
"""A component that demonstrates how to run a Blocking Background task asynchronously | |
in Panel""" | |
select = param.Selector(objects=range(10)) | |
slider = param.Number(2, bounds=(0, 10)) | |
run_blocking_task = param.Event(label="RUN") | |
result = param.Number(0) | |
view = param.Parameter() | |
def __init__(self, **params): | |
super().__init__(**params) | |
self._layout = pn.Column( | |
pn.pane.Markdown("## Blocking Task Running in Background"), | |
pn.Param( | |
self, | |
parameters=["run_blocking_task", "result"], | |
widgets={"result": {"disabled": True}, "run_blocking_task": {"button_type": "primary"}}, | |
show_name=False, | |
), | |
progress, | |
pn.pane.Markdown("## Other, Non-Blocked Tasks"), | |
pn.Param( | |
self, | |
parameters=["select", "slider"], | |
widgets={"text": {"disabled": True}}, | |
show_name=False, | |
), | |
self.text | |
) | |
def __panel__(self): | |
return self._layout | |
def text(self): | |
if self.select: | |
select = self.select | |
else: | |
select = 0 | |
return f"{select} + {self.slider} = {select + self.slider}" | |
async def _run_blocking_tasks(self, num_tasks=10): | |
"""Runs background tasks num_tasks times""" | |
num_tasks = 20 | |
progress.num_tasks = num_tasks | |
for _ in range(num_tasks): | |
future = executor.submit(self._run_blocking_task) | |
result = await wrap_future(future) | |
self._update(result) | |
def _update(self, number): | |
self.result += number | |
def _run_blocking_task(): | |
time.sleep(np.random.randint(1, 2)) | |
return 5 | |
if pn.state.served: | |
pn.extension() | |
component = AsyncComponent() | |
pn.template.FastListTemplate( | |
site="Awesome Panel", site_url="https://awesome-panel.org", title="Async Tasks", main=[component], main_layout=None, main_max_width="400px" | |
).servable() | |