Spaces:
Runtime error
Runtime error
File size: 3,906 Bytes
9beecf3 ab6a63c 9beecf3 ab6a63c 9beecf3 ab6a63c 9beecf3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
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')
@property
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
@param.depends("completed", "bar_color")
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
@contextmanager
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
@param.depends("slider", "select")
def text(self):
if self.select:
select = self.select
else:
select = 0
return f"{select} + {self.slider} = {select + self.slider}"
@pn.depends("run_blocking_task", watch=True)
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)
@progress.increment()
def _update(self, number):
self.result += number
@staticmethod
def _run_blocking_task():
time.sleep(np.random.randint(1, 2))
return 5
if __name__.startswith("bokeh"):
pn.extension(template="fast")
pn.pane.Markdown(__doc__).servable()
AsyncComponent().servable() # pylint: disable=no-value-for-parameter |