Skip to content

Commit

Permalink
feat(express): Automatically suppress non-renderable UI objects
Browse files Browse the repository at this point in the history
  • Loading branch information
gadenbuie committed Nov 14, 2024
1 parent 36aa320 commit 108c5bb
Showing 1 changed file with 30 additions and 3 deletions.
33 changes: 30 additions & 3 deletions shiny/express/_recall_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,42 @@
import functools
import sys
from types import TracebackType
from typing import Callable, Generic, Mapping, Optional, Type, TypeVar
from typing import Any, Callable, Generic, Mapping, Optional, Type, TypeVar

from htmltools import MetadataNode, Tag, TagList, wrap_displayhook_handler
from htmltools import (
HTML,
MetadataNode,
ReprHtml,
Tag,
Tagifiable,
TagList,
wrap_displayhook_handler,
)

from .._typing_extensions import ParamSpec
from ..render.renderer import Renderer

P = ParamSpec("P")
R = TypeVar("R")
U = TypeVar("U")


def only_append_renderable(handler: Callable[[object], None]) -> Callable[[Any], None]:
def f(x: Any):
if isinstance(x, str):
return handler(x)
elif isinstance(x, (str, HTML, Tag, TagList, Tagifiable, ReprHtml, Renderer)):
return handler(x) # pyright: ignore

print(
# TODO: Make this a more informative warning
f"Express is suppressed the object of type {type(x)}. "
"Coerce to HTML, a string, or an htmltools tag to display this object."
)

return f


class RecallContextManager(Generic[R]):
def __init__(
self,
Expand All @@ -31,7 +56,9 @@ def __init__(
self.kwargs: dict[str, object] = dict(kwargs)
# Let htmltools.wrap_displayhook_handler decide what to do with objects before
# we append them.
self.wrapped_append = wrap_displayhook_handler(self.args.append)
self.wrapped_append = only_append_renderable(
wrap_displayhook_handler(self.args.append)
)

def __enter__(self) -> None:
self._prev_displayhook = sys.displayhook
Expand Down

0 comments on commit 108c5bb

Please sign in to comment.