Skip to content

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

Merged
rusackas merged 6 commits into
apache:masterfrom
AryaKetanShCt:fix/post-processing-drop-unsupported-options
Aug 20, 2026
Merged

fix: drop post-processing options the operation no longer accepts#42927
rusackas merged 6 commits into
apache:masterfrom
AryaKetanShCt:fix/post-processing-drop-unsupported-options

Conversation

@AryaKetanShCt

Copy link
Copy Markdown
Contributor

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.73%. Comparing base (c2d653b) to head (0d6c8fb).

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.73%   66.73%   -0.01%     
==========================================
  Files        2876     2876              
  Lines      164201   164218      +17     
  Branches    37887    37890       +3     
==========================================
+ Hits       109577   109587      +10     
- Misses      52467    52471       +4     
- Partials     2157     2160       +3     
Flag Coverage Δ
hive 38.10% <25.00%> (-0.01%) ⬇️
mysql 57.76% <65.00%> (+<0.01%) ⬆️
postgres 57.79% <65.00%> (+<0.01%) ⬆️
presto 40.04% <30.00%> (-0.01%) ⬇️
python 59.18% <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
Contributor 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
Contributor 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

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

# Conflicts:
#	tests/unit_tests/queries/query_object_test.py
@AryaKetanShCt

Copy link
Copy Markdown
Contributor Author

@msyavuz @rusackas — this one is ready for review whenever you have a moment.

Updated to master in 0ea7e84. The conflict was a two-sided import addition in tests/unit_tests/queries/query_object_test.py: master added Metric and this branch added pandas_postprocessing. Both are kept, in isort order. The diff against master is unchanged at 250 insertions and 4 deletions across the same four files, and nothing from master was dropped — that file has zero deletions relative to master.

State:

  • All three review threads resolved. The df finding from codeant-ai and both Copilot findings (*args in the supported set, and the log level) are fixed in code, not just answered.
  • Last full CI run on this branch was green across all 22 workflows.
  • Workflows on the new head are sitting at action_required, so they need an approval click before they can run.

No rush on my end, and happy to split or reshape it if the scope is awkward to review as one change.

@rusackas

Copy link
Copy Markdown
Member

Thanks @AryaKetanShCt, LGTM! Nice diagnosis on the stale query_context issue, and signature-based filtering beats a hard-coded list of removed options. Bot threads all look properly fixed in code too. Will merge once CI's green.

@rusackas
rusackas merged commit f9cedf8 into apache:master Aug 20, 2026
73 checks passed
@bito-code-review

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

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.

3 participants