codeant-ai-for-open-source[bot] commented on code in PR #38405:
URL: https://github.com/apache/superset/pull/38405#discussion_r2930408610


##########
tests/unit_tests/mcp_service/chart/test_viz_type_names.py:
##########
@@ -0,0 +1,274 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Tests for viz_type display name mapping."""
+
+import re
+from pathlib import Path
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from superset.mcp_service.chart.schemas import serialize_chart_object
+from superset.mcp_service.chart.viz_type_names import (
+    _FRONTEND_ONLY_NAMES,
+    get_viz_type_display_name,
+    VIZ_TYPE_DISPLAY_NAMES,
+)
+from superset.utils import json
+
+# Paths to the source-of-truth files
+_JSON_PATH = (
+    Path(__file__).resolve().parents[4]
+    / "superset"
+    / "mcp_service"
+    / "chart"
+    / "viz_type_display_names.json"
+)
+_VIZTYPE_TS_PATH = (
+    Path(__file__).resolve().parents[4]
+    / "superset-frontend"
+    / "packages"
+    / "superset-ui-core"
+    / "src"
+    / "chart"
+    / "types"
+    / "VizType.ts"
+)
+
+
[email protected](autouse=True)
+def _reset_cache():
+    """Reset the lazy display-names cache between tests."""
+    import superset.mcp_service.chart.viz_type_names as mod
+
+    mod._display_names_cache = None
+    yield
+    mod._display_names_cache = None
+
+
[email protected](
+    ("viz_type", "expected"),
+    [
+        # Frontend-only modern plugins
+        ("echarts_timeseries_line", "Line Chart"),
+        ("echarts_timeseries_bar", "Bar Chart"),
+        ("pie", "Pie Chart"),
+        ("pivot_table_v2", "Pivot Table"),
+        ("big_number_total", "Big Number"),
+        ("table", "Table"),
+        ("word_cloud", "Word Cloud"),
+        ("funnel", "Funnel Chart"),
+        ("sankey_v2", "Sankey Chart"),
+    ],
+)
+def test_frontend_only_viz_types_have_display_names(
+    viz_type: str, expected: str
+) -> None:
+    assert get_viz_type_display_name(viz_type) == expected
+
+
+def test_legacy_viz_names_loaded_from_viz_py() -> None:
+    """Legacy chart names are read from BaseViz.verbose_name in viz.py."""
+
+    class FakeLegacyViz:
+        viz_type = "fake_legacy"
+        verbose_name = "Fake Legacy Chart"
+
+        @classmethod
+        def __subclasses__(cls):
+            return set()
+
+    class FakeBaseViz:
+        viz_type = None
+        verbose_name = "Base Viz"
+
+        @classmethod
+        def __subclasses__(cls):
+            return {FakeLegacyViz}
+
+    with patch(
+        "superset.mcp_service.chart.viz_type_names.BaseViz",
+        FakeBaseViz,
+        create=True,
+    ):
+        # Patch the import inside _get_legacy_viz_names
+        import superset.mcp_service.chart.viz_type_names as mod
+
+        with patch.object(mod, "_get_legacy_viz_names") as mock_legacy:
+            mock_legacy.return_value = {"fake_legacy": "Fake Legacy Chart"}
+            mod._display_names_cache = None
+

Review Comment:
   **Suggestion:** This test claims to verify legacy names are loaded from 
`viz.py`, but it mocks `_get_legacy_viz_names` itself, so the real 
import/subclass traversal code is never exercised. If that production logic 
breaks, this test will still pass and hide the regression. Patch `superset.viz` 
via `sys.modules` and call the real code path instead. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Legacy-name loader regressions can pass CI unnoticed.
   - ⚠️ list_charts/get_chart_info may return degraded chart type names.
   ```
   </details>
   
   ```suggestion
       import types
       import superset.mcp_service.chart.viz_type_names as mod
   
       fake_viz_module = types.ModuleType("superset.viz")
       fake_viz_module.BaseViz = FakeBaseViz
   
       with patch.dict("sys.modules", {"superset.viz": fake_viz_module}):
           mod._display_names_cache = None
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Run `pytest tests/unit_tests/mcp_service/chart/test_viz_type_names.py -v`;
   `test_legacy_viz_names_loaded_from_viz_py` executes at
   `tests/unit_tests/mcp_service/chart/test_viz_type_names.py:85`.
   
   2. In that test, `patch.object(mod, "_get_legacy_viz_names")` at
   `tests/unit_tests/mcp_service/chart/test_viz_type_names.py:112-114` replaces 
the
   production loader with a stub dict.
   
   3. `get_viz_type_display_name()` 
(`superset/mcp_service/chart/viz_type_names.py:99-120`)
   then builds cache via `_build_display_names()` (`viz_type_names.py:79-90`), 
but calls the
   mocked `_get_legacy_viz_names`, never exercising real import/subclass 
traversal in
   `_get_legacy_viz_names` (`viz_type_names.py:53-76`).
   
   4. Because of this, a regression in real legacy loading can slip through 
tests while
   runtime paths used by `list_charts`
   (`superset/mcp_service/chart/tool/list_charts.py:65-107`) and 
`get_chart_info`
   (`superset/mcp_service/chart/tool/get_chart_info.py:59-118`) still depend on
   `serialize_chart_object()` calling `get_viz_type_display_name()`
   (`superset/mcp_service/chart/schemas.py:248-267`).
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** tests/unit_tests/mcp_service/chart/test_viz_type_names.py
   **Line:** 104:115
   **Comment:**
        *Logic Error: This test claims to verify legacy names are loaded from 
`viz.py`, but it mocks `_get_legacy_viz_names` itself, so the real 
import/subclass traversal code is never exercised. If that production logic 
breaks, this test will still pass and hide the regression. Patch `superset.viz` 
via `sys.modules` and call the real code path instead.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38405&comment_hash=2e3924f758fa98e714e2e076b10de8da67bc3f56bda659bf9a91577c1c866140&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38405&comment_hash=2e3924f758fa98e714e2e076b10de8da67bc3f56bda659bf9a91577c1c866140&reaction=dislike'>👎</a>



##########
superset/mcp_service/chart/viz_type_names.py:
##########
@@ -0,0 +1,120 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+User-friendly display names for chart viz_type identifiers.
+
+The single source of truth for frontend-only chart display names is the
+JSON file ``viz_type_display_names.json`` in this directory.  A sync-
+validation test ensures it stays aligned with ``VizType.ts``.
+
+Legacy chart names are read from ``BaseViz.verbose_name`` in
+``superset/viz.py``, avoiding a duplicate hardcoded list.
+"""
+
+import logging
+from pathlib import Path
+
+from superset.utils import json
+
+logger = logging.getLogger(__name__)
+
+_JSON_PATH = Path(__file__).parent / "viz_type_display_names.json"
+
+
+def _load_frontend_display_names() -> dict[str, str]:
+    """Load frontend-only display names from the JSON source of truth."""
+    return json.loads(_JSON_PATH.read_text(encoding="utf-8"))

Review Comment:
   **Suggestion:** Loading the JSON file without error handling can crash 
module import at runtime (for example in packaged deployments where the data 
file is missing or unreadable), which then breaks chart serialization paths 
that import this module. Handle file/JSON read failures and return an empty 
mapping so callers can still use the fallback display-name logic. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ list_charts/get_chart_info can fail with server exceptions.
   - ⚠️ Dashboard chart serialization can fail on same import.
   - ⚠️ Fallback title-case naming never executes after import crash.
   ```
   </details>
   
   ```suggestion
       try:
           return json.loads(_JSON_PATH.read_text(encoding="utf-8"))
       except (FileNotFoundError, OSError, ValueError):
           logger.exception("Could not load viz type display names from %s", 
_JSON_PATH)
           return {}
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start MCP server (`python -m superset.mcp_service.server`), which exposes
   `list_charts`/`get_chart_info` tools defined at
   `superset/mcp_service/chart/tool/list_charts.py:67` and
   `superset/mcp_service/chart/tool/get_chart_info.py:61`.
   
   2. In a deployment where 
`superset/mcp_service/chart/viz_type_display_names.json` is
   missing/unreadable/corrupt, call `list_charts`; execution reaches
   `serialize_chart_object()` at `superset/mcp_service/chart/schemas.py:248`.
   
   3. `serialize_chart_object()` imports `get_viz_type_display_name` at
   `superset/mcp_service/chart/schemas.py:253`, which imports
   `superset/mcp_service/chart/viz_type_names.py`; module initialization 
executes
   `_FRONTEND_ONLY_NAMES = _load_frontend_display_names()` at 
`viz_type_names.py:47`.
   
   4. `_load_frontend_display_names()` at `viz_type_names.py:41` raises
   `FileNotFoundError`/`OSError`/JSON parse error, causing tool failure before 
fallback logic
   at `get_viz_type_display_name()` can run; same failure path affects 
`get_chart_info`
   (`get_chart_info.py:117`) and dashboard chart serialization
   (`superset/mcp_service/dashboard/schemas.py:512`).
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/chart/viz_type_names.py
   **Line:** 41:41
   **Comment:**
        *Possible Bug: Loading the JSON file without error handling can crash 
module import at runtime (for example in packaged deployments where the data 
file is missing or unreadable), which then breaks chart serialization paths 
that import this module. Handle file/JSON read failures and return an empty 
mapping so callers can still use the fallback display-name logic.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38405&comment_hash=c8793f85f4425367d350076e00a619862ab120d4f36d35244e2b14822f29d376&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38405&comment_hash=c8793f85f4425367d350076e00a619862ab120d4f36d35244e2b14822f29d376&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to