shoemoney opened a new pull request, #44460:
URL: https://github.com/apache/superset/pull/44460

   ### SUMMARY
   
   Fixes #42926 (the second symptom, the one left open after #42927).
   
   A chart saved before the x-axis control existed keeps its time column in 
`params` as the legacy `granularity_sqla`, and its stored `query_context` has 
`is_timeseries: true` with `granularity: null`:
   
   ```json
   {"is_timeseries": true, "columns": ["ds"], "metrics": ["count"], "filters": 
[], "granularity": null}
   ```
   
   `QueryContextFactory._apply_granularity` 
(`superset/common/query_context_factory.py:245-276` on master) only infers a 
granularity when `form_data` carries an adhoc `x_axis` plus a temporal range 
bound. With no `x_axis`, `is_adhoc_column(None)` is false, 
`should_infer_filter_granularity` is false, the `if granularity := 
query_object.granularity:` block at line 278 is skipped because the granularity 
is `None`, and the method returns having set nothing. 
`superset/models/helpers.py:4715` then hits
   
   ```python
   if not granularity and is_timeseries:
       raise QueryObjectValidationError(
           _("Datetime column not provided as part table configuration "
             "and is required by this type of chart")
       )
   ```
   
   and the request fails with a 400 out of `ChartDataQueryFailedError`. The 
backward-compatibility coercion just above it (`helpers.py:4704`) is explicitly 
gated on `granularity is not None`, so a null granularity is not rescued there, 
and the `granularity_sqla` to `granularity` rename at `query_object.py:69` is 
query-object level only and never reads `form_data`.
   
   The chart still renders in Explore, because the paths that rebuild a query 
from form data already resolve the legacy key: `extractExtras.ts:77-80` for 
Explore, and `form_data_query_context.py:349` for the Excel export and the MCP 
tools. Only the consumers that replay the stored `query_context` verbatim 
through `GET /api/v1/chart/<id>/data/` fail, which is alerts and reports, 
thumbnails, cache warm-up and data export.
   
   This is the fix @rusackas described on the issue: when the query object is a 
timeseries with no granularity, fall back to `form_data`'s `granularity_sqla`, 
and only then to the dataset's main datetime column.
   
   Two deliberate narrowings, both to avoid disturbing existing behavior:
   
   - Candidates are matched against the already computed `temporal_columns` 
set, so a column that old `params` still names but the dataset has since 
dropped or made non temporal is ignored rather than injected into the query.
   - The fallback is skipped when `form_data` carries an `x_axis`. Setting a 
granularity there would fall into the block below and rewrite the x-axis column 
to the granularity, which is exactly what 
`test_apply_granularity_preserves_physical_temporal_axis` guards against. An 
`x_axis` query is also not the reported shape: `is_timeseries` defaults to 
`DTTM_ALIAS in columns` (`query_object.py:202`), which is the pre-x-axis form. 
A stored query that somehow has both an explicit `is_timeseries: true` and an 
`x_axis` still reaches the raise, and is left for a separate change rather than 
risking the column rewrite here.
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   Not applicable, backend only.
   
   ### TESTING INSTRUCTIONS
   
   Six unit tests were added to 
`tests/unit_tests/common/test_query_context_factory.py`: the `granularity_sqla` 
fallback, the `main_dttm_col` fallback, a stale legacy column being ignored, an 
explicit granularity not being overridden, a non timeseries query being left 
alone, and an x-axis query being left alone.
   
   ```
   pytest tests/unit_tests/common/test_query_context_factory.py
   ```
   
   Red, with the three new fallback tests against unmodified 
`query_context_factory.py`:
   
   ```
   FFF...                                                                   
[100%]
   >       assert query_object.granularity == "ds"
   E       AssertionError: assert None == 'ds'
   E        +  where None = <Mock spec='QueryObject' 
id='4709837200'>.granularity
   tests/unit_tests/common/test_query_context_factory.py:567: AssertionError
   ...
   FAILED 
tests/unit_tests/common/test_query_context_factory.py::TestQueryContextFactory::test_apply_granularity_falls_back_to_legacy_granularity_sqla
   FAILED 
tests/unit_tests/common/test_query_context_factory.py::TestQueryContextFactory::test_apply_granularity_falls_back_to_main_dttm_col
   FAILED 
tests/unit_tests/common/test_query_context_factory.py::TestQueryContextFactory::test_apply_granularity_ignores_stale_legacy_granularity_sqla
   3 failed, 3 passed, 45 deselected in 0.55s
   ```
   
   Green, same file with the fix applied (45 pre-existing plus the 6 new):
   
   ```
   ...................................................                      
[100%]
   51 passed in 0.37s
   ```
   
   The rest of the directory is unaffected:
   
   ```
   $ pytest tests/unit_tests/common -q
   337 passed in 6.90s
   ```
   
   `tests/unit_tests/charts` and `tests/unit_tests/models` were also run: 1154 
passed with this branch against 1148 on master, with the same 20 failures in 
`models/core_test.py` and `models/test_hours_offset_bound_truncation.py` before 
and after, so they are pre-existing in my environment and unrelated.
   
   `pre-commit run` on the two staged files passes, including mypy (main), 
ruff, ruff-format and pylint.
   
   Manual check: save a chart whose `query_context` has `is_timeseries: true` 
and no `granularity` while its `params` carry only `granularity_sqla`, then 
call `GET /api/v1/chart/<pk>/data/`. It returns the data instead of "Datetime 
column not provided as part table configuration".
   
   Environment used: Python 3.11 venv, `pip install -r requirements/base.txt` 
then `pip install -e . --no-deps`, plus pytest. No end-to-end API test is 
included in this PR, since the change is confined to one method and the unit 
file already owns the `_apply_granularity` cases. Happy to add an integration 
test that stores a legacy-shaped `query_context` and asserts a 200 from the 
data endpoint if a reviewer would rather see it pinned there too.
   
   ### ADDITIONAL INFORMATION
   
   - [x] Has associated issue: #42926
   - [ ] Required feature flags:
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in 
[SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] 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
   


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

To unsubscribe, e-mail: [email protected]

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


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

Reply via email to