Skip to content

feat(mcp): add typed Sunburst chart support - #43771

Merged
aminghadersohi merged 87 commits into
apache:masterfrom
aminghadersohi:sc-119162-mcp-sunburst
Oct 9, 2026
Merged

aminghadersohi merged 87 commits into
apache:masterfrom
aminghadersohi:sc-119162-mcp-sunburst

Conversation

@aminghadersohi

@aminghadersohi aminghadersohi commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

SUMMARY

Adds complete typed MCP support for the frontend ECharts Sunburst plugin using the exact sunburst_v2 viz tag and the typed chart_type="sunburst" discriminator.

  • Registers ordered hierarchy, saved/SIMPLE/SQL primary and secondary metrics, filters/time controls, ordering/limits, presentation controls, schema discovery, previews, and recommendation metadata. A supplied secondary metric drives sequential coloring through its ratio to the primary metric; omitting it uses categorical colors.

  • Preserves native/plugin presentation controls on same-viz updates while replacing every target-owned query-role alias from the chart plugin registry before overlay. This removes stale singular/plural, raw/aggregate, primary/secondary, pivot, series, and x-axis roles across every enabled registered native viz alias and table/Handlebars query mode.

  • Treats an explicit null temporal range, column, or grain as an atomic clear across top-level range/granularity/grain keys, adhoc filters, top-level legacy filters/extra_filters, and nested extra_form_data filters while retaining unrelated predicates.

  • Seeds g.form_data with set_query_context_form_data immediately before ChartDataCommand.run() for saved ASCII, table, and Vega-Lite previews, so virtual-dataset url_param, filter_values, and get_filters Jinja macros receive the saved query fields.

  • Retains strict first-query result handling, operation-owned chart/datasource identity, exact/unique-casefold namespace resolution, native WHERE semantics, finite numeric Sunburst result validation, and programmatic query-context seeding for all other compile/preview paths.

  • Normalizes SQL NULL Sunburst metrics to frontend zero in compile, preview, and data/export paths, while retaining strict field/alias and finite-numeric checks.

  • Accepts the exact Superset CACHE_DISABLED_TIMEOUT = -1 result metadata sentinel.

Maintainer coordination

  • Completed a finite maintainer pass against all live review submissions, issue comments, and review threads on September 10.
  • Reconciled the latest master changes while retaining the complete Sunburst update pipeline, Gauge preview support, Gauge descending sort_by_metric behavior, and shared MCP update semantics.
  • The live review snapshot contains 20 threads, all resolved. No new actionable feedback was added after the preceding pass, so no additional review replies or thread-state changes were necessary.
  • PR remains open, non-draft, mergeable, and ready for review; review approval is the only remaining gate.

Scope and review map

A file-by-file audit separated the original 77-file diff into four groups:

Group Files Added/removed lines before extraction Review focus
Sunburst-only implementation/tests 3 +5,866 / -0 plugin, result normalization, and exhaustive Sunburst regressions
Mixed Sunburst/shared chart surfaces 30 +7,651 / -2,185 schemas, registry, compile/preview/data/update paths; these contain both the new chart adapter and shared behavior it exercises
Shared MCP foundations/tests 33 +10,016 / -611 typed query envelopes, response preflight, canonical form-data/query contracts, dataset validation, and shared tool behavior required by the Sunburst paths
Clearly incidental 11 +249 / -32 dashboard Excel pagination, strict DataFrame JSON projection, and a CI timeout adjustment

The independently testable incidental work is being separated without rewriting this ready PR:

  1. #44218 contains the dashboard Excel pagination fix. Its three files have been removed from this PR.
  2. #44219 contains strict DataFrame/non-finite JSON projection. It is independent and should land before this PR; after it lands, a normal merge of master will remove those six duplicated files here. Removing them before the dependency lands causes 29 focused query-result/get-data regressions, so this PR retains them temporarily rather than becoming red.
  3. The unrelated Python-unit timeout edit was dropped rather than moved.
  4. The remaining 63 Sunburst/mixed/shared files are interdependent at the public compile, preview, update, and query-result boundaries. Splitting them mechanically before their foundations land would either duplicate the same code or leave this PR untestable. Review can proceed in the table order above: Sunburst-only adapter, mixed chart entry points, then shared contract modules. Further shared extraction should follow the same land-first/normal-merge pattern; no history rewrite or force-push is needed.

Landing order: #44218 and #44219 first (independent), then #43771. Current master has been integrated into #43771 with a normal merge commit; the duplicated #44219 files remain until that dependency lands.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Screenshots

Sunburst created by the MCP generate_chart tool and opened in Explore: hierarchy territory -> country -> product_line, primary metric SUM(sales). The native Sunburst controls are populated from the MCP config.

secondary_metric (SUM(quantity_ordered)) over the primary metric drives the sequential colour scale; omitting it gives categorical colours.

The rendered sunburst_v2 panel, showing the three hierarchy rings and the total.

Captured at 5b0df699. Captured on a local dev env (docker-compose-light) against the Superset examples dataset cleaned_sales_data; both charts were created through the MCP generate_chart tool.

No frontend component changes. MCP gains typed Sunburst support and frontend-faithful NULL aggregate behavior.

TESTING INSTRUCTIONS

Python 3.11, with the repository and superset-core/src on PYTHONPATH:

pytest -q tests/unit_tests/mcp_service/chart/test_query_result.py \
  tests/unit_tests/mcp_service/chart/test_preview_utils.py \
  tests/unit_tests/tasks/test_export_dashboard_excel.py \
  tests/unit_tests/mcp_service/utils/test_response_utils.py \
  tests/unit_tests/mcp_service/chart/test_sunburst_chart.py \
  tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
# 845 passed

pytest -q tests/unit_tests/mcp_service tests/unit_tests/common \
  tests/unit_tests/dataframe_test.py tests/unit_tests/tasks/test_export_dashboard_excel.py
# 5,040 passed

pre-commit run
pre-commit run --files $(git diff --name-only --diff-filter=ACMR origin/master...HEAD)
# Both pass, including MyPy, Ruff, Pylint and applicable workflow checks.

git diff --check
# Passed

Regressions cover UTC/named/static pytz zones, both DST-fold occurrences and nanoseconds; short/default/tall Sunburst canvases, omitted-row accounting, wide/combining Unicode and clipping markers; aggregate/raw paginated Table export rebuilds without page-size truncation/count sheets; and distinct bounded Decimal fraction identities. Existing NULL compile/preview/data/export tests remain passing.

Exact-head CI: head fb3e2c40d798223d3910fde661cb93c0ccb83717 is mergeable. Focused Gauge, Sunburst, and chart-data tests pass (656 passed, 1 skipped), and merge-conflict pre-commit passes. Integration/E2E checks are blocked by the two migration heads present on current master (c7f53d184ea2 and 88a01c781622).

All 21 live review threads are resolved. The scope/reviewability request is addressed with two companion PRs, removal of the Excel and unrelated CI-timeout diffs from this branch, and the evidence-backed review/dependency map above. The PR is OPEN / non-draft / MERGEABLE, with REVIEW_REQUIRED plus the upstream migration-head CI blocker. Local, tracking, fork, and live PR heads match; the worktree is clean.

Local HTTP health is unavailable, so browser/manual runtime testing is not claimed.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@bito-code-review

bito-code-review Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #eec59f

Actionable Suggestions - 0
Additional Suggestions - 6
  • superset/mcp_service/chart/chart_utils.py - 2
    • Broad merge changes all chart updates · Line 1124-1128
      `merge_form_data_for_update` is called for every chart type in `update_chart_preview.py`, but the non-Sunburst branch returns `{**existing_form_data, **new_form_data}`, retaining all prior keys. Previously the preview only preserved specific keys via `merge_table_column_config`/`merge_interactive_pivot_ui_config`. This now keeps stale keys (e.g. removed `groupby`/metrics) on any non-Sunburst update. Consider returning `new_form_data` for non-Sunburst configs.
    • Missing tests for new branch · Line 1882-1886
      The new `SunburstChartConfig` branch in `analyze_chart_semantics` has no test coverage, unlike the big_number/handlebars/pivot branches which have dedicated tests. Per BITO.md rule [11730], add unit tests asserting `primary_insight`, the `data_story` including hierarchy names/metric, and the >3-column ellipsis path.
  • superset/mcp_service/chart/tool/update_chart_preview.py - 1
    • Unconditional merge changes all charts · Line 248-250
      `merge_form_data_for_update` is called for every chart type, but its non-Sunburst path (chart_utils.py:1125-1128) returns a blanket `{**existing, **new}` merge. This now retains stale keys from the previous cached form_data (e.g. `time_range`, `granularity_sqla`) that the mapper omits when the new config leaves them unset (chart_utils.py:1076-1078). Previously only `column_config`/`pivot_table_state`/`adhoc_filters` were preserved. Consider restricting the merge to Sunburst same-viz updates.
  • superset/mcp_service/chart/schemas.py - 1
    • SQL metric round-trip fails · Line 1178-1183
      In `_coerce_native_metric`, a native SQL adhoc metric with `hasCustomLabel: false` yields `label=None`, but `ColumnRef` raises "sql_expression requires a 'label'" (line 786). Round-tripping such a saved metric therefore fails validation. Fall back to `sqlExpression` when `label` is None.
  • superset/mcp_service/chart/plugins/sunburst.py - 2
    • Unconditional canonicalization crash · Line 106-109
      `hierarchy` is `List[ColumnRef]`, and `ColumnRef` permits `sql_expression` with `name=None`. Calling `get_canonical_column_name(dimension["name"], ...)` unconditionally would pass `None` into `.lower()` and raise `AttributeError`. The sibling `pie.py` guards with `if not dim.get("sql_expression") and not dim.get("saved_metric")`; mirror that guard here for consistency.
    • Dynamically typed Any disallowed · Line 73-73
      `Any` is used in `config` parameters across `extract_column_refs`, `to_form_data`, `generate_name`, `resolve_viz_type`, and `normalize_column_refs` (ANN401). Replace with specific types like `SunburstChartConfig` or `object` where narrowing applies.
Review Details
  • Files reviewed - 17 · Commit Range: fb0a0e3..fb0a0e3
    • superset/common/form_data_query_context.py
    • superset/mcp_service/app.py
    • superset/mcp_service/chart/chart_helpers.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/compile.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/sunburst.py
    • superset/mcp_service/chart/preview_utils.py
    • superset/mcp_service/chart/resources/chart_configs.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • superset/mcp_service/chart/validation/runtime/chart_type_suggester.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/mcp_service/chart/schemas.py
Comment thread superset/mcp_service/chart/tool/update_chart_preview.py
Comment thread superset/mcp_service/chart/chart_utils.py
@codecov

codecov Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.37548% with 782 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.77%. Comparing base (489a02e) to head (72ddec0).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/chart/query_result.py 74.13% 177 Missing and 106 partials ⚠️
superset/mcp_service/chart/schemas.py 84.63% 55 Missing and 49 partials ⚠️
superset/mcp_service/chart/sunburst.py 63.41% 54 Missing and 21 partials ⚠️
superset/common/form_data_query_context.py 91.17% 31 Missing and 24 partials ⚠️
superset/mcp_service/chart/tool/get_chart_data.py 80.12% 28 Missing and 5 partials ⚠️
superset/mcp_service/chart/chart_helpers.py 84.57% 11 Missing and 20 partials ⚠️
superset/mcp_service/chart/preview_utils.py 82.18% 17 Missing and 14 partials ⚠️
superset/mcp_service/chart/tool/get_chart_sql.py 66.30% 24 Missing and 7 partials ⚠️
superset/mcp_service/chart/plugins/sunburst.py 77.55% 18 Missing and 4 partials ⚠️
superset/mcp_service/utils/response_utils.py 89.63% 9 Missing and 8 partials ⚠️
... and 14 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #43771      +/-   ##
==========================================
+ Coverage   82.74%   82.77%   +0.02%     
==========================================
  Files        3013     3016       +3     
  Lines      188491   192300    +3809     
  Branches    43761    44731     +970     
==========================================
+ Hits       155963   159169    +3206     
- Misses      29758    30098     +340     
- Partials     2770     3033     +263     
Flag Coverage Δ
hive 35.38% <14.76%> (-0.77%) ⬇️
mysql 53.79% <17.26%> (-1.40%) ⬇️
postgres 53.80% <17.26%> (-1.40%) ⬇️
presto 37.17% <14.76%> (-0.84%) ⬇️
python 86.46% <82.37%> (-0.09%) ⬇️
sqlite 53.54% <17.26%> (-1.39%) ⬇️
unit 80.05% <82.33%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@netlify

netlify Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 72ddec0
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ac85cba5faa280008adc391
😎 Deploy Preview https://deploy-preview-43771--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review

bito-code-review Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #d98b39

Actionable Suggestions - 0
Additional Suggestions - 9
  • superset/mcp_service/chart/chart_utils.py - 1
    • Orphan grain not rejected · Line 1352-1355
      The comment says the final-form-data validator rejects orphan grains, but `_validate_sunburst_temporal_subject` in `compile.py` returns early for any `viz_type != "sunburst_v2"`. Non-sunburst configs (`BigNumberChartConfig`, `interactive_pivot`, `waterfall`) also carry `time_grain`, so an orphan `time_grain_sqla` set at lines 1346-1350 is now neither popped nor rejected and reaches the query builder. Consider extending the validator or keeping the pop for non-sunburst types.
  • superset/mcp_service/chart/schemas.py - 1
    • Strict model rejects saved columns · Line 1088-1122
      `SunburstNativeMetricColumn` inherits `UnknownFieldCheckMixin`, whose `check_unknown_fields` validator raises `ValueError` on any undeclared field, defeating the `extra="ignore"` config. It is used in `_coerce_native_metric` (line 1355) while reading *saved* Sunburst form_data, where real frontend `ColumnMeta` objects carry many fields not declared here (`is_certified`, `certified_by`, `extra`, `warnings`, `is_physical`, ...). Such saved charts would fail to load. Consider a plain `BaseModel` with `extra="ignore"` for this saved-data path.
  • superset/mcp_service/chart/sunburst.py - 1
    • Unhandled exception on ambiguity · Line 246-246
      `DatasetValidator.get_canonical_column_name` raises on ambiguous (case-folded) column matches, but `normalize_sunburst_form_data_references` calls it (and `get_canonical_metric_name`) without try/except. The caller `update_chart_preview` also has no handler, so an ambiguous reference in form_data would propagate as an unhandled exception (500) instead of a clean `ChartError`. Consider catching and returning a validation error.
  • superset/mcp_service/chart/preview_utils.py - 1
    • Datasource precedence override · Line 94-94
      `resolve_form_data_datasource` (chart_helpers.py:686) prefers `form_data.get("datasource_id")` over the `datasource` string set here. If `form_data` already carries a `datasource_id` (e.g. merged from a saved chart's params in `update_chart_preview.py`), the preview queries that datasource instead of the validated `dataset_id` param, silently ignoring the explicit dataset. Consider clearing `datasource_id`/`datasource_type` before setting `datasource`.
  • superset/mcp_service/chart/tool/get_chart_preview.py - 1
    • Sunburst ignores ascii dimensions · Line 277-277
      For `sunburst_v2`, `_generate_ascii_preview_from_data` hardcodes `width=80, height=20` (preview_utils.py:153), so the returned `ASCIIPreview` metadata ignores the caller's `self.request.ascii_width`/`ascii_height`. The non-sunburst branch (lines 288-289) honors them. Consider threading the requested dimensions through so both paths behave consistently.
  • superset/mcp_service/chart/chart_helpers.py - 1
    • Validation coverage gap · Line 608-608
      Move the `_validate_sunburst_simple_filter_clauses(form_data, viz_type)` call to immediately after `prepare_form_data_for_query(...)` so that legacy `having`/`filters` and `extra_form_data` are also validated.
  • superset/mcp_service/chart/tool/generate_chart.py - 1
    • Misleading cache comment · Line 672-674
      The comment claims "Cache only a chart state that passed its compile checks," but the compile check is gated on `if numeric_dataset_id is not None:` (line 625). When the dataset is missing or the user lacks access, `_compile_chart` is skipped yet `generate_explore_link` still caches `form_data`. Consider gating the cache on compile success or adjusting the comment to match the conditional behavior.
  • superset/mcp_service/chart/query_result.py - 1
    • Unreachable defensive branches · Line 112-116
      Both defensive branches are unreachable: `query_result_failure()` (line 110) already returns a `ChartError` for a non-`Mapping` result and for any non-`Mapping` query in the `queries` list. Lines 112-116 and 124-128 can never execute. Consider removing them to avoid dead code; the empty-`queries` check at line 118 remains reachable and should be kept.
  • superset/common/form_data_query_context.py - 1
    • Clause validation regression · Line 78-80
      The old code used `(flt.get("clause") or "WHERE").upper()`, tolerating lowercase and `None` clause values. The new strict `isinstance`/set check now raises `ValueError` for a lowercase `"where"` or a `None` clause in stored form_data on the export path (`where_only=True`). Consider normalizing with `.upper()` before validating to avoid a regression for legacy charts.
Review Details
  • Files reviewed - 23 · Commit Range: fb0a0e3..a609fb8
    • superset/common/form_data_query_context.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/compile.py
    • superset/mcp_service/chart/plugins/sunburst.py
    • superset/mcp_service/chart/preview_utils.py
    • superset/mcp_service/chart/query_result.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/sunburst.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • superset/mcp_service/chart/validation/dataset_validator.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py
    • tests/unit_tests/mcp_service/chart/validation/test_dataset_validator.py
    • superset/mcp_service/chart/chart_helpers.py
    • superset/mcp_service/chart/plugins/histogram.py
    • tests/unit_tests/common/test_form_data_query_context.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #3f2309

Actionable Suggestions - 0
Additional Suggestions - 15
  • superset/mcp_service/chart/tool/update_chart.py - 1
    • Stale column config on rebind · Line 275-278
      On a dataset rebind, `merge_table_column_config`/`merge_interactive_pivot_ui_config` (lines 265-266) copy the old dataset's `column_config`/`pivot_table_state` into `new_form_data` before `_merge_replacement_config` triggers `scrub_dataset_bound_form_data`. Since both keys are in `_DATASET_BOUND_FORM_DATA_KEYS`, the scrub is meant to drop them, but `merged.update(new_form_data)` re-adds the stale values. Guard the merge helpers with `if not dataset_rebind` (same applies to the preview path at lines 374-375).
  • superset/mcp_service/chart/tool/update_chart_preview.py - 1
    • Stale dataset config on rebind · Line 251-265
      When `dataset_rebind` is True, `merge_form_data_for_update` scrubs dataset-bound keys via `scrub_dataset_bound_form_data`, but `merge_table_column_config`/`merge_interactive_pivot_ui_config` run first and re-inject `column_config`/`pivot_table_state` from the previous dataset into `new_form_data`, which then overrides the scrubbed base. Stale column config leaks into the rebound preview. Compute `dataset_rebind` first and skip these merges when rebinding.
  • superset/common/form_data_query_context.py - 2
    • Orderby parse raises on discarded result · Line 144-145
      `query_fields_from_form_data` raises `ValueError` on malformed orderby JSON, but `columns_from_form_data` (line 252) and `_columns_and_metrics` (line 354) call it and discard the orderby result. A saved chart carrying a stale/malformed `order_by_cols` would now crash where it previously ran. `orderby_from_form_data` already drops such entries leniently; mirror that with `continue`.
    • Duplicated x_axis logic · Line 362-369
      The new `x_axis` block duplicates the identical logic already in `columns_from_form_data` (lines 254-260). Both are live query-building paths: `columns_from_form_data` feeds the MCP preview (`preview_utils.py`) and `_columns_and_metrics` feeds dashboard export. A future fix to one handler would silently diverge the other. Consider calling `columns_from_form_data` here to keep a single source of truth.
  • superset/mcp_service/chart/chart_utils.py - 1
    • Rebind leaks old-dataset columns · Line 1559-1560
      `scrub_dataset_bound_form_data` only cleans `existing_form_data`, but in `update_chart.py` the callers `merge_table_column_config`/`merge_interactive_pivot_ui_config` already copy dataset-bound keys (`column_config`, `conditional_formatting`, `pivot_table_state`) from the old dataset into `new_form_data` before this runs. On rebind those stale column references survive into the new dataset's form data, defeating the scrub. Guard the merge helpers with the same `dataset_rebind` flag or scrub `new_form_data` too.
  • superset/mcp_service/chart/schemas.py - 1
    • Temporal binding lost on None granularity · Line 1442-1443
      When native form data has `granularity_sqla: None` (set by `chart_utils.py` for non-temporal columns) plus a `TEMPORAL_RANGE` filter, the new key-presence guard blocks the filter-subject fallback, and line 1510 then sets `temporal_column = None`. The old `data.setdefault("temporal_column", native_filter.get("subject"))` preserved the binding. Use `not data.get("granularity_sqla")` so a None value still falls back to the filter subject.
  • superset/mcp_service/chart/plugin.py - 1
    • Dropped legacy query role key · Line 52-63
      The refactor derives QUERY_ROLE_KEYS from SHARED_FORM_DATA_QUERY_ROLE_KEYS plus registered roles, which drops the legacy "entity" key the old frozenset contained. `resolve_groupby()` (chart_helpers.py:495) still reads `entity` as a fallback groupby, and `_DATASET_BOUND_FORM_DATA_KEYS` doesn't cover it, so a stale `entity` from a prior viz survives `merge_form_data_for_update` and can leak into the query. Consider restoring it.
  • superset/mcp_service/chart/chart_helpers.py - 1
    • Duplicated pop-None loop · Line 90-92
      The 3-line pop-None loop is duplicated in `canonicalize_operation_form_data` (90-92) and `prepare_form_data_for_query` (199-201), and an identical loop already exists in `chart_utils.py:1649`. The key set is centralized in `MAPPING_ENVELOPE_KEYS`, but the loop body is repeated, so a future change to sentinel-removal semantics must be applied in three places. Consider a shared helper.
  • superset/mcp_service/chart/plugins/table.py - 1
    • Redundant no-op union · Line 45-45
      `percent_metrics` is already in `BaseChartPlugin.query_role_keys` (it is part of `_REGISTERED_PRIMARY_QUERY_ROLE_KEYS` in plugin.py:53, which feeds `QUERY_ROLE_KEYS`). This union is a no-op and misleadingly implies the base set lacks it. Assign `BaseChartPlugin.query_role_keys` directly or remove the override.
  • superset/mcp_service/chart/plugins/xy.py - 1
    • Redundant no-op union · Line 56-56
      This union is a no-op: `x_axis` is already in `BaseChartPlugin.query_role_keys` via `_REGISTERED_PRIMARY_QUERY_ROLE_KEYS` (plugin.py:53), so `query_role_keys` never changes. It misleads readers into thinking the XY plugin contributes a role that is already globally registered. Remove the line, or add a comment if documenting ownership is the goal.
  • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py - 1
    • Dead dispatch branch · Line 609-613
      The new `isinstance(config, InteractivePivotChartConfig)` branch is unreachable: `InteractivePivotChartConfig` is not in this test's parametrize list (lines 581-601), so `map_interactive_pivot_config` is never called here. The interactive-pivot path of `merge_form_data_for_update` goes untested. Add an `InteractivePivotChartConfig` case (as in `test_explicit_sparse_controls_replace_same_viz_preservation`) to cover it.
  • superset/mcp_service/chart/plugins/mixed_timeseries.py - 1
    • Redundant no-op assignment · Line 44-44
      This assignment is a no-op: `MixedTimeseriesChartPlugin` already inherits `query_role_keys` from `BaseChartPlugin` (which equals `QUERY_ROLE_KEYS`), and unlike sibling plugins (`table`, `waterfall`, `xy`, `histogram`) it adds no extra keys via `| {...}`. The line is misleading and can be dropped.
  • superset/mcp_service/chart/plugins/waterfall.py - 1
    • Redundant query role union · Line 44-44
      `x_axis` is already in `BaseChartPlugin.query_role_keys` (plugin.py `_REGISTERED_PRIMARY_QUERY_ROLE_KEYS` includes it), so `| {"x_axis"}` is a no-op. Keeping it implies the base set lacks `x_axis`, which can mislead future maintainers. Consider removing the line for clarity.
  • tests/unit_tests/common/test_form_data_query_context.py - 1
    • Strengthen bucket assertions · Line 46-48
      The parametrized test only asserts the single target bucket, so it can't detect an alias value leaking into another bucket (e.g. a metric also appearing in `columns`). Assert the full `(columns, metrics, orderby)` tuple with the non-target buckets expected empty. Also `value` is always a string literal, so annotate it `str` rather than `object`.
  • superset/mcp_service/chart/plugins/histogram.py - 1
    • Redundant query_role_keys union · Line 46-46
      `BaseChartPlugin.query_role_keys` already contains "column" (plugin.py:52-63 `_REGISTERED_PRIMARY_QUERY_ROLE_KEYS`), so this union is a no-op. It misleads readers into thinking the plugin adds a role that is already shared. Drop the override or add a clarifying comment.
Review Details
  • Files reviewed - 32 · Commit Range: a609fb8..893bae9
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/compile.py
    • superset/mcp_service/chart/preview_utils.py
    • superset/mcp_service/chart/sunburst.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
    • superset/mcp_service/chart/chart_helpers.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/test_preview_utils.py
    • superset/mcp_service/chart/plugin.py
    • superset/mcp_service/chart/registry.py
    • tests/unit_tests/mcp_service/chart/test_registry.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • superset/common/form_data_query_context.py
    • superset/mcp_service/chart/plugins/big_number.py
    • superset/mcp_service/chart/plugins/box_plot.py
    • superset/mcp_service/chart/plugins/handlebars.py
    • superset/mcp_service/chart/plugins/histogram.py
    • superset/mcp_service/chart/plugins/interactive_pivot.py
    • superset/mcp_service/chart/plugins/mixed_timeseries.py
    • superset/mcp_service/chart/plugins/pie.py
    • superset/mcp_service/chart/plugins/pivot_table.py
    • superset/mcp_service/chart/plugins/table.py
    • superset/mcp_service/chart/plugins/waterfall.py
    • superset/mcp_service/chart/plugins/xy.py
    • tests/unit_tests/common/test_form_data_query_context.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #07c451

Actionable Suggestions - 0
Additional Suggestions - 17
  • superset/mcp_service/chart/chart_helpers.py - 4
    • Deck orderby regression · Line 886-886
      The deleted block set `qd["orderby"] = [(deck_metrics[0], not order_desc)]` to mirror `BaseDeckGLViz.query_obj()`. The new `_deck_query_adapter` branches (arc/screengrid/etc.) set `columns`/`metrics`/`filters`/`is_timeseries` but never `orderby`, so deck.gl charts lose the default sort by first metric descending. Verify and restore this ordering.
    • Numeric string treated as metric · Line 402-403
      `_is_deck_metric_value` returns True for any non-empty string, so numeric strings like `point_radius_fixed="100"` (deck_scatter, line 658) and `line_width="5"` (deck_path, line 590) are wrongly added to `metrics`/`orderby`. The legacy `_is_metric_ref` excluded numeric strings via `float()`, and `test_resolve_deck_gl_metrics_numeric_point_radius_fixed_excluded` expects that. Mirror `_is_metric_ref` here.
    • Dead deck helpers remain · Line 886-886
      This diff replaced the old deck query assembly with `_deck_query_adapter`, removing the only production call sites of `_resolve_deck_gl_metrics`, `_deck_gl_null_filters`, and `resolve_deck_gl_columns`. They are now dead in production (only referenced by tests). Consider removing them or marking them test-only to avoid divergence risk.
    • Too many branches and statements · Line 496-496
      `_deck_query_adapter` has 32 branches and 102 statements, exceeding the configured limits (12 and 50). Extract per-viz-type logic (geojson, polygon, path, arc, scatter) into separate helper functions to reduce complexity.
  • superset/mcp_service/chart/tool/get_chart_data.py - 2
    • Empty result rejected as error · Line 789-789
      `validate_query_result_envelope` defaults to `none_as_empty=False`, so a legitimate empty result (`data: None`) for a generic saved chart is rejected as `InvalidQueryResult` before reaching the graceful `EmptyQuery` path below. `get_chart_preview.py` passes `none_as_empty=self.chart.viz_type != "sunburst_v2"` for this reason. Consider passing `none_as_empty=True` here to preserve legacy empty-result behavior.
    • Empty result rejected as error · Line 1155-1155
      Same as line 789: the unsaved-chart path also calls `validate_query_result_envelope` with the default `none_as_empty=False`, so `data: None` is rejected as `InvalidQueryResult` before the `EmptyQuery` branch at line 1171. Pass `none_as_empty=True` for consistency with `get_chart_preview.py`.
  • superset/common/form_data_query_context.py - 3
    • Inherit offset divergence · Line 1416-1417
      `_table_time_offsets` appends the literal `"inherit"` token when `time_compare` contains `"inherit"` but no inherited value is supplied via `extra_form_data.time_compare`. The frontend `buildQuery` only incorporates the inherited shift when `extra_form_data.time_compare` exists, so this yields a spurious `compare` operator and `__inherit`-suffixed labels the frontend would not generate. Guard the append on `extra_form_data.time_compare`.
    • Secondary query regression risk · Line 1478-1485
      This removes the guard that emptied `secondary["metrics"]`/`secondary["groupby"]` when `metrics_b`/`groupby_b` are absent, which the deleted comment says prevented query A from executing twice for older saved charts. If `_finalize_query_objects` doesn't replicate that, the double-execution regression returns. Please confirm the new path preserves the empty-secondary contract.
    • Duplicated BASE_AXIS dict · Line 635-654
      `_box_temporalized_columns` re-inlines the same BASE_AXIS dict (`timeGrain`/`columnType`/`sqlExpression`/`label`/`expressionType`) already built in `_temporalized_columns`. If the pivot/box temporal-column contract changes, the two copies can diverge. Consider extracting a shared `_temporal_column_dict(time_grain, column)` helper and calling it from both functions.
  • superset/mcp_service/chart/query_result.py - 3
    • Rejects valid duplicate colnames · Line 270-270
      This new check rejects valid results: `QueryContextProcessor.get_data` renames columns via `verbose_map` (query_context_processor.py:411), which can collapse two columns onto the same label (see excel.py:64-66), and `extract_dataframe_dtypes` explicitly supports duplicate columns. The consumer `get_chart_data.py` iterates `raw_columns` by index, so duplicates are handled. This would return `InvalidQueryResult` for legitimate charts instead of data.
    • Duplicate colnames regression · Line 316-316
      Routing `first_query_data` through `validate_query_result_envelope` now rejects results whose `colnames` contain duplicates (`len(set(colnames)) != len(colnames)`). The pipeline produces `colnames = list(processed_df.columns)` (client_processing.py:1377), which can contain duplicate names — `extract_dataframe_dtypes` and its unit test explicitly support this. Previews that previously returned data now fail with "malformed column metadata". Consider relaxing the uniqueness check.
    • Too many branches · Line 164-164
      Function has too many branches (25 > 12). Refactor to reduce branches or add a noqa comment.
  • superset/mcp_service/chart/schemas.py - 3
    • Dead always-failing SQL branch · Line 3018-3022
      This branch sets `config["x"] = {"sql_expression": ...}`, but `XYChartConfig.reject_sql_expression_on_dimensions` calls `_reject_sql_expression_on_dimension(self.x, "x")`, which raises `ValueError` for any dimension carrying `sql_expression`. So this path can never produce a valid chart — it always errors. Drop the branch or raise a clear error instead.
    • Cross-class helper coupling · Line 2521-2521
      `coerce_y_column_names` reuses `SunburstChartConfig._coerce_native_metric`, a private Sunburst method whose errors read "Sunburst native metric …" (lines 1334/1376/1378) and which validates via `SunburstNativeMetricColumn`. An XY user with an invalid native metric gets a confusing Sunburst-specific message. Consider a shared chart-agnostic helper with neutral wording.
    • Function has too many branches · Line 2919-2919
      `_normalize_chart_request_input` has 23 branches (limit 12). Consider refactoring into smaller helper functions. This also addresses PLR0915 at the same line.
  • superset/mcp_service/chart/plugin.py - 1
    • Phantom _b role keys · Line 71-75
      The `_b` derivation from `_REGISTERED_PRIMARY_QUERY_ROLE_KEYS` yields 15 phantom keys (`column_b`, `entity_b`, `groupbyColumns_b`, `groupbyRows_b`, `percent_metrics_b`, `x_axis_b`, `metric_b`, `x_b`, `y_b`, `size_b`, `series_b`, ...) that are absent from the authoritative `MIXED_TIMESERIES_SECONDARY_QUERY_KEYS`. The comment claims this prevents vocabulary drift, but the derived set doesn't match the real secondary vocabulary. These dead keys inflate `QUERY_ROLE_KEYS` and are stripped by `query_role_keys_for_viz_type` during same-viz replacement in `chart_utils.py`. Consider deriving only from shared keys with real `_b` counterparts, or dropping the derivation.
  • tests/unit_tests/mcp_service/chart/test_round10_query_contracts.py - 1
    • Duplicated BASE_AXIS literal · Line 193-199
      Consider extracting a module-level `_base_axis_column(name: str) -> dict` helper and using it in both the primary and mixed_timeseries assertions to centralize the BASE_AXIS dict literal and prevent divergence if the contract changes.
Review Details
  • Files reviewed - 21 · Commit Range: 893bae9..efb6961
    • superset/common/form_data_query_context.py
    • superset/mcp_service/chart/chart_helpers.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugin.py
    • superset/mcp_service/chart/schemas.py
    • tests/unit_tests/mcp_service/chart/test_round10_query_contracts.py
    • superset/charts/data/form_data.py
    • superset/mcp_service/chart/query_result.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • tests/unit_tests/common/test_form_data_query_context.py
    • tests/unit_tests/mcp_service/chart/test_chart_helpers.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_round11_query_contracts.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • superset/mcp_service/chart/compile.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/test_preview_utils.py
    • tests/unit_tests/mcp_service/chart/test_round12_query_contracts.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #82b6e5

Actionable Suggestions - 0
Additional Suggestions - 6
  • superset/mcp_service/chart/query_result.py - 1
    • NaN rejected in float bound · Line 110-110
      `math.isfinite(value)` rejects `float('nan')`, but the JSON result path (`query_context_processor` → `df.to_dict(orient="records")`) emits NaN for NULL numeric cells, which the old code accepted. Any chart with a missing numeric value will now fail `validate_query_result_envelope`. Consider allowing NaN (e.g. `math.isnan(value) or math.isfinite(value)`).
  • superset/mcp_service/chart/tool/update_chart.py - 1
    • Redundant live DB compile · Line 860-866
      The removed `run_compile_check=False` (previously passed for dataset-only updates) is now gone, so `_validate_update_against_dataset` uses its default `True` and runs a live DB query via `validate_and_compile`/`ChartDataCommand`. For idempotent same-dataset updates `final_form_data` is the unchanged saved state, so this is redundant work on a plausible path. Pass `run_compile_check=_is_dataset_rebind(request, chart)`.
  • superset/mcp_service/chart/tool/get_chart_data.py - 1
    • dict key order inflates unique_count · Line 195-195
      `_canonical_profile_key` builds the dict key from `value.items()` in insertion order, so equal dicts with different key order (e.g. `{"a":1,"b":2}` vs `{"b":2,"a":1}`) yield different keys and inflate `unique_count`. Sort items by key before canonicalizing. The nested-dict test path makes this reachable.
  • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py - 1
    • Vacuous test assertion · Line 2525-2525
      `mock_validate.call_args.kwargs.get("run_compile_check", True)` is vacuous: the dataset-only call at `update_chart.py:861-866` never passes `run_compile_check`, so `.get(..., True)` always returns the default and the assertion passes regardless of behavior. Assert the effective default (`is not False`) or the absence of the kwarg so a regression that disables the compile check is caught.
  • superset/mcp_service/chart/preview_utils.py - 1
    • Depth guard mismatch · Line 68-68
      `_is_bounded_result_value` accepts containers up to depth 6 (`depth > MAX_RESULT_VALUE_DEPTH` rejects), but `_canonical_preview_value` stops recursing at `depth < 6`, so a valid depth-6 list/dict renders as `"[truncated]"`. Consider sharing the same depth constant/guard so validated nested data isn't collapsed.
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py - 1
    • Duplicate assertion · Line 202-202
      This added line duplicates the assertion on line 201 exactly. It adds no coverage and is dead code in the test. Remove it to keep the assertion single and avoid confusion.
Review Details
  • Files reviewed - 15 · Commit Range: efb6961..813b15f
    • superset/mcp_service/chart/query_result.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/test_preview_utils.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py
    • superset/mcp_service/chart/preview_utils.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/utils/cache_utils.py
    • tests/unit_tests/mcp_service/utils/test_cache_utils.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review bito-code-review Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #4d446c

Actionable Suggestions - 2
  • superset/mcp_service/utils/response_utils.py - 1
  • superset/mcp_service/chart/tool/get_chart_data.py - 1
Additional Suggestions - 2
  • superset/mcp_service/chart/query_result.py - 1
    • Oversized string raises AssertionError · Line 200-202
      Data strings longer than `MAX_RESULT_STRING_LENGTH` (65,536) now hit `assert size is not None` in `_normalized_scalar_json_size`, raising an uncaught `AssertionError`. The removed `_charge_text` path returned `"invalid text data"` instead. Callers `get_table.py`/`query_dataset.py` don't catch exceptions, so this is a behavior regression. Return `None` and emit the graceful error.
  • tests/unit_tests/mcp_service/chart/query_result_fixtures.py - 1
    • Empty-list falsy default · Line 55-55
      `coltypes = coltypes or [...]` treats an explicitly-passed empty list `coltypes=[]` as falsy and silently substitutes NUMERIC defaults, unlike the `is not None` checks on lines 53-54. No current caller passes `coltypes=[]`, so this is latent, but an empty-result caller would get unexpected coltypes. Consider `if coltypes is None` for consistency.
Review Details
  • Files reviewed - 15 · Commit Range: 813b15f..63c6cdc
    • superset/mcp_service/chart/query_result.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/dataset/tool/query_dataset.py
    • superset/mcp_service/semantic_layer/tool/get_table.py
    • tests/unit_tests/mcp_service/chart/query_result_fixtures.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/test_preview_utils.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
    • tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py
    • superset/mcp_service/utils/response_utils.py
    • tests/unit_tests/mcp_service/utils/test_response_utils.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/mcp_service/utils/response_utils.py
Comment thread superset/mcp_service/chart/tool/get_chart_data.py Outdated
@bito-code-review

bito-code-review Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #e5e4cf

Actionable Suggestions - 0
Review Details
  • Files reviewed - 17 · Commit Range: 63c6cdc..923d925
    • superset/mcp_service/chart/query_result.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_sql.py
    • superset/mcp_service/utils/response_utils.py
    • tests/unit_tests/mcp_service/chart/test_compile.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_preview.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
    • tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
    • tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py
    • tests/unit_tests/mcp_service/utils/test_response_utils.py
    • superset/common/query_context_processor.py
    • superset/dataframe.py
    • tests/unit_tests/common/test_query_context_processor.py
    • tests/unit_tests/dataframe_test.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c11764

Actionable Suggestions - 0
Additional Suggestions - 6
  • tests/unit_tests/mcp_service/chart/test_sunburst_chart.py - 1
    • Reject-test boundary mismatch · Line 1976-1986
      `_finite_number` (sunburst.py:152-153) returns only `Decimal.is_finite(value)` for Decimal. `Decimal("1e4097")`, `Decimal("1e-4097")`, and `Decimal("9"*1025)` are all finite, so `validate_sunburst_result_data` will not reject them and these parametrized cases expect `CHART_COMPILE_FAILED` — the test will fail unless a digit/exponent limit exists in the validation path.
  • superset/dataframe.py - 1
    • Decimal NaN regression · Line 48-57
      Add an explicit check for `Decimal` NaN in `_is_trusted_missing_or_nonfinite` to prevent `Decimal('NaN')` from passing through and breaking JSON serialization. For example:
      from decimal import Decimal
      ...
          if isinstance(value, Decimal):
              return value.is_nan()
      ```</div>
      
      </li>
      
      </ul>
      
      </div>
      </li>
      
      <li>
      <div id="secondary_suggestion">
      superset/mcp_service/chart/tool/get_chart_sql.py - <b>1</b>
      
      <ul>
      
      <li>
      <div>Redundant double preflight · <a href ="https://github.com/apache/superset/pull/43771/files#diff-2d5e8a001d734ee22024fb94b8640cbc1ef87504f46245f5b3e67463a6ce9ab5R487">Line 487-487</a></div>
      <div>This ChartError is preflighted here, then returned through `_handle_chart_sql_request` and preflighted again by the finalizer at line 561 — a redundant double O(n) JSON projection on the error path. The test `test_get_chart_sql_preflights_every_returned_chart_error_once` asserts `preflight.call_count == 1`, so return `response` directly here.</div>
      
      </li>
      
      </ul>
      
      </div>
      </li>
      
      <li>
      <div id="secondary_suggestion">
      tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py - <b>2</b>
      
      <ul>
      
      <li>
      <div>Misleading test case · <a href ="https://github.com/apache/superset/pull/43771/files#diff-17353af7a880af10fede9f48db72d339edd6bb0b4181cc0954356e761e8cef6eR560">Line 560-560</a></div>
      <div>The `cached-update` case sets both `identifier: 9` and `form_data_key`, but `get_chart_data` only enters the unsaved-cache path when `not request.identifier` (get_chart_data.py:430). With `identifier` set, `form_data_key` is ignored and `get_cached_form_data` is never called, so this case is functionally identical to `saved-json` (just CSV). The test name overstates what it verifies.</div>
      
      </li>
      
      <li>
      <div>Merge path not exercised · <a href ="https://github.com/apache/superset/pull/43771/files#diff-17353af7a880af10fede9f48db72d339edd6bb0b4181cc0954356e761e8cef6eR676">Line 676-678</a></div>
      <div>In the valid-case test, the cached-update path sets `chart.params` to `json.dumps(form_data)` (line 653) and `get_cached_form_data` also returns `form_data`, so saved and cached form_data are identical. The merge the commit claims to fix is never exercised with divergent inputs. Consider diverging `params` (as the second test does with `saved_region`/`Saved Sales`) so the merge path is meaningfully covered.</div>
      
      </li>
      
      </ul>
      
      </div>
      </li>
      
      <li>
      <div id="secondary_suggestion">
      tests/unit_tests/mcp_service/chart/test_query_result.py - <b>1</b>
      
      <ul>
      
      <li>
      <div>datetime called without tzinfo · <a href ="https://github.com/apache/superset/pull/43771/files#diff-107aae10d72d182c84406264d7e67314c6f375e02b51421e617d6ea4327b5b14R91">Line 91-91</a></div>
      <div>`DTZ001` flags `datetime(2026, 9, 2)` called without a `tzinfo` argument. Add `tzinfo=timezone.utc` (or `datetime.UTC`) to make the timestamp timezone-aware and avoid naive/aware comparison bugs.</div>
      
      </li>
      
      </ul>
      
      </div>
      </li>
      
      </ul>
      
      </details>
      </div>
      
      
      
      
      
      
      
      
      <div>
      <details>
      <summary>
      <b>Review Details</b>
      </summary>
      
      <ul>
      <li>
      <div id="file_reviewed">
      Files reviewed - <b>14</b> · Commit Range: <code>923d925..be228ec</code>
      <ul>
      <li>superset/dataframe.py</li><li>superset/mcp_service/chart/query_result.py</li><li>superset/mcp_service/chart/tool/get_chart_sql.py</li><li>superset/mcp_service/dataset/tool/query_dataset.py</li><li>superset/mcp_service/semantic_layer/tool/get_table.py</li><li>tests/unit_tests/dataframe_test.py</li><li>tests/unit_tests/mcp_service/chart/test_query_result.py</li><li>tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py</li><li>tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py</li><li>tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py</li><li>superset/mcp_service/chart/sunburst.py</li><li>tests/unit_tests/mcp_service/chart/test_sunburst_chart.py</li><li>tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py</li><li>superset/mcp_service/chart/tool/get_chart_data.py</li>
      </ul>
      </div>
      </li>
      
      <li>
      <div id="file_skipped">
      Files skipped - <b>0</b>
      <ul>
            
      </ul>
      </div>
      </li>
      
      
      <li>
      <div id="tools">
      Tools
      <ul>
            <li><b>MyPy</b> (Static Code Analysis) - ✔︎ Successful</li><li><b>Astral Ruff</b> (Static Code Analysis) - ✔︎ Successful</li><li><b>Whispers</b> (Secret Scanner) - ✔︎ Successful</li><li><b>Detect-secrets</b> (Secret Scanner) - ✔︎ Successful</li>
      </ul>
      </div>
      </li>
      
      </ul>
      </details>
      </div>
      
      <hr>
      
      
      <details>
      <summary>
      <b>Bito Usage Guide</b>
      </summary>
            
      **Commands**
            
      Type the following command in the pull request comment and save the comment.
            
      - `/review` - Manually triggers an incremental AI Review.
      - `/review full` - Manually triggers a full AI Review.
      
      - `/pause` - Pauses automatic reviews on this pull request.
      - `/resume` - Resumes automatic reviews.
      - `/resolve` - Marks all Bito-posted review comments as resolved.
      - `/abort` - Cancels all in-progress reviews.
      
            
      Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
            
      **Configuration**
      
      This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
            
      **Documentation & Help**
      - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
      - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
      - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
      - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
      </details>
      
      
      
      
      <span><i>AI Code Review powered by</i> <sub><sub><a href="https://bito.ai/" target="_blank"><img src="https://bito.ai/wp-content/uploads/2023/10/Logo-Bito-Black-cropped.svg" alt="Bito Logo" width="50" height="20" /></a></sub></sub></span>
      
      
      </div>

@bito-code-review

bito-code-review Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c5cd0e

Actionable Suggestions - 0
Additional Suggestions - 4
  • superset/mcp_service/utils/response_utils.py - 1
    • Decimal/int token inconsistency · Line 241-246
      `_decimal_profile_identity` can emit a `("number", numerator, denominator)` token whose numerator/denominator exceed the int path's `_MAX_PROFILE_INTEGER_BITS` cap. Verified: `Decimal('1E+4096')` yields `("number", 10**4096, 1)` (13,607 bits) while `int 10**4096` yields `("oversized_integer", ...)`. Same value, different tokens — contradicting the docstring's cross-type equality promise and inflating `unique_count` in `format_data_columns`. Bound the result to the int cap and return None when exceeded.
  • tests/unit_tests/mcp_service/chart/test_response_preflight.py - 1
    • Test measures wrong wire projection · Line 95-95
      `_fill_model_to_limit` sizes the boundary with `model_dump_json()` (default `by_alias=False`), but production `response_json_failure` uses `model_dump(..., by_alias=True)`. Test 4 only passes because `internal_name` and `longWireAlias` are both 13 chars; it would silently pass even if aliases were ignored. Use `model_dump_json(by_alias=True)` to match the real wire projection.
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py - 1
    • Self-fulfilling test · Line 760-776
      The fake `_Command.run()` pre-canonicalizes non-finite Decimals via `df_to_records` before `chart_data_command_result`, so the `None` values come from the fake, not from `QueryContextProcessor.get_data`. The test would pass even if `get_data`'s canonicalization were removed. Pass the raw Decimals to `chart_data_command_result` so the real producer path is exercised.
  • tests/unit_tests/sql_lab_test.py - 1
    • Tautological test assertion · Line 94-96
      This assertion is tautological: `_deserialize_results_payload` with `use_msgpack=False` (default) returns `superset.utils.json.loads(payload)` (views/utils.py:673), and `superset_json` is the same module. So it compares a function to itself and always passes, verifying nothing about the view consumer. Assert on the deserialized `data` values instead.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/mcp_service/chart/tool/update_chart.py - 1
  • superset/mcp_service/chart/response_preflight.py - 1
Review Details
  • Files reviewed - 16 · Commit Range: be228ec..0ae605f
    • superset/mcp_service/chart/response_preflight.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/get_chart_preview.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • superset/mcp_service/utils/response_utils.py
    • tests/unit_tests/mcp_service/chart/test_response_preflight.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
    • tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py
    • tests/unit_tests/mcp_service/utils/test_response_utils.py
    • superset/dataframe.py
    • tests/unit_tests/dataframe_test.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/sql/execution/test_celery_task.py
    • tests/unit_tests/sql_lab_test.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/mcp_service/chart/schemas.py Outdated

@bito-code-review bito-code-review Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #bb24a2

Actionable Suggestions - 1
  • superset/mcp_service/chart/tool/get_chart_data.py - 1
Additional Suggestions - 7
  • tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py - 3
    • fold=1 offset expectation wrong · Line 599-599
      `fold=1` on 2024-10-27 01:30 in `Europe/Dublin` denotes the second occurrence after clocks fall back, which is GMT (+00:00), not IST (+01:00). The expected `+01:00` is semantically inconsistent with Python/dateutil fold semantics. Verify `_dateutil_named_offset_without_hooks`'s `if not value.fold and is_ambiguous: index -= 1` branch; either the expectation should be `+00:00` or the source's fold handling is inverted.
    • Vacuous secret-leak assertion · Line 337-337
      `HostileRuntimeError.__str__`/`__repr__` return `"round21-hostile-runtime-secret"`, never the constructor arg `"stored-secret"`. So this assertion checks a literal that can never appear and would pass even if the secret leaked. Assert the real leakable string so the containment test actually verifies its claim.
    • Unmocked DB lookup in unit test · Line 298-313
      In the `context-exit` branch `resolve_dataset` is left unmocked, so the test performs a real `DatasetDAO.find_by_id(1)` DB lookup before the context `__exit__` raises. Every other test in this file mocks `resolve_dataset` (e.g. lines 570, 626). Mock it here too for a deterministic unit test.
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py - 1
    • Duplicated test setup · Line 961-989
      Both new tests duplicate the same `_Command` stub, `form_data`, and five `monkeypatch.setattr` calls (lines 902-923 vs 961-989). If one setup block is later updated (e.g. a new mock) and the other is not, the two tests silently diverge. Consider a shared fixture/helper to keep the timezone assertions the only difference.
  • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py - 1
    • Test no longer near boundary · Line 428-428
      `test_extract_sql_accepts_multi_query_and_near_response_boundary` only patches `_get_chart_sql_mod.MAX_QUERY_RESULT_VALUE_BYTES`, but the boundary case flows through `response_json_failure`, which reads the constant from `query_result` (still 16 MiB). So `boundary_sql = test_limit - 512` (3584 B) is no longer near the response limit, and the test no longer verifies its stated purpose. Patch `query_result.MAX_QUERY_RESULT_VALUE_BYTES` too, as the sibling test does.
  • superset/mcp_service/chart/response_preflight.py - 1
    • Missing unit tests · Line 45-80
      This new helper is now used at 10+ call sites across `get_chart_data.py`, `query_dataset.py`, and `get_table.py`, yet has no unit tests. Its byte-budget truncation, multi-byte UTF-8 handling, and type-dispatch branches are non-trivial (C901-suppressed). Per BITO.md rules 11730/11731, add tests covering success paths, edge cases, and the 'request failed' fallback.
  • tests/unit_tests/mcp_service/chart/query_result_fixtures.py - 1
    • Nested ternary readability · Line 82-90
      The nested conditional expression for deriving `columns` is hard to read and error-prone. Consider refactoring to use explicit `if/elif/else` statements for clarity and easier maintenance.
Review Details
  • Files reviewed - 12 · Commit Range: 0ae605f..414c7a6
    • superset/mcp_service/chart/response_preflight.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/dataset/tool/query_dataset.py
    • superset/mcp_service/semantic_layer/tool/get_table.py
    • tests/unit_tests/mcp_service/chart/test_query_result.py
    • tests/unit_tests/mcp_service/chart/test_response_preflight.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_sql.py
    • tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
    • tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.py
    • superset/mcp_service/chart/query_result.py
    • tests/unit_tests/mcp_service/chart/query_result_fixtures.py
  • Files skipped - 1
    • .github/workflows/superset-python-unittest.yml - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/mcp_service/chart/tool/get_chart_data.py
Comment thread superset/common/form_data_query_context.py
Comment thread superset/common/form_data_query_context.py
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/common/form_data_query_context.py
Comment thread superset/common/form_data_query_context.py
Comment thread superset/mcp_service/chart/plugins/table.py Outdated
Comment thread superset/mcp_service/chart/plugins/xy.py
Comment thread superset/mcp_service/chart/preview_utils.py
Comment thread superset/mcp_service/chart/query_result.py
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/mcp_service/chart/response_preflight.py
Comment thread superset/mcp_service/chart/chart_utils.py
# Conflicts:
#	superset/mcp_service/chart/tool/get_chart_data.py
#	tests/unit_tests/mcp_service/chart/tool/test_get_chart_data.py
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/mcp_service/chart/tool/update_chart.py Outdated
Comment thread superset/mcp_service/chart/tool/update_chart_preview.py
Comment thread superset/common/form_data_query_context.py
Comment thread superset/mcp_service/chart/chart_helpers.py Outdated
Comment thread superset/mcp_service/chart/schemas.py
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/common/form_data_query_context.py Outdated
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/mcp_service/chart/preview_utils.py
Comment thread superset/mcp_service/chart/query_result.py Outdated
Comment thread UPDATING.md
Comment thread superset/mcp_service/chart/chart_helpers.py Outdated
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/mcp_service/chart/schemas.py Outdated
Comment thread tests/unit_tests/mcp_service/chart/test_preview_utils.py Outdated
Comment thread docs/docs/using-superset/using-ai-with-superset.mdx Outdated
@aminghadersohi

Copy link
Copy Markdown
Contributor Author

@michael-s-molina @msyavuz this is approved by @sadpandajoe and waiting on a code owner stamp. Could one of you take a look when you get a chance? Thanks!

Comment thread superset/mcp_service/chart/chart_utils.py Outdated
Comment thread superset/common/form_data_query_context.py
Comment thread superset/mcp_service/chart/tool/get_chart_data.py
Keep saved temporal range filters when only the aggregation grain changes. Skip rolling and forecast analytics on bounded compile samples without changing full chart queries. Document non-finite export normalization and cover CSV and both XLSX writers.
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/mcp_service/chart/plugins/mixed_timeseries.py
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/mcp_service/chart/query_result.py
Comment thread superset/mcp_service/chart/tool/get_chart_sql.py
Comment thread superset/mcp_service/chart/query_result.py
Comment thread superset/mcp_service/chart/chart_utils.py
Comment thread superset/mcp_service/chart/chart_utils.py Outdated
Comment thread superset/common/form_data_query_context.py
Comment thread docs/admin_docs/configuration/mcp-server.mdx Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc Namespace | Anything related to documentation size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants