|
31 | 31 | from shiny.http_staticfiles import StaticFiles
|
32 | 32 | from shiny.module import resolve_id
|
33 | 33 | from shiny.render import RenderFunction, RenderFunctionAsync
|
| 34 | +from shiny.render.transformer import ( |
| 35 | + TransformerMetadata, |
| 36 | + ValueFn, |
| 37 | + output_transformer, |
| 38 | + resolve_value_fn, |
| 39 | +) |
34 | 40 | from shiny.session import get_current_session, require_active_session
|
35 | 41 |
|
36 | 42 | from ._as_widget import as_widget
|
@@ -182,71 +188,35 @@ def _restore_state():
|
182 | 188 |
|
183 | 189 | # --------------------------------------------------------------------------------------------
|
184 | 190 | # Implement @render_widget()
|
185 |
| -# TODO: shiny should probably make this simpler |
186 | 191 | # --------------------------------------------------------------------------------------------
|
187 | 192 |
|
188 |
| -IPyWidgetRenderFunc = Callable[[], Widget] |
189 |
| -IPyWidgetRenderFuncAsync = Callable[[], Awaitable[Widget]] |
190 |
| - |
191 |
| - |
192 |
| -class IPyWidget(RenderFunction[Widget, object]): |
193 |
| - def __init__(self, fn: IPyWidgetRenderFunc) -> None: |
194 |
| - super().__init__(fn) |
195 |
| - self._fn: IPyWidgetRenderFuncAsync = wrap_async(fn) |
196 |
| - |
197 |
| - def __call__(self) -> object: |
198 |
| - return run_coro_sync(self.run()) |
199 |
| - |
200 |
| - async def run(self) -> object: |
201 |
| - x = await self._fn() |
202 |
| - if x is None: |
203 |
| - return None |
204 |
| - widget = as_widget(x) |
205 |
| - return {"model_id": widget.model_id} # type: ignore |
206 | 193 |
|
207 |
| - |
208 |
| -class IPyWidgetAsync(IPyWidget, RenderFunctionAsync[Widget, object]): |
209 |
| - def __init__(self, fn: IPyWidgetRenderFuncAsync) -> None: |
210 |
| - if not inspect.iscoroutinefunction(fn): |
211 |
| - raise TypeError("IPyWidgetAsync requires an async function") |
212 |
| - super().__init__(cast(IPyWidgetRenderFunc, fn)) |
213 |
| - |
214 |
| - async def __call__(self) -> object: |
215 |
| - return await self.run() |
| 194 | +@output_transformer(default_ui=output_widget) |
| 195 | +async def WidgetTransformer( |
| 196 | + _meta: TransformerMetadata, |
| 197 | + _fn: ValueFn[object | None], |
| 198 | +) -> dict[str, Any] | None: |
| 199 | + value = await resolve_value_fn(_fn) |
| 200 | + if value is None: |
| 201 | + return None |
| 202 | + widget = as_widget(value) |
| 203 | + return {"model_id": widget.model_id} # type: ignore |
216 | 204 |
|
217 | 205 |
|
218 | 206 | @overload
|
219 |
| -def render_widget( |
220 |
| - fn: Union[IPyWidgetRenderFunc, IPyWidgetRenderFuncAsync] |
221 |
| -) -> IPyWidget: |
| 207 | +def render_widget(fn: WidgetTransformer.ValueFn) -> WidgetTransformer.OutputRenderer: |
222 | 208 | ...
|
223 | 209 |
|
224 | 210 |
|
225 | 211 | @overload
|
226 |
| -def render_widget() -> ( |
227 |
| - Callable[[Union[IPyWidgetRenderFunc, IPyWidgetRenderFuncAsync]], IPyWidget] |
228 |
| -): |
| 212 | +def render_widget() -> WidgetTransformer.OutputRendererDecorator: |
229 | 213 | ...
|
230 | 214 |
|
231 | 215 |
|
232 | 216 | def render_widget(
|
233 |
| - fn: Optional[Union[IPyWidgetRenderFunc, IPyWidgetRenderFuncAsync]] = None |
234 |
| -) -> Union[ |
235 |
| - IPyWidget, |
236 |
| - Callable[[Union[IPyWidgetRenderFunc, IPyWidgetRenderFuncAsync]], IPyWidget], |
237 |
| -]: |
238 |
| - def wrapper(fn: Union[IPyWidgetRenderFunc, IPyWidgetRenderFuncAsync]) -> IPyWidget: |
239 |
| - if inspect.iscoroutinefunction(fn): |
240 |
| - fn = cast(IPyWidgetRenderFuncAsync, fn) |
241 |
| - return IPyWidgetAsync(fn) |
242 |
| - else: |
243 |
| - fn = cast(IPyWidgetRenderFunc, fn) |
244 |
| - return IPyWidget(fn) |
245 |
| - |
246 |
| - if fn is None: |
247 |
| - return wrapper |
248 |
| - else: |
249 |
| - return wrapper(fn) |
| 217 | + fn: WidgetTransformer.ValueFn | None = None, |
| 218 | +) -> WidgetTransformer.OutputRenderer | WidgetTransformer.OutputRendererDecorator: |
| 219 | + return WidgetTransformer(fn) |
250 | 220 |
|
251 | 221 |
|
252 | 222 | def reactive_read(widget: Widget, names: Union[str, Sequence[str]]) -> Any:
|
|
0 commit comments