codeant-ai-for-open-source[bot] commented on code in PR #40077:
URL: https://github.com/apache/superset/pull/40077#discussion_r3230462105
##########
superset/mcp_service/chart/tool/update_chart_preview.py:
##########
@@ -229,9 +234,35 @@ def update_chart_preview( # noqa: C901
high_contrast_available=False,
)
- # Note: Screenshot-based previews are not supported.
- # Use the explore_url to view the chart interactively.
previews: Dict[str, Any] = {}
+ if request.generate_preview:
+ try:
+ with event_logger.log_context(
+ action="mcp.update_chart_preview.preview"
+ ):
+ for format_type in request.preview_formats:
+ # URL previews are represented by
explore_url/chart.url.
+ # Screenshot-based previews are not supported.
+ if format_type not in
SUPPORTED_FORM_DATA_PREVIEW_FORMATS:
+ continue
+
+ preview_result = generate_preview_from_form_data(
+ form_data=new_form_data,
+ dataset_id=dataset.id,
+ preview_format=format_type,
+ )
+
+ if isinstance(preview_result, ChartError):
+ logger.warning(
+ "Preview '%s' failed: %s",
+ format_type,
+ preview_result.error,
+ )
+ else:
+ previews[format_type] = preview_result
+
Review Comment:
**Suggestion:** `generate_preview_from_form_data` returns Pydantic preview
models (`ASCIIPreview`/`TablePreview`/`VegaLitePreview`), but this tool returns
a raw `dict` response and stores those model instances directly. That can break
MCP/JSON serialization at runtime (or produce inconsistent wire payloads)
because `previews` may contain non-JSON-native objects. Serialize each preview
model (for example with `model_dump(mode="json")`) before inserting it into the
response map. [api mismatch]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ update_chart_preview fails when returning table/ascii previews.
- ❌ MCP clients may receive non-JSON-serializable preview objects.
- ⚠️ Behavior inconsistent with generate_chart Pydantic response handling.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. The MCP FastMCP server is created in `superset/mcp_service/app.py:25-29`
and exposes
the `update_chart_preview` tool (listed in `get_default_instructions()` at
`superset/mcp_service/app.py:67-77`), so external MCP clients can call it.
2. A client (mirroring `Client.call_tool("update_chart_preview", {"request":
...})` as in
`tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:169-172`)
sends a
request with `generate_preview=True` and `preview_formats=["table"]` and a
numeric
`dataset_id` that resolves to a real dataset, so the code in
`update_chart_preview()` at
`superset/mcp_service/chart/tool/update_chart_preview.py:117-151`
successfully loads the
dataset and passes validation.
3. Inside `update_chart_preview()`, the preview generation block at
`superset/mcp_service/chart/tool/update_chart_preview.py:237-253` iterates
`request.preview_formats`, sees `"table"` in
`SUPPORTED_FORM_DATA_PREVIEW_FORMATS`, and
calls `generate_preview_from_form_data(form_data=new_form_data,
dataset_id=dataset.id,
preview_format="table")` (lines 249-253). In
`superset/mcp_service/chart/preview_utils.py:65-79`,
`generate_preview_from_form_data()`
executes the query and, for `preview_format == "table"`, returns a
`TablePreview` Pydantic
model (`_generate_table_preview_from_data()` annotated to return
`TablePreview` at
`preview_utils.py:235-237`, which constructs a `TablePreview` instance at
`preview_utils.py:240-242` or `292-293`).
4. Back in `update_chart_preview()`, the `isinstance(preview_result,
ChartError)` check at
`update_chart_preview.py:255-259` fails (the result is a `TablePreview`, not
`ChartError`), so the `else` branch at line 263 executes and assigns
`previews["table"] =
preview_result`, where `preview_result` is a Pydantic `TablePreview` object.
The function
then builds a plain `dict` `result` and returns it directly at
`update_chart_preview.py:23-50` with `"previews": previews`. Because
`update_chart_preview()`'s return type is `Dict[str, Any]` and it is not
wrapped in a
Pydantic response model, the FastMCP tooling must JSON-serialize this plain
dict; with a
`TablePreview` instance stored under `previews["table"]`, standard JSON
encoding cannot
natively serialize the object, leading to runtime serialization failures or
inconsistent
wire payloads when the MCP server attempts to respond.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fupdate_chart_preview.py%0A%2A%2ALine%3A%2A%2A%20263%3A263%0A%2A%2AComment%3A%2A%2A%0A%09%2AApi%20Mismatch%3A%20%60generate_preview_from_form_data%60%20returns%20Pydantic%20preview%20models%20%28%60ASCIIPreview%60%2F%60TablePreview%60%2F%60VegaLitePreview%60%29%2C%20but%20this%20tool%20returns%20a%20raw%20%60dict%60%20response%20and%20stores%20those%20model%20instances%20directly.%20That%20can%20break%20MCP%2FJSON%20serialization%20at%20runtime%20%28or%20produce%20inconsistent%20wire%20payloads%29%20because%20%60previews%60%20may%20contain%20non-JSON-native%20objects.%20Serialize%20each%20preview%20model%20%28for%20example%20with%20%60model_dump%28mode%3D%22json%22%29%60%29%20before%20inserting%20it%20into%20the%20response%20map.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20is
sue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fupdate_chart_preview.py%0A%2A%2ALine%3A%2A%2A%20263%3A263%0A%2A%2AComment%3A%2A%2A%0A%09%2AApi%20Mismatch%3A%20%60generate_preview_from_form_data%60%20returns%20Pydantic%20preview%20models%20%28%60ASCIIPreview%60%2F%60TablePreview%60%2F%60VegaLitePreview%60%29%2C%20but%20this%20tool%20returns%20a%20raw%2
0%60dict%60%20response%20and%20stores%20those%20model%20instances%20directly.%20That%20can%20break%20MCP%2FJSON%20serialization%20at%20runtime%20%28or%20produce%20inconsistent%20wire%20payloads%29%20because%20%60previews%60%20may%20contain%20non-JSON-native%20objects.%20Serialize%20each%20preview%20model%20%28for%20example%20with%20%60model_dump%28mode%3D%22json%22%29%60%29%20before%20inserting%20it%20into%20the%20response%20map.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/mcp_service/chart/tool/update_chart_preview.py
**Line:** 263:263
**Comment:**
*Api Mismatch: `generate_preview_from_form_data` returns Pydantic
preview models (`ASCIIPreview`/`TablePreview`/`VegaLitePreview`), but this tool
returns a raw `dict` response and stores those model instances directly. That
can break MCP/JSON serialization at runtime (or produce inconsistent wire
payloads) because `previews` may contain non-JSON-native objects. Serialize
each preview model (for example with `model_dump(mode="json")`) before
inserting it into the response map.
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.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40077&comment_hash=65cca1c481aeabaa624dd63449138c8de4f294f3b23d7ba1638b6fdd1b4a73bb&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40077&comment_hash=65cca1c481aeabaa624dd63449138c8de4f294f3b23d7ba1638b6fdd1b4a73bb&reaction=dislike'>👎</a>
##########
tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:
##########
@@ -698,6 +698,74 @@ async def
test_preserves_previous_adhoc_filters_without_warning(
assert result["warnings"] == []
mock_get_previous_form_data.assert_called_once_with("valid_key_12345")
+ @patch.object(update_chart_preview_module, "validate_and_compile")
+ @patch.object(update_chart_preview_module, "has_dataset_access",
return_value=True)
+ @patch("superset.daos.dataset.DatasetDAO.find_by_id")
+
@patch("superset.mcp_service.chart.preview_utils.generate_preview_from_form_data")
Review Comment:
**Suggestion:** This patch target is incorrect for the code under test:
`update_chart_preview.py` imports `generate_preview_from_form_data` directly
into its module namespace, so patching
`superset.mcp_service.chart.preview_utils.generate_preview_from_form_data` does
not replace the function actually called by `update_chart_preview`. The test
can execute real preview generation instead of the mock, making it flaky and
potentially failing unexpectedly. Patch
`update_chart_preview_module.generate_preview_from_form_data` instead. [api
mismatch]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Unit test may hit real database/query stack.
- ❌ Assertions on preview content and mock calls unreliable.
- ⚠️ Harder to reason about failures in preview update tests.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. The test module imports the tool module once at import time via
`update_chart_preview_module =
importlib.import_module("superset.mcp_service.chart.tool.update_chart_preview")`
in
`tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:39-45`.
In that
module, `generate_preview_from_form_data` is imported into the module
namespace with `from
superset.mcp_service.chart.preview_utils import
generate_preview_from_form_data` at
`superset/mcp_service/chart/tool/update_chart_preview.py:42-46`, binding a
local name
inside `update_chart_preview_module`.
2. The test `test_returns_requested_table_preview` is decorated with
`@patch("superset.mcp_service.chart.preview_utils.generate_preview_from_form_data")`
at
`tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:52-61`
(line 55 in
the hunk). This patch changes the attribute
`generate_preview_from_form_data` on the
`superset.mcp_service.chart.preview_utils` module, but **does not** modify
the
already-imported
`update_chart_preview_module.generate_preview_from_form_data` reference
that `update_chart_preview()` actually calls.
3. When the test invokes
`update_chart_preview_module.update_chart_preview(request=request,
ctx=Mock())` at
`tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:108-110`,
the
function enters the preview block at
`superset/mcp_service/chart/tool/update_chart_preview.py:237-253` (because
`request.generate_preview=True` and `"table"` is present in
`request.preview_formats`). It
calls the unpatched local symbol `generate_preview_from_form_data`, which
still points to
the real implementation in
`superset/mcp_service/chart/preview_utils.py:65-79`, issuing
real `ChartDataCommand` queries and DB lookups instead of the intended mock.
4. As a result, the patched argument `mock_generate_preview_from_form_data`
passed into
the test (from the decorator at line 55) is never invoked, so assertions like
`mock_generate_preview_from_form_data.assert_called_once()` and
`result["previews"] ==
{"table": table_preview}` at
`tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py:112-118`
can fail or
become flaky depending on whether the real
`generate_preview_from_form_data()` hits a real
database, returns a `ChartError`, or raises an exception. The root cause is
that the patch
target string should be
`"update_chart_preview_module.generate_preview_from_form_data"` to
replace the symbol actually used by `update_chart_preview()`.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20tests%2Funit_tests%2Fmcp_service%2Fchart%2Ftool%2Ftest_update_chart_preview.py%0A%2A%2ALine%3A%2A%2A%20704%3A704%0A%2A%2AComment%3A%2A%2A%0A%09%2AApi%20Mismatch%3A%20This%20patch%20target%20is%20incorrect%20for%20the%20code%20under%20test%3A%20%60update_chart_preview.py%60%20imports%20%60generate_preview_from_form_data%60%20directly%20into%20its%20module%20namespace%2C%20so%20patching%20%60superset.mcp_service.chart.preview_utils.generate_preview_from_form_data%60%20does%20not%20replace%20the%20function%20actually%20called%20by%20%60update_chart_preview%60.%20The%20test%20can%20execute%20real%20preview%20generation%20instead%20of%20the%20mock%2C%20making%20it%20flaky%20and%20potentially%20failing%20unexpectedly.%20Patch%20%60update_chart_preview_module.generate_preview_from_form_data%60%20instead.%0A%0AValidate%20the%20correct
ness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20tests%2Funit_tests%2Fmcp_service%2Fchart%2Ftool%2Ftest_update_chart_preview.py%0A%2A%2ALine%3A%2A%2A%20704%3A704%0A%2A%2AComment%3A%2A%2A%0A%09%2AApi%20Mismatch%3A%20This%20patch%20target%20is%20incorrect%20for%20the%20code%20under%20test%3A%20%60update_chart_preview.py%60%20imports%20%60generate_preview_from_form
_data%60%20directly%20into%20its%20module%20namespace%2C%20so%20patching%20%60superset.mcp_service.chart.preview_utils.generate_preview_from_form_data%60%20does%20not%20replace%20the%20function%20actually%20called%20by%20%60update_chart_preview%60.%20The%20test%20can%20execute%20real%20preview%20generation%20instead%20of%20the%20mock%2C%20making%20it%20flaky%20and%20potentially%20failing%20unexpectedly.%20Patch%20%60update_chart_preview_module.generate_preview_from_form_data%60%20instead.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%2
0implement%20a%20minimal%20fix%0A)
*(Use Cmd/Ctrl + Click for best experience)*
<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/tool/test_update_chart_preview.py
**Line:** 704:704
**Comment:**
*Api Mismatch: This patch target is incorrect for the code under test:
`update_chart_preview.py` imports `generate_preview_from_form_data` directly
into its module namespace, so patching
`superset.mcp_service.chart.preview_utils.generate_preview_from_form_data` does
not replace the function actually called by `update_chart_preview`. The test
can execute real preview generation instead of the mock, making it flaky and
potentially failing unexpectedly. Patch
`update_chart_preview_module.generate_preview_from_form_data` 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.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40077&comment_hash=6247b701e49bbf5cd683c631340214eaa610c65e8fececdc4c881d66eefb2649&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40077&comment_hash=6247b701e49bbf5cd683c631340214eaa610c65e8fececdc4c881d66eefb2649&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]