SEPURI-SAI-KRISHNA opened a new issue, #45017:
URL: https://github.com/apache/superset/issues/45017

   ### Bug description
   
   `_append_columns` decides between overwriting and appending with `all()`, so 
a mapping that does both falls entirely to the append path:
   
   ```python
   # superset/utils/pandas_postprocessing/utils.py
   if all(key == value for key, value in columns.items()):
       _base_df = base_df.copy()
       _base_df.loc[:, columns.keys()] = append_df
       return _base_df
   append_df = append_df.rename(columns=columns)
   return pd.concat([base_df, append_df], axis="columns")
   ```
   
   The column that should have been overwritten is re-appended under its own 
name, so the result carries two columns with the same label. Every operator 
taking a `columns: dict[str, str]` mapping is affected: `cum`, `rolling`, 
`diff`, `geohash_decode`, `geohash_encode`, `geodetic_parse`.
   
   Measured on master (`df` has columns `y` and `z`):
   
   | mapping | result | |
   |---|---|---|
   | `{"y": "y", "z": "z"}` | `['y', 'z']` | ✅ all overwrite |
   | `{"y": "y2", "z": "z2"}` | `['y', 'z', 'y2', 'z2']` | ✅ all rename |
   | `{"y": "y", "z": "z2"}` | `['y', 'z', 'y', 'z2']` | ❌ `y` duplicated |
   
   ```python
   import pandas as pd
   from superset.utils.pandas_postprocessing import cum
   
   df = pd.DataFrame({"y": [1.0, 2.0, 3.0], "z": [4.0, 5.0, 6.0]})
   out = cum(df=df, operator="sum", columns={"y": "y", "z": "z2"})
   out.columns.tolist()          # ['y', 'z', 'y', 'z2']
   type(out["y"])                # <class 'pandas.DataFrame'>  -- callers 
expect a Series
   ```
   
   `rolling` and `diff` reproduce identically. It also happens with MultiIndex 
columns, which is the realistic chart path. Cumulating one metric in place 
after a pivot while adding another alongside it duplicates `('sum_metric', 
'UK')` and `('sum_metric', 'US')`.
   
   Downstream, `df["y"]` returning a 2-column DataFrame instead of a Series 
breaks `flatten`, serialization, and any later post-processing step.
   
   ### A second defect in the same branch
   
   The append path concatenates the whole of `append_df`, including columns the 
mapping never asked for. `geodetic_parse` always parses an altitude but only 
maps it when the caller requested one:
   
   ```python
   post_df = geodetic_parse(
       df=lonlat_df[["city", "geodetic"]],
       geodetic="geodetic",
       latitude="lat",
       longitude="lon",       # no altitude requested
   )
   post_df.columns.tolist()   # ['city', 'geodetic', 'lat', 'lon', 'altitude']
   ```
   
   An unrequested `altitude` column reaches the result. The all-overwrite path 
does *not* leak it, because `.loc[:, keys] = append_df` aligns by label and 
ignores the extra column, so the two paths already disagree. The existing 
`test_geodetic_parse` covers only the path that behaves correctly.
   
   `geohash_encode` is worse, because the columns it leaks collide with the 
ones already in the frame. It builds its working frame with hardcoded 
`latitude`/`longitude` labels and maps only the geohash, so naming the geohash 
column anything other than `geohash` makes the mapping a pure rename and sends 
the whole working frame through the concat:
   
   ```python
   out = geohash_encode(
       df=lonlat_df[["city", "latitude", "longitude"]],
       latitude="latitude",
       longitude="longitude",
       geohash="hash",       # any name but "geohash" takes the rename path
   )
   out.columns.tolist()              # ['city', 'latitude', 'longitude', 
'latitude', 'longitude', 'hash']
   out.columns.duplicated().any()    # True
   type(out["latitude"])             # <class 'pandas.DataFrame'>
   ```
   
   So the duplicate-label failure is not confined to mixed mappings: an 
all-rename mapping reaches it too whenever `append_df` carries a column that 
`base_df` already has. Both defects come from the same two lines, and selecting 
before renaming fixes both.
   
   ### How to reproduce the bug
   
   1. Send a chart-data request whose `post_processing` passes a `columns` 
mapping where some entries rename and others do not, e.g. `{"operation": "cum", 
"options": {"operator": "sum", "columns": {"y": "y", "z": "z2"}}}`.
   2. The response carries two columns labelled `y`.
   
   ### Why it was not caught
   
   No test in `test_cum.py`, `test_rolling.py` or `test_diff.py` passes a mixed 
mapping. Every case is either all-overwrite or all-rename, where `all()` and 
`any()` agree. The geography tests miss their half for a different reason: 
`test_geohash_encode` and `test_geodetic_parse` name the target columns exactly 
as the working frame names them, which is an identity mapping, so both take the 
overwrite path and never exercise the concat.
   
   ### Suggested fix
   
   Split the mapping and handle each half, selecting before renaming so 
unmapped columns are dropped:
   
   ```python
   overwritten = {key: value for key, value in columns.items() if key == value}
   appended = {key: value for key, value in columns.items() if key != value}
   ```
   
   ### Screenshots/recordings
   
   _No response_
   
   ### Superset version
   
   master / latest-dev
   
   ### Python version
   
   3.11
   
   ### Node version
   
   Not applicable
   
   ### Browser
   
   Not applicable
   
   ### Additional context
   
   _No response_
   
   ### Checklist
   
   - [x] I have searched Superset docs and Slack and didn't find a solution to 
my problem.
   - [x] I have searched the GitHub issue tracker and didn't find a similar bug 
report.
   - [x] I have checked Superset's logs for errors and if I found a relevant 
Python stacktrace, I included it here as text in the "additional context" 
section.
   


-- 
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