Skip to content

[bot] Merge master/56f00e1f into rel/dev - #1693

Merged
yenkins-admin merged 10 commits into
rel/devfrom
snapshot-master-56f00e1f-to-rel/dev
Jul 20, 2026
Merged

[bot] Merge master/56f00e1f into rel/dev#1693
yenkins-admin merged 10 commits into
rel/devfrom
snapshot-master-56f00e1f-to-rel/dev

Conversation

@yenkins-admin

Copy link
Copy Markdown
Contributor

🚀 Automated PR to perform merge from master into rel/dev with changes up to 56f00e1 (created by https://github.com/gooddata/gooddata-python-sdk/actions/runs/29727223381).

The JSON extraction path converted attribute values one at a time, calling pandas.to_datetime / pandas.to_numeric
per scalar and re-resolving the converter for every value.

Convert each attribute column in a single vectorized call instead: parse each raw value with the cheap per-value
to_type(), then apply the pandas conversion once to the whole column. This is safe because to_type() fully parses
the raw strings first, so the vectorized call only ever wraps already-typed date/datetime/int objects
(never raw strings, which could be subject to column-wide format inference).

Measured 6-13x faster attribute-column conversion on 50k-row columns.

JIRA: CQ-2677
risk: low
…ot per page

The paging loop resolved each index / attribute column to its CatalogAttribute
via a linear catalog scan (_find_attribute) on every page.

The Attribute -> CatalogAttribute mapping is invariant across pages, so resolve
it once before the loop and reuse it.

JIRA: CQ-2677
risk: low
The Arrow conversion path ran four functions (convert_arrow_table_to_dataframe,
compute_row/column_totals_indexes, compute_primary_labels) on the same table,
each independently orjson-parsing the schema metadata blobs.

Parse the schema metadata once in the orchestrator and pass it into the functions
via an optional schema_meta parameter. The parsed metadata is treated as read-only
throughout, so sharing one instance is safe.

JIRA: CQ-2677
risk: low
reorder_grand_totals and compute_row_totals_indexes both figured out which
rows are totals by walking the __row_type column value by value in Python.
Letting pyarrow/numpy compare the whole column at once is faster and keeps
the code simpler.

JIRA: CQ-2677
risk: low
The Arrow indexed()/not_indexed() extraction (use_arrow=True) converted
every metric column into a Python list via to_pylist(), which pandas.DataFrame
then re-parsed back into a float64 block - an Arrow -> Python objects -> pandas
round-trip.

Return metric columns as numpy arrays (table.column(...).to_numpy(zero_copy_only=False))
so pandas consumes the numeric block directly.

Measured ~930x faster for 200 columns x 100k rows.

JIRA: CQ-2677
risk: low
convert_label_values converted date-granularity attribute columns one value at a time via pandas.to_datetime per scalar - the same per-scalar pitfall #1 fixed on the JSON path, and the last significant gap making the Arrow indexed/not_indexed path slower than JSON for date-heavy results.

For DateConverter/DatetimeConverter, parse each value with the cheap per-value to_type() and then run one pandas.to_datetime() over the whole column, restoring None for null rows to preserve the previous behaviour. WEEK/QUARTER and other granularities keep the straightforward per-value path. Measured ~13x faster on a 100k-row DAY column; identical values (verified across all granularities, nulls and empty input); covered by the existing convert_label_values and use_arrow tests.

JIRA: CQ-2677
risk: low
…t values

Building the primary-label mapping for a crosstab used to walk every row for
each attribute level and pull the whole label column into Python, even though
the mapping only ever needs the distinct values.

Instead, filter down to the data rows once and, when the primary and display
labels are the same (the usual case), build the map straight from the column's
distinct values, so repeated attribute values collapse up front. That is
roughly 30x faster for low-cardinality attributes - the typical pivot - and no
slower when every value is unique. When the primary and display labels differ,
the values are still paired up row by row.

The filter also keeps only the label columns it actually needs; otherwise it
would copy every metric column along with them, which is a lot of wasted memory
on wide results.

The output is unchanged, checked against the primary-label fixtures at both low
and high cardinality.

JIRA: CQ-2677
risk: low
Two targeted guards for the perf changes in this branch, each verified by
mutation to fail on the bug it protects against:

- _compute_primary_labels_from_inline with metric/grand-total columns and a
  total row present (primaryLabelId != labelId). Guards the column-projection
  optimization: a projection that drops a needed label column, or a filter that
  leaks total rows, would break it - and the existing separate-column test
  cannot catch either (its table has no extra columns and no total row).

- _typed_attribute_values date-granularity batching. The JSON exec_def
  cassettes only contain text attributes (granularity: null), so the vectorized
  date conversion was otherwise unexercised.

JIRA: CQ-2677
risk: low
The ty type checker cannot see pyarrow.compute functions (equal, not_equal,
any) because pyarrow generates them at runtime, so it reported them as
unresolved attributes. Mark those call sites with ty: ignore[unresolved-attribute]
and extract the masks into named locals so the lines stay within the format
limit and read clearly. No behavior change.

JIRA: CQ-2677
risk: low
perf(gooddata-pandas): speed up and slim down DataFrame conversion
@yenkins-admin
yenkins-admin merged commit 2356cf3 into rel/dev Jul 20, 2026
1 check passed
@yenkins-admin
yenkins-admin deleted the snapshot-master-56f00e1f-to-rel/dev branch July 20, 2026 08:15
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 716a19c5-4c42-4b15-b227-95365db75e2d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.05%. Comparing base (807d829) to head (56f00e1).
⚠️ Report is 543 commits behind head on rel/dev.

Additional details and impacted files
@@             Coverage Diff             @@
##           rel/dev    #1693      +/-   ##
===========================================
+ Coverage    78.02%   78.05%   +0.02%     
===========================================
  Files          271      271              
  Lines        18639    18669      +30     
===========================================
+ Hits         14544    14572      +28     
- Misses        4095     4097       +2     

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants