Repository: modin-project/modin

Issue:
BUG: BasePandasDataset tries to inherit custom docstrings from DataFrame instead of from a separate base class
Modin's `BasePandasDataset` inherits docstrings from `pandas.DataFrame`, so any docstring overrides for dataframe affect `BasePandasDataset`. Some options:

1.  we could have the base dataset inherit from the pandas base class instead, but that might change some existing docstrings
2. we could explicitly choose a parent docstring class for BasePandasDataset in _inherit_docstrings
3. we could accept some incorrect docstrings in BasePandasDataset

@devin-petersohn and I prefer option 2)

Discussion:

Patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
index 51c9cd81..04dd8459 100644
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -99,7 +99,13 @@ sentinel = object()
 
 # Do not lookup certain attributes in columns or index, as they're used for some
 # special purposes, like serving remote context
-_ATTRS_NO_LOOKUP = {"__name__", "_cache"}
+_ATTRS_NO_LOOKUP = {
+    "__name__",
+    "_cache",
+    "_ipython_canary_method_should_not_exist_",
+    "_ipython_display_",
+    "_repr_mimebundle_",
+}
 
 _DEFAULT_BEHAVIOUR = {
     "__init__",
diff --git a/modin/utils.py b/modin/utils.py
index 34071be1..86237326 100644
--- a/modin/utils.py
+++ b/modin/utils.py
@@ -462,7 +462,18 @@ def _inherit_docstrings_in_place(
     if doc_module != DocModule.default and "pandas" in str(
         getattr(parent, "__module__", "")
     ):
-        parent = getattr(imported_doc_module, getattr(parent, "__name__", ""), parent)
+        parent_name = (
+            # DocModule should use the class BasePandasDataset to override the
+            # docstrings of BasePandasDataset, even if BasePandasDataset
+            # normally inherits docstrings from a different `parent`.
+            "BasePandasDataset"
+            if getattr(cls_or_func, "__name__", "") == "BasePandasDataset"
+            # For other classes, override docstrings with the class that has the
+            # same name as the `parent` class, e.g. DataFrame inherits
+            # docstrings from doc_module.DataFrame.
+            else getattr(parent, "__name__", "")
+        )
+        parent = getattr(imported_doc_module, parent_name, parent)
     if parent != default_parent:
         # Reset API link in case the docs are overridden.
         apilink = None


Test patch:
diff --git a/modin/tests/config/docs_module/__init__.py b/modin/tests/config/docs_module/__init__.py
index aa21549f..5f617d68 100644
--- a/modin/tests/config/docs_module/__init__.py
+++ b/modin/tests/config/docs_module/__init__.py
@@ -11,7 +11,7 @@
 # ANY KIND, either express or implied. See the License for the specific language
 # governing permissions and limitations under the License.
 
-from .classes import DataFrame, Series
+from .classes import BasePandasDataset, DataFrame, Series
 from .functions import read_csv
 
-__all__ = ["DataFrame", "Series", "read_csv"]
+__all__ = ["BasePandasDataset", "DataFrame", "Series", "read_csv"]
diff --git a/modin/tests/config/docs_module/classes.py b/modin/tests/config/docs_module/classes.py
index 8dc152e2..235c99bd 100644
--- a/modin/tests/config/docs_module/classes.py
+++ b/modin/tests/config/docs_module/classes.py
@@ -22,3 +22,11 @@ class Series:
     def isna(self):
         """This is a test of the documentation module for Series."""
         return
+
+
+class BasePandasDataset:
+    """This is a test of the documentation module for BasePandasDataSet."""
+
+    def apply():
+        """This is a test of the documentation module for BasePandasDataSet.apply."""
+        return
diff --git a/modin/tests/config/test_envvars.py b/modin/tests/config/test_envvars.py
index 384bd5f1..d057ecb0 100644
--- a/modin/tests/config/test_envvars.py
+++ b/modin/tests/config/test_envvars.py
@@ -20,6 +20,7 @@ import modin.config as cfg
 import modin.pandas as pd
 from modin.config.envvars import _check_vars
 from modin.config.pubsub import _UNSET, ExactStr
+from modin.pandas.base import BasePandasDataset
 
 
 def reset_vars(*vars: tuple[cfg.Parameter]):
@@ -89,6 +90,12 @@ class TestDocModule:
         cfg.DocModule.put("modin.tests.config.docs_module")
 
         # Test for override
+        assert BasePandasDataset.__doc__ == (
+            "This is a test of the documentation module for BasePandasDataSet."
+        )
+        assert BasePandasDataset.apply.__doc__ == (
+            "This is a test of the documentation module for BasePandasDataSet.apply."
+        )
         assert (
             pd.DataFrame.apply.__doc__
             == "This is a test of the documentation module for DataFrame."
@@ -96,6 +103,7 @@ class TestDocModule:
         # Test for pandas doc when method is not defined on the plugin module
         assert pandas.DataFrame.isna.__doc__ in pd.DataFrame.isna.__doc__
         assert pandas.DataFrame.isnull.__doc__ in pd.DataFrame.isnull.__doc__
+        assert BasePandasDataset.astype.__doc__ in pd.DataFrame.astype.__doc__
         # Test for override
         assert (
             pd.Series.isna.__doc__