Skip to content

Remove special Index class from the general index class hierarchy - #8309

Merged
rapids-bot[bot] merged 10 commits into
NVIDIA:branch-21.08from
vyasr:refactor/index_meta
Jun 9, 2021
Merged

rapids-bot[bot] merged 10 commits into
NVIDIA:branch-21.08from
vyasr:refactor/index_meta

Conversation

@vyasr

@vyasr vyasr commented May 21, 2021

Copy link
Copy Markdown
Contributor

Renames the old Index class to BaseIndex as the parent for all index types and creates a new Index class that subclasses BaseIndex to provide the expected API for cudf.Index. The critical change is that this class has a custom metaclass to make it look like BaseIndex from an inheritance perspective, and it takes on the __new__ method that allows it to return different Index types depending on the input. This change will allow us to rewrite the hierarchy of different Index types in much simpler, more robust, and more performant ways. In particular, we will no longer have to override __new__ in those classes, we will be able to make use of __init__ rather than the custom _initialize method we are currently using, and we reduce ambiguities with respect to which and how many __new__ and __init__ methods are called.

@vyasr
vyasr requested a review from a team as a code owner May 21, 2021 00:07
@vyasr
vyasr requested review from galipremsagar and shwina May 21, 2021 00:07
@github-actions github-actions Bot added the Python Affects Python cuDF API. label May 21, 2021
@vyasr vyasr added 3 - Ready for Review Ready for review by team improvement Improvement / enhancement to an existing function non-breaking Non-breaking change tech debt 0 - Blocked Cannot progress due to external reasons and removed 3 - Ready for Review Ready for review by team labels May 21, 2021
@vyasr

vyasr commented May 21, 2021

Copy link
Copy Markdown
Contributor Author

This should be a non-breaking change, but should be reviewed carefully for edge cases where this solution fails. It will also need to be rebased once the forward merge of 21.06 brings the changes from #8254 onto 21.08, since this relies on that PR.

@shwina

shwina commented May 23, 2021

Copy link
Copy Markdown
Contributor

Note that users who subclass cudf.Index will run into some nasty behaviour:

In [10]: class MyIndex(cudf.Index):
    ...:     pass
    ...:

In [11]: isinstance(cudf.StringIndex(), MyIndex)
True  # !!!

What they should do is subclass cudf.BaseIndex instead. We should probably call this out loudly in our docs for Index.

@shwina

shwina commented May 23, 2021

Copy link
Copy Markdown
Contributor

This should be a non-breaking change

I think the above makes this a breaking change, as any existing user code that subclasses cudf.Index will need to. be changed.

@vyasr

vyasr commented May 24, 2021

Copy link
Copy Markdown
Contributor Author

I think that's a valid concern. I have two main reasons why I think this is OK to do and shouldn't prevent us from moving forward with this PR.

First, someone who subclassed pd.Index in their code and then try to use cudf.Index as a drop-in replacement would already see errors because our internal structures are different. Subclassing pd.Index is already a bit of a minefield: it's not documented on the official pandas documentation of Subclassing pandas data structures, and there are lots of "internal" details that have to be handled by subclasses as documented in this open issue. For those reasons, I don't think promising compatibility with pandas at the level of subclassing Index is something we should even attempt because it requires more than API promises, it requires our internal implementation details to conform to pandas internals as well.

Second, subclassing Index (or any of its subclasses) in its current form is already very difficult, and we don't currently make any promises regarding how to do this (or even document these requirements). At minimum users need to:

  1. Override __new__ rather than __init__.
  2. Call the correct parent's __new__ method, which for now is equivalent to object.__new__ but is also not documented and is subject to change if we modify any of the parent __new__ methods for any reason.
  3. Call _initialize if extending a subclass of Index (e.g. Int64Index) rather than Index itself.
  4. Avoid putting any logic in __init__ for performance reasons (because it would be called twice), and absolutely avoid putting any logic in __init__ that is not idempotent because then the second call will fail.

For those reasons, I think we would be justified in just telling users that instead of subclassing Index they should subclass BaseIndex, which will ultimately provide an easier path than pandas does to extending the class.

@shwina

shwina commented May 25, 2021

Copy link
Copy Markdown
Contributor

Understood. Let's add a note along these lines in the cudf.Index docs:

Do not subclass cudf.Index. If you absolutely must, and if you're intimately familiar with the internals of cuDF, subclass cudf.BaseIndex instead.

If nothing, it will serve as a reminder to internal developers...

@vyasr

vyasr commented May 25, 2021

Copy link
Copy Markdown
Contributor Author

If you like, I think that we could explicitly prohibit this with an assert cls is Index in Index.__new__. That would prevent Index.__new__ being called by any subclasses.

@shwina

shwina commented May 25, 2021

Copy link
Copy Markdown
Contributor

I'd be +1 for that

@vyasr vyasr added breaking Breaking change and removed non-breaking Non-breaking change labels May 25, 2021
@vyasr

vyasr commented May 25, 2021

Copy link
Copy Markdown
Contributor Author

I'd be +1 for that

Done. Of course this won't save us from subclasses that actually override __new__, but if someone knows enough to override __new__ rather than __init__ and still chooses to move forward I'm fine saying they're on their own.

@vyasr
vyasr force-pushed the refactor/index_meta branch from 12bd233 to 18995b7 Compare May 25, 2021 23:13
@vyasr vyasr added 3 - Ready for Review Ready for review by team and removed 0 - Blocked Cannot progress due to external reasons labels May 25, 2021
@vyasr vyasr self-assigned this May 25, 2021
@shwina

shwina commented May 26, 2021

Copy link
Copy Markdown
Contributor

rerun tests

@vyasr

vyasr commented May 26, 2021

Copy link
Copy Markdown
Contributor Author

This is blocked by rapidsai/integration#282, which is necessary to run 21.08 tests. Once that's merged tests can be rerun.

@vyasr

vyasr commented Jun 1, 2021

Copy link
Copy Markdown
Contributor Author

rerun tests

@vyasr

vyasr commented Jun 1, 2021

Copy link
Copy Markdown
Contributor Author

Integration PR is now merged, but this PR is now blocked by #8419 .

@codecov

codecov Bot commented Jun 8, 2021

Copy link
Copy Markdown

Codecov Report

❗ No coverage uploaded for pull request base (branch-21.08@90e29d9). Click here to learn what that means.
The diff coverage is n/a.

❗ Current head 0f8bbb6 differs from pull request most recent head 6e53634. Consider uploading reports for the commit 6e53634 to get more accurate results
Impacted file tree graph

@@               Coverage Diff               @@
##             branch-21.08    #8309   +/-   ##
===============================================
  Coverage                ?   82.85%           
===============================================
  Files                   ?      109           
  Lines                   ?    17920           
  Branches                ?        0           
===============================================
  Hits                    ?    14847           
  Misses                  ?     3073           
  Partials                ?        0           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 90e29d9...6e53634. Read the comment docs.

@shwina shwina 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.

LGTM

@vyasr
vyasr requested a review from a team as a code owner June 9, 2021 17:26

@quasiben quasiben 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.

Thanks @vyasr . If @rjzamora has time it would be good to get his sign off as well though I think the changes are good

@rjzamora rjzamora 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.

I only looked at the minor dask_cudf changes and the index.py changes. This seems fine to me :)

@vyasr vyasr changed the title Remove special Index class out of the general index class hierarchy Remove special Index class from the general index class hierarchy Jun 9, 2021
@vyasr

vyasr commented Jun 9, 2021

Copy link
Copy Markdown
Contributor Author

@gpucibot merge

@rapids-bot
rapids-bot Bot merged commit e448675 into NVIDIA:branch-21.08 Jun 9, 2021
rapids-bot Bot pushed a commit that referenced this pull request Jun 18, 2021
The changes in #8309 allow us to avoid overriding `__new__` for all index types and instead use the more standard `__init__`, which also makes it easier to share logic between different index classes via typical inheritance patterns.

Authors:
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - Ashwin Srinath (https://github.com/shwina)
  - GALI PREM SAGAR (https://github.com/galipremsagar)

URL: #8485
@vyasr vyasr added this to the cuDF Python Refactoring milestone Jul 22, 2021
rapids-bot Bot pushed a commit to rapidsai/dask-cuda that referenced this pull request Sep 2, 2021
Fixes: #715 

With the recent `cudf` refactor done in NVIDIA/cudf#8309, we will need to update `cudf.Index` to `cudf.BaseIndex` at these places.

Authors:
  - GALI PREM SAGAR (https://github.com/galipremsagar)

Approvers:
  - Benjamin Zaitlen (https://github.com/quasiben)

URL: #718
@vyasr
vyasr deleted the refactor/index_meta branch January 14, 2022 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3 - Ready for Review Ready for review by team breaking Breaking change improvement Improvement / enhancement to an existing function Python Affects Python cuDF API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants