render.transformer.output_transformer

render.transformer.output_transformer(
    transform_fn=None,
    *,
    default_ui=None,
    default_ui_passthrough_args=None,
)

Deprecated. Please use Renderer instead.

Output transformer decorator.

This decorator method is a convenience method to generate the appropriate types and internal implementation for an overloaded renderer method. This method will provide you with all the necessary types to define two different overloads: one for when the decorator is called without parentheses and another for when it is called with parentheses where app authors can pass in parameters to the renderer.

Transform function

The output renderer’s transform function (transform_fn) is the key building block for output_transformer. It is a package author function that calls the app-defined output value function (value_fn) transforms the result of type IT into type OT.

The transform function is supplied meta output information, the (app-supplied) value function, and any keyword arguments supplied to the output tranformer decorator:

  • The first parameter to the handler function has the class TransformerMetadata and is typically called _meta. This information gives context to the handler while trying to resolve the app-supplied value function (typically called _fn).
  • The second parameter is the app-defined output value function (e.g. _fn). It’s return type (IT) determines what types can be returned by the app-supplied output value function. For example, if _fn has the type ValueFnAsync[str | None], both the str and None types are allowed to be returned from the app-supplied output value function.
  • The remaining parameters are the keyword arguments (e.g. alt:Optional[str] = None or **kwargs: object) that app authors may supply to the renderer (when the renderer decorator is called with parentheses). Variadic positional parameters (e.g. *args) are not allowed. All keyword arguments should have a type and default value. No default value is needed for keyword arguments that are passed through (e.g. **kwargs: Any).

The transform function’s return type (OT) determines the output type of the OutputRenderer. Note that in many cases (but not all!) IT and OT will be the same. The None type should typically be defined in both IT and OT. If IT allows for None values, it (typically) signals that nothing should be rendered. If OT allows for None and returns a None value, shiny will not render the output.

Notes

  • When defining the renderer decorator overloads, if you have extra parameters of **kwargs: object, you may get a type error about incompatible signatures. To fix this, you can use **kwargs: Any instead or add _fn: None = None as the first parameter in the overload containing the **kwargs: object.

  • The transform_fn should be defined as an asynchronous function but should only asynchronously yield (i.e. use await syntax) when the value function (the second parameter of type ValueFn[IT]) is awaitable. If the value function is not awaitable (i.e. it is a synchronous function), then the execution of the transform function should also be synchronous.

Parameters

transform_fn : TransformFn[IT, P, OT] | None = None

Asynchronous function used to determine the app-supplied output value function return type (IT), the transformed type (OT), and the keyword arguments (P) app authors can supply to the renderer decorator.

default_ui : Optional[DefaultUIFn] = None

Optional function that takes an output_id string and returns a Shiny UI object that can be used to display the output. This allows render functions to respond to _repr_html_ method calls in environments like Jupyter.

Returns

: OutputTransformer[IT, OT, P] | Callable[[TransformFn[IT, P, OT]], OutputTransformer[IT, OT, P]]

An OutputTransformer object that can be used to define two overloads for your renderer function. One overload is for when the renderer is called without parentheses and the other is for when the renderer is called with parentheses.

Examples

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400

## file: app.py
from __future__ import annotations

from typing import Literal, overload

from shiny import App, Inputs, Outputs, Session, ui
from shiny.render.transformer import (
    TransformerMetadata,
    ValueFn,
    output_transformer,
    resolve_value_fn,
)

#######
# DEPRECATED. Please see `shiny.render.renderer.Renderer` for the latest API.
# This example is kept for backwards compatibility.
#
#
# Package authors can create their own output transformer methods by leveraging
# `output_transformer` decorator.
#
# The transformer is kept simple for demonstration purposes, but it can be much more
# complex (e.g. shiny.render.plotly)
#######


# Create renderer components from the async handler function: `capitalize_components()`
@output_transformer()
async def CapitalizeTransformer(
    # Contains information about the render call: `name` and `session`
    _meta: TransformerMetadata,
    # The app-supplied output value function
    _fn: ValueFn[str | None],
    *,
    # Extra parameters that app authors can supply to the render decorator
    # (e.g. `@render_capitalize(to="upper")`)
    to: Literal["upper", "lower"] = "upper",
) -> str | None:
    # Get the value
    value = await resolve_value_fn(_fn)
    # Equvalent to:
    # if shiny.render.transformer.is_async_callable(_fn):
    #     value = await _fn()
    # else:
    #     value = _fn()

    # Render nothing if `value` is `None`
    if value is None:
        return None

    if to == "upper":
        return value.upper()
    if to == "lower":
        return value.lower()
    raise ValueError(f"Invalid value for `to`: {to}")


# First, create an overload where users can supply the extra parameters.
# Example of usage:
# ```
# @render_capitalize(to="upper")
# def value():
#     return input.caption()
# ```
# Note: Return type is `OutputRendererDecorator`
@overload
def render_capitalize(
    *,
    to: Literal["upper", "lower"] = "upper",
) -> CapitalizeTransformer.OutputRendererDecorator: ...


# Second, create an overload where users are not using parentheses to the method.
# While it doesn't look necessary, it is needed for the type checker.
# Example of usage:
# ```
# @render_capitalize
# def value():
#     return input.caption()
# ```
# Note: `_fn` type is the transformer's `ValueFn`
# Note: Return type is the transformer's `OutputRenderer`
@overload
def render_capitalize(
    _fn: CapitalizeTransformer.ValueFn,
) -> CapitalizeTransformer.OutputRenderer: ...


# Lastly, implement the renderer.
# Note: `_fn` type is the transformer's `ValueFn` or `None`
# Note: Return type is the transformer's `OutputRenderer` or `OutputRendererDecorator`
def render_capitalize(
    _fn: CapitalizeTransformer.ValueFn | None = None,
    *,
    to: Literal["upper", "lower"] = "upper",
) -> (
    CapitalizeTransformer.OutputRenderer | CapitalizeTransformer.OutputRendererDecorator
):
    return CapitalizeTransformer(
        _fn,
        CapitalizeTransformer.params(to=to),
    )


#######
# End of package author code
#######

app_ui = ui.page_fluid(
    ui.h1("Capitalization renderer"),
    ui.input_text("caption", "Caption:", "Data summary"),
    "Renderer called with out parentheses:",
    ui.output_text_verbatim("no_parens"),
    "To upper:",
    ui.output_text_verbatim("to_upper"),
    "To lower:",
    ui.output_text_verbatim("to_lower"),
)


def server(input: Inputs, output: Outputs, session: Session):
    # Without parentheses
    @render_capitalize
    def no_parens():
        return input.caption()

    # With parentheses. Equivalent to `@render_capitalize()`
    @render_capitalize(to="upper")
    def to_upper():
        return input.caption()

    @render_capitalize(to="lower")
    # Works with async output value functions
    async def to_lower():
        return input.caption()


app = App(app_ui, server)