Create output renderers
Package author methods for creating new output renderers.
render.renderer.Renderer
render.renderer.Renderer(self, _fn=None)
Output renderer class
An output renderer is a class that will take in a callable function (value function), transform the returned value into a JSON-serializable object, and send the result to the browser.
When the value function is received, the renderer will be auto registered with the current session's Output
class, hooking it into Shiny's reactive graph. By auto registering as an Output
, it allows for App authors to skip adding @output
above the renderer. (If programmatic id
is needed, @output(id="foo")
can still be used!)
There are two methods that must be implemented by the subclasses: .auto_output_ui(self)
and either .transform(self, value: IT)
or .render(self)
.
- In Express mode, the output renderer will automatically render its UI via
.auto_output_ui(self)
. This helper method allows App authors to skip adding aui.output_*
function to their UI, making Express mode even more concise. If more control is needed over the UI,@ui.hold
can be used to suppress the auto rendering of the UI. When using@ui.hold
on a renderer, the renderer's UI will need to be added to the app to connect the rendered output to Shiny's reactive graph. - The
render
method is responsible for executing the value function and performing any transformations for the output value to be JSON-serializable (None
is a valid value!). To avoid the boilerplate of resolving the value function and returning early ifNone
is received, package authors may implement the.transform(self, value: IT)
method. Thetransform
method's sole job is to transform non-None
values into an object that is JSON-serializable.
Examples
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400
## file: app.py
from __future__ import annotations
# Import the custom renderer implementations
from renderers import render_capitalize, render_upper
from shiny import App, Inputs, Outputs, Session, ui
app_ui = ui.page_fluid(
ui.h1("Capitalization renderer"),
ui.input_text("caption", "Caption:", "Data summary"),
"@render_upper: ",
ui.output_text_verbatim("upper", placeholder=True),
"@render_upper(): ",
ui.output_text_verbatim("upper_with_paren", placeholder=True),
"@render_capitalize: ",
ui.output_text_verbatim("cap_upper", placeholder=True),
"@render_capitalize(to='lower'): ",
ui.output_text_verbatim("cap_lower", placeholder=True),
)
def server(input: Inputs, output: Outputs, session: Session):
# Hovering over `@render_upper` will display the class documentation
@render_upper
def upper():
return input.caption()
# Hovering over `@render_upper` will display the class documentation as there is no
# `__init__()` documentation
@render_upper()
def upper_with_paren():
return input.caption()
# Hovering over `@render_capitalize` will display the class documentation
@render_capitalize
def cap_upper():
return input.caption()
# Hovering over `@render_capitalize` will display the `__init__()` documentation
@render_capitalize(to_case="lower")
def cap_lower():
return input.caption()
app = App(app_ui, server)
## file: renderers.py
from __future__ import annotations
from typing import Literal, Optional
from shiny.render.renderer import Renderer, ValueFn
from shiny.ui import output_text_verbatim
class render_capitalize(Renderer[str]):
# The documentation for the class will be displayed when the user hovers over the
# decorator when **no** parenthesis are used. Ex: `@render_capitalize`
# If no documentation is supplied to the `__init__()` method, then this
# documentation will be displayed when parenthesis are used on the decorator.
"""
Render capitalize class documentation goes here.
"""
to_case: Literal["upper", "lower", "ignore"]
"""
The case to render the value in.
"""
placeholder: bool
"""
Whether to render a placeholder value. (Defaults to `True`)
"""
def auto_output_ui(self):
"""
Express UI for the renderer
"""
return output_text_verbatim(self.output_id, placeholder=True)
def __init__(
self,
_fn: Optional[ValueFn[str]] = None,
*,
to_case: Literal["upper", "lower", "ignore"] = "upper",
placeholder: bool = True,
) -> None:
# If a different set of documentation is supplied to the `__init__` method,
# then this documentation will be displayed when parenthesis are used on the decorator.
# Ex: `@render_capitalize()`
"""
Render capitalize documentation goes here.
It is a good idea to talk about parameters here!
## Parameters
to_case
The case to render the value. (`"upper"`)
Options:
- `"upper"`: Render the value in upper case.
- `"lower"`: Render the value in lower case.
- `"ignore"`: Do not alter the case of the value.
placeholder
Whether to render a placeholder value. (`True`)
"""
# Do not pass params
super().__init__(_fn)
self.to_case = to_case
self.placeholder = placeholder
async def render(self) -> str | None:
value = await self.fn()
if value is None:
# If `None` is returned, then do not render anything.
return None
ret = str(value)
if self.to_case == "upper":
return ret.upper()
if self.to_case == "lower":
return ret.lower()
if self.to_case == "ignore":
return ret
raise ValueError(f"Invalid value for `to_case`: {self.to_case}")
class render_upper(Renderer[str]):
"""
Minimal capitalize string transformation renderer.
No parameters are supplied to this renderer. This allows us to skip the `__init__()`
method and `__init__()` documentation. If you hover over this decorator with and
without parenthesis, you will see this documentation in both situations.
Note: This renderer is equivalent to `render_capitalize(to="upper")`.
"""
def auto_output_ui(self):
"""
Express UI for the renderer
"""
return output_text_verbatim(self.output_id, placeholder=True)
async def transform(self, value: str) -> str:
"""
Transform the value to upper case.
This method is shorthand for the default `render()` method. It is useful to
transform non-`None` values. (Any `None` value returned by the app author will
be forwarded to the browser.)
## Parameters
value
The a non-`None` value to transform.
## Returns
str
The transformed value. (Must be a subset of `Jsonifiable`.)
"""
return str(value).upper()
Attributes
Name | Description |
---|---|
fn | App-supplied output value function which returns type IT . This function is always asyncronous as the original app-supplied function possibly wrapped to execute asynchonously. |
output_id | Output function name or ID (provided to @output(id=) ). |
Methods
Name | Description |
---|---|
auto_output_ui | Express mode method that automatically generates the output’s UI. |
render | Renders the output value function. |
transform | Transform an output value into a JSON-serializable object. |
auto_output_ui
render.renderer.Renderer.auto_output_ui()
Express mode method that automatically generates the output's UI.
render
render.renderer.Renderer.render()
Renders the output value function.
This method is called when the renderer is requested to render its output.
The Renderer
's render()
implementation goes as follows:
- Execute the value function supplied to the renderer.
- If the output value is
None
,None
will be returned. - If the output value is not
None
, the.transform()
method will be called to transform the value into a JSON-serializable object.
When overwriting this method in a subclass, the implementation should execute the value function .fn
and return the transformed value (which is JSON-serializable).
transform
render.renderer.Renderer.transform(value)
Transform an output value into a JSON-serializable object.
When subclassing Renderer
, this method can be implemented to transform non-None
values into a JSON-serializable object.
If a .render()
method is not implemented, this method must be implemented. When the output is requested, the Renderer
's .render()
method will execute the output value function, return None
if the value is None
, and call this method to transform the value into a JSON-serializable object.
Note, only one of .transform()
or .render()
should be implemented.
render.renderer.Jsonifiable
render.renderer.Jsonifiable
render.renderer.ValueFn
render.renderer.ValueFn
App-supplied output value function which returns type IT
or None
. This function can be synchronous or asynchronous.
render.renderer.AsyncValueFn
render.renderer.AsyncValueFn(self, fn)
App-supplied output value function which returns type IT
. asynchronous.
Type definition: Callable[[], Awaitable[IT]]
Methods
Name | Description |
---|---|
get_async_fn | Return the async value function. |
get_sync_fn | Retrieve the original, synchronous value function function. |
is_async | Was the original function asynchronous? |
get_async_fn
render.renderer.AsyncValueFn.get_async_fn()
Return the async value function.
Returns
Type | Description |
---|---|
Callable[[], Awaitable[IT | None]] |
Async wrapped value function supplied to the AsyncValueFn constructor. |
get_sync_fn
render.renderer.AsyncValueFn.get_sync_fn()
Retrieve the original, synchronous value function function.
If the original function was asynchronous, a runtime error will be thrown.
Returns
Type | Description |
---|---|
Callable[[], IT | None] |
Original, synchronous function supplied to the AsyncValueFn constructor. |
is_async
render.renderer.AsyncValueFn.is_async()
Was the original function asynchronous?
Returns
Type | Description |
---|---|
bool | Whether the original function is asynchronous. |
render.renderer.RendererT
render.renderer.RendererT
Generic output renderer class to pass the original Renderer subclass through a decorator function.
When accepting and returning a Renderer
class, utilize this TypeVar as to not reduce the variable type to Renderer[Any]