Repository: pyjanitor-devs/pyjanitor

Issue:
Inconsistent docstrings on functions returning Pandas Dataframes
Many return docstrings on functions returning Pandas Dataframes in functions.py are inconsistent.

ex: 
```
def min_max_scale(~):
"""
:returns: df
"""

def coalesce(df, columns, new_column_name):
"""
:returns: A pandas DataFrame.
"""
```


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -31,7 +31,7 @@ def _strip_underscores(df, strip_underscores=None):
         column names. Default None keeps outer underscores. Values can be
         either 'left', 'right' or 'both' or the respective shorthand 'l', 'r'
         and True.
-    :returns: A pandas DataFrame.
+    :returns: A pandas DataFrame with underscores removed.
     """
     underscore_options = [None, "left", "right", "both", "l", "r", True]
     if strip_underscores not in underscore_options:
@@ -242,7 +242,6 @@ def encode_categorical(df, column_names=None, **kwargs):
     :returns: A pandas DataFrame
 
     .. _category: http://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html  # noqa: E501
-
     """
     if kwargs and column_names is not None:
         raise TypeError("Mixed usage of columns and column_names")
@@ -297,9 +296,9 @@ def label_encode(df, column_names=None, **kwargs):
         df = pd.DataFrame(...).label_encode(column_names=categorical_cols)
 
     :param df: The pandas DataFrame object.
-    :param str/iterable column_names: A column name or an iterable (list or
-        tuple) of column names.
-    :returns: A pandas DataFrame
+    :param str/iterable columns: A column name or an iterable (list or tuple)
+        of column names.
+    :returns: A pandas DataFrame.
     """
     if kwargs and column_names is not None:
         raise TypeError("Mixed usage of columns and column_names")
@@ -403,7 +402,7 @@ def rename_column(df, old, new):
 
     :param str old: The old column name.
     :param str new: The new column name.
-    :returns: A pandas DataFrame.
+    :returns: A pandas DataFrame with renamed columns.
     """
     if old not in df.columns:
         raise ValueError(f"{old} not present in dataframe columns!")
@@ -445,7 +444,7 @@ def reorder_columns(
     :param df: `DataFrame` to reorder
     :param column_order: A list of column names or Pandas `Index`
         specifying their order in the returned `DataFrame`.
-    :returns: A pandas DataFrame.
+    :returns: A pandas DataFrame with reordered columns.
     """
 
     check("column_order", column_order, [list, pd.Index])
@@ -498,7 +497,7 @@ def coalesce(df, columns, new_column_name):
     :param df: A pandas DataFrame.
     :param columns: A list of column names.
     :param str new_column_name: The new column name after combining.
-    :returns: A pandas DataFrame.
+    :returns: A pandas DataFrame with coalesced columns.
     """
     series = [df[c] for c in columns]
 
@@ -657,6 +656,7 @@ def fill_empty(df, columns, value):
         in, then only that column will be filled; if a list or tuple of strings
         are passed in, then they will all be filled with the same value.
     :param value: The value that replaces the `NaN` values.
+    :returns: A pandas DataFrame with `Nan` values filled.
     """
     if isinstance(columns, list) or isinstance(columns, tuple):
         for col in columns:
@@ -704,6 +704,7 @@ def expand_column(df, sep, column_name=None, concat=True, **kwargs):
     :param bool concat: Whether to return the expanded column concatenated to
         the original dataframe (`concat=True`), or to return it standalone
         (`concat=False`).
+    :returns: A pandas DataFrame with an expanded column.
     """
     if kwargs and column_name is not None:
         raise TypeError("Mixed usage of column and column_name")
@@ -749,6 +750,7 @@ def concatenate_columns(
     :param columns: A list of columns to concatenate together.
     :param new_column_name: The name of the new column.
     :param sep: The separator between each column's data.
+    :returns: A pandas DataFrame with concatenated columns.
     """
     assert len(columns) >= 2, "At least two columns must be specified"
     for i, col in enumerate(columns):
@@ -793,6 +795,7 @@ def deconcatenate_column(df, column: str, new_column_names: List, sep: str):
     :param column: The column to split.
     :param new_column_names: A list of new column names post-splitting.
     :param sep: The separator delimiting the column's data.
+    :returns: A pandas DataFrame with a deconcatenated column.
     """
     assert (
         column in df.columns
@@ -860,6 +863,7 @@ def filter_string(
     :param column: The column to filter. The column should contain strings.
     :param search_string: A regex pattern or a (sub-)string to search.
     :param complement: Whether to return the complement of the filter or not.
+    :returns: A filtered pandas DataFrame.
     """
     criteria = df[column].str.contains(search_string)
     if complement:
@@ -920,6 +924,7 @@ def filter_on(df, criteria, complement=False):
     :param criteria: A filtering criteria that returns an array or Series of\
         booleans, on which pandas can filter on.
     :param complement: Whether to return the complement of the filter or not.
+    :returns: A filtered pandas DataFrame.
     """
     if complement:
         return df.query("not " + criteria)
@@ -968,6 +973,7 @@ def filter_date(
     recognized natively by pandas' to_datetime function, you may supply the\
     format yourself. Python date and time formats may be found at\
     http://strftime.org/.'
+    :returns: A filtered pandas DataFrame.
 
     **Note:** This only affects the format of the `start` and `end` parameters.
      If there's an issue with the format of the DataFrame being parsed, you
@@ -1189,6 +1195,7 @@ def filter_column_isin(
         Series.
     :param complement: Whether to return the complement of the selection or
         not.
+    :returns: A filtered pandas DataFrame.
     """
     if len(iterable) == 0:
         raise ValueError(
@@ -1217,6 +1224,7 @@ def remove_columns(df: pd.DataFrame, columns: List):
 
     :param df: A pandas DataFrame
     :param columns: The columns to remove.
+    :returns: A pandas DataFrame.
     """
     return df.drop(columns=columns)
 
@@ -1246,6 +1254,7 @@ def change_type(df, column: str, dtype, ignore_exception=False):
     :param dtype: The datatype to convert to. Should be one of the standard
         Python types, or a numpy datatype.
     :param ignore_exception: one of {False, "fillna", "keep_values"}.
+    :returns: A pandas DataFrame with changed column types.
     """
     if not ignore_exception:
         df[column] = df[column].astype(dtype)
@@ -1297,6 +1306,7 @@ def add_column(df, col_name: str, value, fill_remaining: bool = False):
     :param fill_remaining: If value is a tuple or list that is smaller than
         the number of rows in the DataFrame, repeat the list or tuple
         (R-style) to the end of the DataFrame.
+    :returns: A pandas DataFrame with an added column.
 
     :Setup:
 
@@ -1453,6 +1463,7 @@ def add_columns(df: pd.DataFrame, fill_remaining: bool = False, **kwargs):
         (R-style) to the end of the DataFrame. (Passed to `add_column`)
     :param kwargs: column, value pairs which are looped through in
         `add_column` calls.
+    :returns: A pandas DataFrame with added columns.
     """
 
     # Note: error checking can pretty much be handled in `add_column`
@@ -1483,6 +1494,7 @@ def limit_column_characters(df, column_length: int, col_separator: str = "_"):
         values. I think an underscore looks nicest, however a period is a
         common option as well. Supply an empty string (i.e. '') to remove the
         separator.
+    :returns: A pandas DataFrame with truncated column lengths.
 
     :Example Setup:
 
@@ -1598,6 +1610,7 @@ def row_to_names(
         Defaults to False.
     :param remove_rows_above: Whether the rows above the selected row should
         be removed from the DataFrame. Defaults to False.
+    :returns: A pandas DataFrame with set column names.
 
     :Setup:
 
@@ -1705,6 +1718,7 @@ def round_to_fraction(
     :param denominator: The denominator of the fraction for rounding
     :param digits: The number of digits for rounding after rounding to the
         fraction. Default is np.inf (i.e. no subsequent rounding)
+    :returns: A pandas DataFrame with a column's values rounded.
 
     Taken from https://github.com/sfirke/janitor/issues/235
 
@@ -1849,6 +1863,7 @@ def transform_column(df, col_name: str, function, dest_col_name: str = None):
     :param function: A function to apply on the column.
     :param dest_col_name: The column name to store the transformation result
         in. By default, replaces contents of original column.
+    :returns: A pandas DataFrame with a transformed column.
     """
 
     if dest_col_name is None:
@@ -1925,6 +1940,7 @@ def transform_columns(
         the transformed values.
     :param new_names: (optional) An explicit mapping of old column names to
         new column names.
+    :returns: A pandas DataFrame with transformed columns.
     """
     dest_col_names = dict(zip(columns, columns))
 
@@ -2013,7 +2029,7 @@ def min_max_scale(
     :param new_min, new_max (optional): The minimum and maximum values of the
         data after it has been scaled.
     :param col_name (optional): The column on which to perform scaling.
-    :returns: df
+    :returns: A pandas DataFrame with scaled data.
     """
     if (
         (old_min is not None)
@@ -2085,7 +2101,7 @@ def collapse_levels(df: pd.DataFrame, sep: str = "_"):
 
     :param df: A pandas DataFrame.
     :param sep: String separator used to join the column level names
-    :returns: df
+    :returns: A flattened pandas DataFrame.
     """
 
     check("sep", sep, [str])
@@ -2142,7 +2158,7 @@ def reset_index_inplace(df: pd.DataFrame, *args, **kwargs):
     :param df: A pandas DataFrame.
     :param args: Arguments supplied to `DataFrame.reset_index()`
     :param kwargs: Arguments supplied to `DataFrame.reset_index()`
-    :returns: df
+    :returns: A pandas DataFrame with reset indexes.
     """
 
     # Deprecation Warning
@@ -2168,6 +2184,7 @@ def check(varname: str, value, expected_types: list):
     :param varname: The name of the variable.
     :param value: The value of the varname.
     :param expected_types: The types we expect the item to be.
+    :returns: TypeError if data is not the expected type.
     """
     is_expected_type = False
     for t in expected_types:
@@ -2189,6 +2206,8 @@ def _clean_accounting_column(x):
     attribute in currency_column_to_numeric.
 
     It is intended to be used in a pandas `apply` method.
+
+    :returns: An object with a cleaned column.
     """
 
     y = x.strip()
@@ -2282,7 +2301,7 @@ def currency_column_to_numeric(
         make everything that doesn't coerce to a currency 1.
     :param remove_non_numeric: Will remove rows of a DataFrame that contain
         non-numeric values in the `col_name` column. Defaults to `False`.
-    :return: A mutated DataFrame
+    :returns: A mutated DataFrame.
 
     :Example Setup:
 
@@ -2493,7 +2512,7 @@ def select_columns(df: pd.DataFrame, search_cols: List, invert: bool = False):
     :param invert: Whether or not to invert the selection.
         This will result in selection of the complement of the columns\
         provided.
-    :returns: A pandas DataFrame with the columns selected.
+    :returns: A pandas DataFrame with the specified columns selected.
     """
 
     full_column_list = []
@@ -2552,6 +2571,7 @@ def impute(df, column: str, value=None, statistic=None):
     :param column: The name of the column on which to impute values.
     :param value: (optional) The value to impute.
     :param statistic: (optional) The column statistic to impute.
+    :returns: An imputed pandas DataFrame.
     """
 
     # Firstly, we check that only one of `value` or `statistic` are provided.
@@ -2601,6 +2621,7 @@ def then(df: pd.DataFrame, func) -> pd.DataFrame:
         It should take one parameter and return one parameter, each being the
         DataFrame object. After that, do whatever you want in the middle.
         Go crazy.
+    :returns: A pandas DataFrame.
     """
     df = func(df)
     return df
@@ -2619,6 +2640,7 @@ def dropnotnull(df, column: str):
 
     :param column: The column name to drop rows from.
     :param df: A pandas DataFrame.
+    :returns: A pandas DataFrame with dropped rows.
     """
     return df[pd.isnull(df[column])]
 
@@ -2648,6 +2670,7 @@ def find_replace(df: pd.DataFrame, column: str, mapper: dict):
     :param column: The column on which the find/replace action is to be made.
     :param mapper: A dictionary that maps "thing to find" -> "thing to
         replace".
+    :returns: A pandas DataFrame.
     """
     df[column] = df[column].apply(lambda x: mapper.get(x, x))
     return df
@@ -2684,6 +2707,7 @@ def update_where(
         and target value
     :param target_col: Column to be updated
     :param target_val: Value to be updated
+    :returns: An updated pandas DataFrame.
     """
     df.loc[conditions, target_col] = target_val
     return df
@@ -2712,7 +2736,7 @@ def to_datetime(df: pd.DataFrame, column: str, **kwargs) -> pd.DataFrame:
     :param df: A pandas DataFrame.
     :param column: Column name.
     :param kwargs: provide any kwargs that pd.to_datetime can take.
-    :returns: A pandas DataFrame.
+    :returns: A pandas DataFrame with updated datetime data.
     """
 
     df[column] = pd.to_datetime(df[column], **kwargs)


Test patch: