You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/09/22 01:25:25 UTC

(superset) branch master updated: fix(reports): replace stale Selenium references in screenshot messages (#44244)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new f47fcad3d6e fix(reports): replace stale Selenium references in screenshot messages (#44244)
f47fcad3d6e is described below

commit f47fcad3d6e5ec7740bc5b7dd26d21695580d2b4
Author: Sam Firke <sf...@users.noreply.github.com>
AuthorDate: Mon Sep 21 21:25:18 2026 -0400

    fix(reports): replace stale Selenium references in screenshot messages (#44244)
    
    Co-authored-by: Joe Li <jo...@preset.io>
---
 docker-compose.yml                       |  2 +-
 superset/config.py                       |  5 +++--
 superset/mcp_service/README.md           |  6 ++----
 superset/utils/screenshots.py            |  3 +--
 superset/utils/webdriver.py              | 17 ++++++++++++-----
 tests/unit_tests/utils/webdriver_test.py | 31 +++++++++++++++++++++++++++++++
 6 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/docker-compose.yml b/docker-compose.yml
index 381a1cefca4..2a7d01e86f2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -257,7 +257,7 @@ services:
       - "host.docker.internal:host-gateway"
     healthcheck:
       test: ["CMD-SHELL", "celery -A superset.tasks.celery_app:app inspect ping -d celery@$$HOSTNAME"]
-    # Bump memory limit if processing selenium / thumbnails on superset-worker
+    # Bump memory limit if processing screenshots / thumbnails on superset-worker
     # mem_limit: 2038m
     # mem_reservation: 128M
 
diff --git a/superset/config.py b/superset/config.py
index 5afe84e06fa..648e4f9fd0a 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -1287,8 +1287,8 @@ CACHE_WARMUP_EXECUTORS = [ExecutorType.EDITOR]
 # ---------------------------------------------------
 # Thumbnail config (behind feature flag)
 # ---------------------------------------------------
-# By default, thumbnails are rendered per user, and will fall back to the Selenium
-# user for anonymous users. Similar to Alerts & Reports, thumbnails
+# By default, thumbnails are rendered as the user who requests them. Similar to
+# Alerts & Reports, thumbnails
 # can be configured to always be rendered as a fixed user. See
 # `superset.tasks.types.ExecutorType` for a full list of executor options.
 # To always use a fixed user account (admin in this example, use the following
@@ -1365,6 +1365,7 @@ SUPERSET_CACHE_WARMUP_USER: str | None = None
 SCREENSHOT_LOCATE_WAIT = int(timedelta(seconds=10).total_seconds())
 # Time before screenshot capture times out while waiting for chart readiness.
 SCREENSHOT_LOAD_WAIT = int(timedelta(minutes=1).total_seconds())
+# "SELENIUM" in the next two key names is historical; both apply to Playwright.
 # Give the browser an initial headstart, in seconds
 SCREENSHOT_SELENIUM_HEADSTART = 3
 # Wait for the chart animation, in seconds
diff --git a/superset/mcp_service/README.md b/superset/mcp_service/README.md
index 052b18d681c..2079ba94884 100644
--- a/superset/mcp_service/README.md
+++ b/superset/mcp_service/README.md
@@ -688,9 +688,8 @@ fixed dev-mode identity would defeat the point of requiring real auth. Pick one:
 # MCP Service Configuration -- development/testing (no auth)
 MCP_DEV_USERNAME = 'admin'                    # Username for development/testing
 
-# WebDriver for chart screenshots
+# Headless browser (Playwright + Chromium) settings for chart screenshots
 WEBDRIVER_BASEURL = 'http://superset:8088/'
-WEBDRIVER_TYPE = 'chrome'
 WEBDRIVER_OPTION_ARGS = ['--headless', '--no-sandbox']
 ```
 
@@ -703,9 +702,8 @@ MCP_JWT_PUBLIC_KEY = 'your-public-key'        # For JWT token validation
 MCP_AUTH_FACTORY = 'your.custom.auth_factory'
 MCP_USER_RESOLVER = 'your.custom.user_resolver'
 
-# WebDriver for chart screenshots
+# Headless browser (Playwright + Chromium) settings for chart screenshots
 WEBDRIVER_BASEURL = 'http://superset:8088/'
-WEBDRIVER_TYPE = 'chrome'
 WEBDRIVER_OPTION_ARGS = ['--headless', '--no-sandbox']
 ```
 
diff --git a/superset/utils/screenshots.py b/superset/utils/screenshots.py
index 1b7a70bea10..cd331a8b3e6 100644
--- a/superset/utils/screenshots.py
+++ b/superset/utils/screenshots.py
@@ -542,7 +542,6 @@ class BaseScreenshot:
                 else:
                     self.cache.set(cache_key, cache_payload.to_dict())
                 image = None
-                # Assuming all sorts of things can go wrong with Selenium
                 try:
                     logger.info(
                         "trying to generate screenshot for cache_key=%s", cache_key
@@ -647,7 +646,7 @@ class BaseScreenshot:
         context_suffix = f" [{log_context}]" if log_context else ""
         thumb_size = thumb_size or cls.thumb_size
         img = Image.open(BytesIO(img_bytes))
-        logger.debug("Selenium image size: %s%s", str(img.size), context_suffix)
+        logger.debug("Screenshot image size: %s%s", str(img.size), context_suffix)
         if crop and img.size[1] != cls.window_size[1]:
             desired_ratio = float(cls.window_size[1]) / cls.window_size[0]
             desired_width = int(img.size[0] * desired_ratio)
diff --git a/superset/utils/webdriver.py b/superset/utils/webdriver.py
index 3aa464ebc33..d7ae9618d05 100644
--- a/superset/utils/webdriver.py
+++ b/superset/utils/webdriver.py
@@ -66,10 +66,12 @@ from superset.utils.screenshot_utils import (
 WindowSize = tuple[int, int]
 logger = logging.getLogger(__name__)
 
-# Installation message for missing Playwright (Cypress doesn't work with DeckGL)
+# Installation hint for the one failure that carries no error of its own: the
+# Playwright import failed, so there is nothing to report but this. Launch
+# failures raise Playwright's own error instead, which already says whether the
+# browser binary is missing and which command installs it.
 PLAYWRIGHT_INSTALL_MESSAGE = (
-    "To complete the migration from Cypress "
-    "and enable WebGL/DeckGL screenshot support, install Playwright with: "
+    "Install Playwright and Chromium with: "
     "pip install playwright && playwright install chromium"
 )
 
@@ -944,9 +946,14 @@ class WebDriverPlaywright(WebDriverProxy):
         try:
             browser = _browser_manager.get_browser(browser_args)
         except Exception as ex:
+            logger.exception(
+                "Failed to launch the headless browser with args %s%s",
+                browser_args,
+                context_suffix,
+            )
             raise RuntimeError(
-                f"Playwright is required for screenshots. "
-                f"{PLAYWRIGHT_INSTALL_MESSAGE}{context_suffix}"
+                f"Failed to launch the headless browser for screenshots: "
+                f"{ex}{context_suffix}"
             ) from ex
         pixel_density = app.config["WEBDRIVER_WINDOW"].get("pixel_density", 1)
         viewport_height = self._window[1]
diff --git a/tests/unit_tests/utils/webdriver_test.py b/tests/unit_tests/utils/webdriver_test.py
index 5a0068d37aa..e7461f9e3ab 100644
--- a/tests/unit_tests/utils/webdriver_test.py
+++ b/tests/unit_tests/utils/webdriver_test.py
@@ -41,6 +41,7 @@ from superset.utils.webdriver import (
     check_playwright_availability,
     PLAYWRIGHT_AVAILABLE,
     PLAYWRIGHT_INSTALL_MESSAGE,
+    PlaywrightError,
     WebDriverPlaywright,
 )
 
@@ -505,6 +506,36 @@ class TestWebDriverPlaywrightFallback:
         with pytest.raises(RuntimeError, match="Playwright is required"):
             driver.get_screenshot("http://example.com", "test-element", mock_user)
 
+    @patch("superset.utils.webdriver.PLAYWRIGHT_AVAILABLE", True)
+    @patch("superset.utils.webdriver._browser_manager")
+    @patch("superset.utils.webdriver.app")
+    def test_get_screenshot_surfaces_the_browser_launch_error(
+        self, mock_app, mock_browser_manager
+    ):
+        """Chromium is installed but refuses to start, here because the worker
+        runs as root without --no-sandbox. Every launch failure used to be
+        reported as a missing dependency, sending operators after a reinstall
+        that fixes nothing, so Playwright's own error is passed through instead
+        (#44244). A missing browser binary takes the same path: Playwright names
+        the expected path and the install command in its message, which is more
+        than Superset can say about it."""
+        mock_app.config = {
+            "WEBDRIVER_OPTION_ARGS": [],
+            "SCREENSHOT_LOCATE_WAIT": 10,
+            "SCREENSHOT_LOAD_WAIT": 10,
+        }
+        mock_browser_manager.get_browser.side_effect = PlaywrightError(
+            "BrowserType.launch: Running as root without --no-sandbox is not supported."
+        )
+
+        driver = WebDriverPlaywright("chrome")
+        with pytest.raises(RuntimeError) as excinfo:
+            driver.get_screenshot("http://example.com", "test-element")
+
+        message = str(excinfo.value)
+        assert "Running as root without --no-sandbox" in message
+        assert PLAYWRIGHT_INSTALL_MESSAGE not in message
+
     @patch("superset.utils.webdriver.PLAYWRIGHT_AVAILABLE", True)
     @patch("superset.utils.webdriver._browser_manager")
     @patch("superset.utils.webdriver.app")