From 1d605e8f8ab46582bf009d1f2195554b01bcb4bd Mon Sep 17 00:00:00 2001 From: Peter Schafhalter Date: Thu, 12 Apr 2018 20:30:19 -0700 Subject: [PATCH] [DataFrame] Inherit documentation from Pandas (#1727) * Added _inherit_docstrings * DataFrame documentation inherits from Pandas * Fix formatting * Replace hasattr and document properties * Fix rebase * Override documentation for groupby * Override documentation for series * Don't overwrite property docstrings * Fix property __doc__ for python2 --- python/ray/dataframe/dataframe.py | 4 ++- python/ray/dataframe/groupby.py | 5 +++ python/ray/dataframe/series.py | 4 +++ python/ray/dataframe/test/test_dataframe.py | 11 ++++++ python/ray/dataframe/utils.py | 40 +++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/python/ray/dataframe/dataframe.py b/python/ray/dataframe/dataframe.py index c0e09d8ef..b68d050db 100644 --- a/python/ray/dataframe/dataframe.py +++ b/python/ray/dataframe/dataframe.py @@ -32,11 +32,13 @@ from .utils import ( to_pandas, _blocks_to_col, _blocks_to_row, - _create_block_partitions) + _create_block_partitions, + _inherit_docstrings) from . import get_npartitions from .index_metadata import _IndexMetadata +@_inherit_docstrings(pd.DataFrame) class DataFrame(object): def __init__(self, data=None, index=None, columns=None, dtype=None, diff --git a/python/ray/dataframe/groupby.py b/python/ray/dataframe/groupby.py index 26a789eb1..bec192cdf 100644 --- a/python/ray/dataframe/groupby.py +++ b/python/ray/dataframe/groupby.py @@ -2,7 +2,12 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import pandas.core.groupby +from .utils import _inherit_docstrings + + +@_inherit_docstrings(pandas.core.groupby.DataFrameGroupBy) class DataFrameGroupBy(object): def __init__(self, partitions, columns, index): diff --git a/python/ray/dataframe/series.py b/python/ray/dataframe/series.py index eea7f7bbb..dbbac7993 100644 --- a/python/ray/dataframe/series.py +++ b/python/ray/dataframe/series.py @@ -3,6 +3,9 @@ from __future__ import division from __future__ import print_function import numpy as np +import pandas as pd + +from .utils import _inherit_docstrings def na_op(): @@ -11,6 +14,7 @@ def na_op(): raise NotImplementedError("Not Yet implemented.") +@_inherit_docstrings(pd.Series) class Series(object): def __init__(self, series_oids): diff --git a/python/ray/dataframe/test/test_dataframe.py b/python/ray/dataframe/test/test_dataframe.py index 7a323a33b..8b1810818 100644 --- a/python/ray/dataframe/test/test_dataframe.py +++ b/python/ray/dataframe/test/test_dataframe.py @@ -3014,3 +3014,14 @@ def test_iloc(ray_df, pd_df): assert ray_df.iloc[1:, 0].equals(pd_df.iloc[1:, 0]) assert ray_df.iloc[1:2, 0].equals(pd_df.iloc[1:2, 0]) assert ray_df.iloc[1:2, 0:2].equals(pd_df.iloc[1:2, 0:2]) + + +def test__doc__(): + assert rdf.DataFrame.__doc__ != pd.DataFrame.__doc__ + assert rdf.DataFrame.__init__ != pd.DataFrame.__init__ + for attr, obj in rdf.DataFrame.__dict__.items(): + if (callable(obj) or isinstance(obj, property)) \ + and attr != "__init__": + pd_obj = getattr(pd.DataFrame, attr, None) + if callable(pd_obj) or isinstance(pd_obj, property): + assert obj.__doc__ == pd_obj.__doc__ diff --git a/python/ray/dataframe/utils.py b/python/ray/dataframe/utils.py index 458935dd6..10382984c 100644 --- a/python/ray/dataframe/utils.py +++ b/python/ray/dataframe/utils.py @@ -242,3 +242,43 @@ def _blocks_to_row(*partition): # columns), this change is needed to ensure correctness. row_part.columns = pd.RangeIndex(0, len(row_part.columns)) return row_part + + +def _inherit_docstrings(parent): + """Creates a decorator which overwrites a decorated class' __doc__ + attribute with parent's __doc__ attribute. Also overwrites __doc__ of + methods and properties defined in the class with the __doc__ of matching + methods in parent. + + Args: + parent (object): Class from which the decorated class inherits __doc__. + + Note: + Currently does not override class' __doc__ or __init__'s __doc__. + + Todo: + Override the class' __doc__ and __init__'s __doc__ once DataFrame's + __init__ method matches pandas.DataFrame's __init__ method. + + Returns: + function: decorator which replaces the decorated class' documentation + parent's documentation. + """ + def decorator(cls): + # cls.__doc__ = parent.__doc__ + for attr, obj in cls.__dict__.items(): + if attr == "__init__": + continue + parent_obj = getattr(parent, attr, None) + if not callable(parent_obj) and \ + not isinstance(parent_obj, property): + continue + if callable(obj): + obj.__doc__ = parent_obj.__doc__ + elif isinstance(obj, property) and obj.fget is not None: + p = property(obj.fget, obj.fset, obj.fdel, parent_obj.__doc__) + setattr(cls, attr, p) + + return cls + + return decorator