Skip to content

fix: drop post-processing options the operation no longer accepts - #42927

Open
AryaKetanShCt wants to merge 4 commits into
apache:masterfrom
AryaKetanShCt:fix/post-processing-drop-unsupported-options
Open

fix: drop post-processing options the operation no longer accepts#42927
AryaKetanShCt wants to merge 4 commits into
apache:masterfrom
AryaKetanShCt:fix/post-processing-drop-unsupported-options

Conversation

@AryaKetanShCt

Copy link
Copy Markdown

SUMMARY

Fixes the first symptom of #42926.

A chart's query_context is written when the chart is saved and is never rewritten. Explore rebuilds the query from form_data at every render and never reads it, so only the paths that are not a browser replay it: GET /api/v1/chart/<id>/data/, alerts and reports, thumbnails, cache warm-up, CSV export.

The stored query therefore ages while the engine moves on. pivot used to accept flatten_columns and reset_index; flattening became its own operation and those parameters were removed. exec_post_processing passes the stored options straight through:

df = getattr(pandas_postprocessing, operation)(df, **options)

so replaying a chart saved before that change gives

TypeError: pivot() got an unexpected keyword argument 'flatten_columns'

on every one of those paths, while the same chart renders correctly in Explore. There is no migration for the stored query, so the failure is permanent until somebody opens each chart and re-saves it.

The change. QueryObject compares the stored options against the signature of the operation and drops those it no longer accepts, logging a warning that names the operation and the options. Comparing against the signature avoids a hard-coded list of removed names, which would need extending at each release. An operation that takes **kwargs is left alone. An unknown operation is left in place so that exec_post_processing still reports it as InvalidPostProcessingError.

Why functools.wraps is in the same PR. That comparison needs a signature to read, and there was none. validate_column_args returned def wrapped(df, **options) without wraps:

>>> inspect.signature(pivot)
(df: object, **options: object) -> object
>>> pivot.__name__
'wrapped'

All ten operations using that decorator (aggregate, compare, contribution, cum, diff, pivot, rename, rolling, select, sort) reported **kwargs and lost their name and docstring. inspect.unwrap cannot recover the original, because without wraps there is no __wrapped__. Adding wraps restores the signature, the name and the docstring. Happy to split this into its own PR if you prefer.

Scope. The second symptom in #42926 — a stored query that sets is_timeseries without a temporal column — is deliberately not addressed here. _apply_granularity has since gained its own inference path, so the intended behaviour there deserves a maintainer's opinion before I send code.

Behaviour for current charts is unchanged. A query_context built by the current frontend has options that match the current signature, so nothing is dropped and the same dict object is returned.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Server-side; no UI change.

Before, on a chart saved in 2023:

GET /api/v1/chart/6132/data/
500  TypeError: pivot() got an unexpected keyword argument 'flatten_columns'

After, the same chart returns its rows. The chart itself was never broken in Explore, before or after.

TESTING INSTRUCTIONS

New unit tests:

  • tests/unit_tests/queries/query_object_test.py
    • a stored pivot with flatten_columns and reset_index keeps only the supported options, and keeps their values
    • a current query_context is returned unchanged, as the same object
    • an unknown operation is preserved for exec_post_processing to reject
  • tests/unit_tests/pandas_postprocessing/test_utils.py
    • the decorator exposes the signature and the name of the operation it wraps

Manual check on any version:

import inspect
from superset.utils.pandas_postprocessing import pivot
print(inspect.signature(pivot))  # before: (df, **options); after: the real parameters

This change is also running in production on a 6.1.0 instance, applied as a patch. Three charts that had failed for years — an echarts_timeseries_bar and a big_number saved in 2023 — now return data through the chart-data endpoint, and charts saved recently are unaffected.

ADDITIONAL INFORMATION

@bito-code-review

bito-code-review Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #833b8f

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: 3982225..3982225
    • superset/common/query_object.py
    • superset/utils/pandas_postprocessing/utils.py
    • tests/unit_tests/pandas_postprocessing/test_utils.py
    • tests/unit_tests/queries/query_object_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 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/common/query_object.py Outdated
@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The _drop_unsupported_options method in QueryObject inspects the signature of post-processing operations to filter out unsupported options. However, if an option named df is present in the stored options dictionary, it is currently treated as a supported parameter because it is not explicitly excluded, leading to a TypeError when the operation is called as operation(df, **options) (since df is passed both as the first positional argument and as a keyword argument).

To resolve this, you should explicitly exclude df from the options dictionary in _drop_unsupported_options.

Proposed Fix

In superset/common/query_object.py, update the filtering logic in _drop_unsupported_options:

        options = post_proc.get("options") or {}
        unsupported = {key for key in options if key not in parameters or key == "df"}
        if not unsupported:
            return post_proc

This change ensures that even if df is present in the stored options, it is filtered out before the operation is invoked.

Would you like me to check the rest of the comments on this PR to see if there are other issues that need addressing?

superset/common/query_object.py

options = post_proc.get("options") or {}
        unsupported = {key for key in options if key not in parameters or key == "df"}
        if not unsupported:
            return post_proc

@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.00000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.41%. Comparing base (3539c41) to head (56f6b84).

Files with missing lines Patch % Lines
superset/common/query_object.py 61.11% 4 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42927      +/-   ##
==========================================
- Coverage   66.41%   66.41%   -0.01%     
==========================================
  Files        2858     2858              
  Lines      161446   161463      +17     
  Branches    37190    37193       +3     
==========================================
+ Hits       107222   107229       +7     
- Misses      52187    52193       +6     
- Partials     2037     2041       +4     
Flag Coverage Δ
hive 38.20% <25.00%> (-0.01%) ⬇️
mysql 57.76% <65.00%> (+<0.01%) ⬆️
postgres 57.82% <65.00%> (-0.01%) ⬇️
presto 40.17% <30.00%> (-0.01%) ⬇️
python 59.20% <65.00%> (-0.01%) ⬇️
sqlite 57.43% <65.00%> (+<0.01%) ⬆️
unit 100.00% <ø> (ø)

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.

AryaKetanShCt added a commit to AryaKetanShCt/superset that referenced this pull request Aug 9, 2026
Review comment on apache#42927. `exec_post_processing` calls the operation as
`operation(df, **options)`, so the first parameter takes the DataFrame
positionally. The name check accepted every parameter of the signature,
therefore an option named `df` counted as supported and reached the call,
which then raised `TypeError: pivot() got multiple values for argument 'df'`.

The behaviour is the same before this pull request, because the options went
to the operation unchanged. The check must still not call such an option
supported. It now compares against the parameters that a caller can give by
keyword: the first parameter and any positional-only parameter are excluded.

Also adds tests for the branches that the first commit left uncovered: an
option named `df`, an operation that takes `**kwargs`, and an entry that names
no operation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@AryaKetanShCt

Copy link
Copy Markdown
Author

Thanks — the df finding is correct, and 83f4957 fixes it.

One clarification for the record: the same call fails on master today, because the options go to the operation unchanged. So this pull request does not add the failure. But the check must still not report such an option as supported, and it did.

The check now compares against the parameters that a caller can give by keyword. It excludes the first parameter, which takes the DataFrame positionally in operation(df, **options), and any positional-only parameter.

keyword_parameters = {
    name
    for position, (name, parameter) in enumerate(parameters.items())
    if position > 0 and parameter.kind is not inspect.Parameter.POSITIONAL_ONLY
}

An option named df is now dropped with the same warning as any other unsupported option, instead of reaching the call.

The commit also adds tests for the three branches that the first commit left uncovered, which was the codecov report: an option named df, an operation that takes **kwargs, and an entry that names no operation.

@bito-code-review

bito-code-review Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #b871e5

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 3982225..83f4957
    • superset/common/query_object.py
    • tests/unit_tests/queries/query_object_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 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

@rusackas
rusackas requested review from msyavuz and rusackas and a lite review from Copilot August 10, 2026 00:47
Copilot stopped reviewing on behalf of rusackas due to an error August 10, 2026 00:47

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds backward-compatible handling for stored query_context post-processing options by filtering out options no longer accepted by pandas post-processing operations.

Changes:

  • Filter unsupported post-processing options in QueryObject by inspecting the target operation’s signature.
  • Preserve decorated operation signatures via functools.wraps so signature inspection remains accurate.
  • Add unit tests covering option dropping behavior and decorator signature preservation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tests/unit_tests/queries/query_object_test.py Adds tests for dropping unsupported post-processing options while retaining valid/unknown operations.
tests/unit_tests/pandas_postprocessing/test_utils.py Adds regression test ensuring decorated operations keep their original signature for inspect.signature.
superset/utils/pandas_postprocessing/utils.py Updates decorator to use wraps so signature/name are preserved.
superset/common/query_object.py Implements signature-based filtering of unsupported post-processing options and logs when dropping occurs.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread superset/common/query_object.py
Comment thread superset/common/query_object.py Outdated
AryaKetanShCt and others added 2 commits August 10, 2026 10:40
A chart's `query_context` is written when the chart is saved and is never
rewritten. Explore rebuilds the query from `form_data` at every render and
never reads it, so only the paths that are not a browser replay it: the chart
data endpoint, alerts and reports, thumbnails, cache warm-up and CSV export.

The stored query therefore ages while the engine moves on. `pivot` used to
accept `flatten_columns` and `reset_index`; flattening became its own
operation and the parameters were removed. `exec_post_processing` passes the
stored options as keyword arguments, so replaying a chart saved before that
change raises `TypeError: pivot() got an unexpected keyword argument
'flatten_columns'` on every one of those paths, while the same chart still
renders correctly in Explore. There is no migration for the stored query, so
the failure is permanent until somebody re-saves each chart by hand.

`QueryObject` now compares the stored options against the signature of the
operation and drops the ones it no longer accepts, with a warning naming the
operation and the options. Comparing against the signature avoids a list of
removed option names that would need extending at each release. An operation
that takes `**kwargs` is left alone, and an unknown operation is left for
`exec_post_processing` to report as `InvalidPostProcessingError`.

That comparison needs a signature to read. `validate_column_args` returned
`def wrapped(df, **options)` without `functools.wraps`, so all ten operations
that use it reported `(df, **options)` and lost their `__name__` and
`__doc__`. `inspect.unwrap` could not recover the original, because without
`wraps` there is no `__wrapped__`. Adding `wraps` restores the signature, the
name and the docstring.

Fixes the first symptom of apache#42926. The second symptom in that issue, a stored
query that sets `is_timeseries` without a temporal column, is left out on
purpose: `_apply_granularity` has since gained its own inference path, and the
intended behaviour there deserves a maintainer's opinion first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review comment on apache#42927. `exec_post_processing` calls the operation as
`operation(df, **options)`, so the first parameter takes the DataFrame
positionally. The name check accepted every parameter of the signature,
therefore an option named `df` counted as supported and reached the call,
which then raised `TypeError: pivot() got multiple values for argument 'df'`.

The behaviour is the same before this pull request, because the options went
to the operation unchanged. The check must still not call such an option
supported. It now compares against the parameters that a caller can give by
keyword: the first parameter and any positional-only parameter are excluded.

Also adds tests for the branches that the first commit left uncovered: an
option named `df`, an operation that takes `**kwargs`, and an entry that names
no operation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@AryaKetanShCt
AryaKetanShCt force-pushed the fix/post-processing-drop-unsupported-options branch from 83f4957 to 4495fa0 Compare August 10, 2026 05:10
`exec_post_processing` calls the operation as `operation(df, **options)`,
so an option can only reach a parameter that accepts a keyword argument.
The check also accepted `*args`, which cannot be filled that way, so an
option named after it was reported as supported and still raised
`TypeError: got an unexpected keyword argument`.

Restrict the supported set to POSITIONAL_OR_KEYWORD and KEYWORD_ONLY
parameters, which drops `*args` alongside the positional-only parameters
already excluded.

Log the dropped options at info rather than warning. A chart saved before
an option was removed reaches this on every render, so a warning repeats
for as long as the chart is not resaved without reporting anything new.

Signed-off-by: Arya Ketan <aryaketan@sharechat.co>
@AryaKetanShCt

Copy link
Copy Markdown
Author

hi @rusackas , can u pl re-trigger the workflow,

@bito-code-review

bito-code-review Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #21d3e2

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: 5565c3b..56f6b84
    • superset/common/query_object.py
    • superset/utils/pandas_postprocessing/utils.py
    • tests/unit_tests/pandas_postprocessing/test_utils.py
    • tests/unit_tests/queries/query_object_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 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants