From 88deca4a52dda23953ef12d181a121d1ef0aa842 Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Thu, 14 Dec 2023 18:20:59 -0600 Subject: [PATCH] Express: don't automatically put strings in a `
` block
 (#905)

---
 setup.cfg                               |  2 +-
 shiny/express/_recall_context.py        | 17 ++---------------
 shiny/render/_display.py                |  4 ++--
 tests/playwright/utils/express_utils.py |  6 +++---
 4 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/setup.cfg b/setup.cfg
index 814ccd013..ba7d24196 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -37,7 +37,7 @@ install_requires =
     starlette>=0.17.1
     websockets>=10.0
     python-multipart
-    htmltools>=0.4.1.9001
+    htmltools @ git+https://github.com/posit-dev/py-htmltools.git
     click>=8.1.4
     markdown-it-py>=1.1.0
     # This is needed for markdown-it-py. Without it, when loading shiny/ui/_markdown.py,
diff --git a/shiny/express/_recall_context.py b/shiny/express/_recall_context.py
index 3317ff2a1..0dc55d52a 100644
--- a/shiny/express/_recall_context.py
+++ b/shiny/express/_recall_context.py
@@ -5,7 +5,7 @@
 from types import TracebackType
 from typing import Callable, Generic, Mapping, Optional, Type, TypeVar
 
-from htmltools import HTML, Tag, Tagifiable, TagList, tags
+from htmltools import Tag, wrap_displayhook_handler
 
 from .._typing_extensions import ParamSpec
 
@@ -32,19 +32,6 @@ def __init__(
         self.args: list[object] = list(args)
         self.kwargs: dict[str, object] = dict(kwargs)
 
-    def append_arg(self, value: object):
-        if isinstance(value, (Tag, TagList, Tagifiable)):
-            self.args.append(value)
-        elif hasattr(value, "_repr_html_"):
-            self.args.append(HTML(value._repr_html_()))  # pyright: ignore
-        else:
-            # We should NOT end up here for objects that were `def`ed, because they
-            # would already have been filtered out by _display_decorator_function_def().
-            # This is only for other kinds of expressions, the kind which would normally
-            # be printed at the console.
-            if value is not None:
-                self.args.append(tags.pre(repr(value)))
-
     def __enter__(self) -> None:
         if self.default_page is not None:
             from . import _run
@@ -53,7 +40,7 @@ def __enter__(self) -> None:
 
         self._prev_displayhook = sys.displayhook
         # Collect each of the "printed" values in the args list.
-        sys.displayhook = self.append_arg
+        sys.displayhook = wrap_displayhook_handler(self.args.append)
 
     def __exit__(
         self,
diff --git a/shiny/render/_display.py b/shiny/render/_display.py
index 6c6f38bb6..b9eb002ee 100644
--- a/shiny/render/_display.py
+++ b/shiny/render/_display.py
@@ -4,7 +4,7 @@
 import sys
 from typing import Any, Callable, Optional, Union, overload
 
-from htmltools import TagAttrValue, TagFunction, TagList
+from htmltools import TagAttrValue, TagFunction, TagList, wrap_displayhook_handler
 
 from .. import ui as _ui
 from ..session._utils import RenderedDeps
@@ -29,7 +29,7 @@ async def DisplayTransformer(
 ) -> RenderedDeps | None:
     results: list[object] = []
     orig_displayhook = sys.displayhook
-    sys.displayhook = results.append
+    sys.displayhook = wrap_displayhook_handler(results.append)
     try:
         x = _fn()
         if inspect.iscoroutine(x):
diff --git a/tests/playwright/utils/express_utils.py b/tests/playwright/utils/express_utils.py
index c76412985..961500efa 100644
--- a/tests/playwright/utils/express_utils.py
+++ b/tests/playwright/utils/express_utils.py
@@ -51,11 +51,11 @@ def verify_express_page_default(page: Page) -> None:
     nav_html.set("span")
     nav_html.expect_content("span 0span 1span 2")
     navset_card_tab = LayoutNavsetTab(page, "express_navset_card_tab")
-    navset_card_tab.expect_content("Ellipsis")
+    navset_card_tab.expect_content("")
     # since it is a custom table we can't use the OutputTable controls
     shell_text = page.locator("#shell").inner_text().strip()
     assert shell_text == (
-        "'R1C1R1'\n'R1C1R2-R1C1R1'\n'R1C1R2-R1C1R2'\n'R1C1R2-R1C2'\n'R1C2'"
+        "R1C1R1\nR1C1R2-R1C1R1\nR1C1R2-R1C1R2\nR1C1R2-R1C2\nR1C2"
     ), "Locator contents don't match expected text"
 
 
@@ -79,7 +79,7 @@ def verify_express_page_fluid(page: Page) -> None:
 
 def verify_express_page_sidebar(page: Page) -> None:
     sidebar = Sidebar(page, "sidebar")
-    sidebar.expect_text("SidebarTitle 'Sidebar Content'")
+    sidebar.expect_text("SidebarTitle Sidebar Content")
     output_txt = OutputTextVerbatim(page, "txt")
     output_txt.expect_value("50")
     compare_annotations(ui.sidebar, layout.sidebar)