Skip to content

Fix DataFrame.rename for an unnamed MultiIndex level - #23062

Merged
rapids-bot[bot] merged 6 commits into
NVIDIA:mainfrom
galipremsagar:midx-rename
Jul 2, 2026
Merged

Fix DataFrame.rename for an unnamed MultiIndex level#23062
rapids-bot[bot] merged 6 commits into
NVIDIA:mainfrom
galipremsagar:midx-rename

Conversation

@galipremsagar

Copy link
Copy Markdown
Contributor

Description

Split out of #22966 per review feedback.

DataFrame.rename(index=..., level=...) on a MultiIndex with an unnamed level previously inserted a spurious extra level instead of overwriting the target level: the level name (None for an unnamed level) was used as the ColumnAccessor key. It now resolves to the positional ColumnAccessor label via MultiIndex._level_to_ca_label, restores the original level names afterward, and forwards all_nan to find_and_replace so all-null replacements behave like the non-level path.

Adds a cuDF unit test and removes the now-passing cudf.pandas xfail entry.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@galipremsagar
galipremsagar requested a review from a team as a code owner July 1, 2026 04:17
@copy-pr-bot

copy-pr-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added Python Affects Python cuDF API. cudf.pandas Issues specific to cudf.pandas labels Jul 1, 2026
@GPUtester GPUtester moved this to In Progress in cuDF Python Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved DataFrame.rename for MultiIndex when renaming a specific level, correctly updating only the targeted level without adding an extra level.
    • Correctly handles unnamed MultiIndex levels and cases where replacement values are all null.
    • Preserves the original MultiIndex level names after renaming to avoid unexpected index name changes.

Walkthrough

This PR updates MultiIndex level renaming so targeted values are overwritten in place, preserves index level names after rebuilding, adds coverage for unnamed MultiIndex cases, and removes a related test-plugin exclusion entry.

Changes

MultiIndex Level Rename Fix

Layer / File(s) Summary
Level rename logic and value replacement
python/cudf/cudf/core/dataframe.py
DataFrame.rename resolves the target level to a ColumnAccessor label, replaces values with find_and_replace, handles all-None replacements, rebuilds the index, and restores the original level names.
Test coverage and exclusion removal
python/cudf/cudf/tests/dataframe/methods/test_rename.py, python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
Adds a parametrized unnamed-MultiIndex rename test that checks overwrite behavior and nlevels, updates the SPDX header year range, and removes the related pandas-testing-plugin exclusion entry.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: fixing DataFrame.rename for an unnamed MultiIndex level.
Description check ✅ Passed The description is directly related to the changeset and accurately summarizes the fix, test, and xfail cleanup.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/cudf/cudf/core/dataframe.py`:
- Around line 4242-4256: The MultiIndex `level` rename path in
`DataFrame.rename` is missing the same `OverflowError` suppression used in the
non-level branch, so `errors='ignore'` can still raise from `find_and_replace`.
Update the `level is not None and isinstance(self.index, MultiIndex)` branch to
catch `OverflowError` around the `level_values._column.find_and_replace(...)`
call and return the original object when `errors='ignore'`, matching the
existing rename behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 20b4d10b-2a78-4861-8682-cd576f5729ff

📥 Commits

Reviewing files that changed from the base of the PR and between bd7bb74 and 48b2cd7.

📒 Files selected for processing (3)
  • python/cudf/cudf/core/dataframe.py
  • python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
  • python/cudf/cudf/tests/dataframe/methods/test_rename.py
💤 Files with no reviewable changes (1)
  • python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py

Comment on lines 4242 to 4256
if level is not None and isinstance(self.index, MultiIndex):
level = self.index._get_level_label(level)
# Resolve to the ColumnAccessor label (e.g. the positional key
# ``0`` for an unnamed level), NOT the level *name* (which is
# ``None`` for unnamed levels and would insert a spurious extra
# column rather than overwrite the level being renamed).
ca_label, _ = self.index._level_to_ca_label(level)
level_values = self.index.get_level_values(level)
ca = self.index._data.copy(deep=copy)
ca[level] = level_values._column.find_and_replace(
vals = list(index.values())
is_all_na = all(val is None for val in vals)
ca[ca_label] = level_values._column.find_and_replace(
to_replace=list(index.keys()),
replacement=list(index.values()),
replacement=vals,
all_nan=is_all_na,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="python/cudf/cudf/core/dataframe.py"

# Show the relevant region with line numbers
sed -n '4225,4295p' "$file" | cat -n

# Also inspect the sibling branch around the documented try/except
sed -n '4258,4288p' "$file" | cat -n

Repository: rapidsai/cudf

Length of output: 4914


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="python/cudf/cudf/core/dataframe.py"

# Inspect method signature/docstring and surrounding control flow
sed -n '4170,4255p' "$file" | cat -n

Repository: rapidsai/cudf

Length of output: 3607


Add the OverflowError guard to the MultiIndex level rename path.

The errors='ignore' path already suppresses OverflowError in the non-level branch, but this MultiIndex-level branch doesn’t. If find_and_replace overflows here, rename(..., errors='ignore') will raise instead of returning the original object.

Fix
-                ca[ca_label] = level_values._column.find_and_replace(
-                    to_replace=list(index.keys()),
-                    replacement=vals,
-                    all_nan=is_all_na,
-                )
-                out_index = type(self.index)._from_data(
-                    ca, name=self.index.name
-                )
-                out_index.names = self.index.names
+                try:
+                    ca[ca_label] = level_values._column.find_and_replace(
+                        to_replace=list(index.keys()),
+                        replacement=vals,
+                        all_nan=is_all_na,
+                    )
+                    out_index = type(self.index)._from_data(
+                        ca, name=self.index.name
+                    )
+                    out_index.names = self.index.names
+                except OverflowError:
+                    pass
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf/cudf/core/dataframe.py` around lines 4242 - 4256, The MultiIndex
`level` rename path in `DataFrame.rename` is missing the same `OverflowError`
suppression used in the non-level branch, so `errors='ignore'` can still raise
from `find_and_replace`. Update the `level is not None and
isinstance(self.index, MultiIndex)` branch to catch `OverflowError` around the
`level_values._column.find_and_replace(...)` call and return the original object
when `errors='ignore'`, matching the existing rename behavior.

@galipremsagar

Copy link
Copy Markdown
Contributor Author

/okay to test 8fe27b7

@galipremsagar galipremsagar added bug Something isn't working non-breaking Non-breaking change 5 - Ready to Merge Testing and reviews complete, ready to merge labels Jul 1, 2026
@galipremsagar

Copy link
Copy Markdown
Contributor Author

/okay to test b722630

@galipremsagar

Copy link
Copy Markdown
Contributor Author

/okay to test 129ca6a

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
python/cudf/cudf/core/dataframe.py (1)

4234-4241: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale pandas-compat note: "Not Supporting: level" contradicts the implemented level-based MultiIndex rename.

This unchanged docstring note predates (and is now more clearly contradicted by) the level-handling logic below and the top-level level parameter documentation (lines 4192-4193). Consider removing/updating it in a follow-up so users aren't misled into thinking level is unsupported.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudf/cudf/core/dataframe.py` around lines 4234 - 4241, The
pandas-compat note in DataFrame.rename is stale because it still says “Not
Supporting: level” even though the rename implementation and the level parameter
docs already support level-based MultiIndex renaming. Update or remove that note
in DataFrame.rename so it matches the behavior exposed by the level handling
logic and the documented level parameter.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@python/cudf/cudf/core/dataframe.py`:
- Around line 4234-4241: The pandas-compat note in DataFrame.rename is stale
because it still says “Not Supporting: level” even though the rename
implementation and the level parameter docs already support level-based
MultiIndex renaming. Update or remove that note in DataFrame.rename so it
matches the behavior exposed by the level handling logic and the documented
level parameter.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 77931d7a-1c97-4b5a-9892-5c64aed5f6f6

📥 Commits

Reviewing files that changed from the base of the PR and between b722630 and 129ca6a.

📒 Files selected for processing (2)
  • python/cudf/cudf/core/dataframe.py
  • python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py
✅ Files skipped from review due to trivial changes (1)
  • python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py

@galipremsagar

Copy link
Copy Markdown
Contributor Author

/okay to test 5b8620c

@galipremsagar

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 0732eaa into NVIDIA:main Jul 2, 2026
126 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in cuDF Python Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5 - Ready to Merge Testing and reviews complete, ready to merge bug Something isn't working cudf.pandas Issues specific to cudf.pandas non-breaking Non-breaking change Python Affects Python cuDF API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants