# Buggy code
def groupby(
    self,
    by=None,
    axis=0,
    level=None,
    as_index=True,
    sort=True,
    group_keys=True,
    squeeze=False,
    observed=False,
):
    """Apply a groupby to this DataFrame. See _groupby() remote task.
    Args:
        by: The value to groupby.
        axis: The axis to groupby.
        level: The level of the groupby.
        as_index: Whether or not to store result as index.
        sort: Whether or not to sort the result by the index.
        group_keys: Whether or not to group the keys.
        squeeze: Whether or not to squeeze.
    Returns:
        A new DataFrame resulting from the groupby.
    """
    axis = self._get_axis_number(axis)
    idx_name = None
    # Drop here indicates whether or not to drop the data column before doing the
    # groupby. The typical pandas behavior is to drop when the data came from this
    # dataframe. When a string, Series directly from this dataframe, or list of
    # strings is passed in, the data used for the groupby is dropped before the
    # groupby takes place.
    drop = False

    if (
        not isinstance(by, (pandas.Series, Series))
        and is_list_like(by)
        and len(by) == 1
    ):
        by = by[0]

    if callable(by):
        by = self.index.map(by)
    elif isinstance(by, str):
        drop = by in self.columns
        idx_name = by
        if (
            self._query_compiler.has_multiindex(axis=axis)
            and by in self.axes[axis].names
        ):
            # In this case we pass the string value of the name through to the
            # partitions. This is more efficient than broadcasting the values.
            pass
        else:
            by = self.__getitem__(by)._query_compiler
    elif isinstance(by, Series):
        drop = by._parent is self
        idx_name = by.name
        by = by._query_compiler
    elif is_list_like(by):
        # fastpath for multi column groupby
        if (
            not isinstance(by, Series)
            and axis == 0
            and all(
                (
                    (isinstance(o, str) and (o in self))
                    or (isinstance(o, Series) and (o._parent is self))
                )
                for o in by
            )
        ):
            # We can just revert Series back to names because the parent is
            # this dataframe:
            by = [o.name if isinstance(o, Series) else o for o in by]

            warnings.warn(
                "Multi-column groupby is a new feature. "
                "Please report any bugs/issues to bug_reports@modin.org."
            )
            by = self.__getitem__(by)._query_compiler
            drop = True
        else:
            mismatch = len(by) != len(self.axes[axis])
            if mismatch and all(
                isinstance(obj, str)
                and (
                    obj in self
                    or (hasattr(self.index, "names") and obj in self.index.names)
                )
                for obj in by
            ):
                # In the future, we will need to add logic to handle this, but for now
                # we default to pandas in this case.
                pass
            elif mismatch and any(
                isinstance(obj, str) and obj not in self.columns for obj in by
            ):
                names = [o.name if isinstance(o, Series) else o for o in by]
                raise KeyError(next(x for x in names if x not in self))
    return DataFrameGroupBy(
        self,
        by,
        axis,
        level,
        as_index,
        sort,
        group_keys,
        squeeze,
        idx_name,
        observed=observed,
        drop=drop,
    )


# Traceback (AttributeError)
import modin.pandas as pd
import glob

files = glob.glob('/path/to/files/*.parquet')
df = pd.concat([pd.read_parquet(file) for file in files])
df.reset_index(inplace=True)
df.drop(columns=['index', 'DATE', 'STATUS', 'ID', 'ID2],inplace=True)

df.groupby(['REPORTING_DATE', 'ENTITY', 'CURRENCY']).sum()

UserWarning: Multi-column groupby is a new feature. Please report any bugs/issues to bug_reports@modin.org.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-15-081b1819b7d6> in <module>
----> 1 df.groupby(['DATA_SALDA', 'BANK', 'WALUTA_KON']).sum()

~/eksperyment/lib64/python3.6/site-packages/modin/pandas/groupby.py in sum(self, **kwargs)
323
324     def sum(self, **kwargs):
--> 325         return self._groupby_reduce(lambda df: df.sum(**kwargs), None)
326
327     def describe(self, **kwargs):

~/eksperyment/lib64/python3.6/site-packages/modin/pandas/groupby.py in _groupby_reduce(self, map_func, reduce_func, drop, numeric_only, **kwargs)
479                 reduce_args=kwargs,
480                 numeric_only=numeric_only,
--> 481                 drop=self._drop,
482             )
483         )

~/eksperyment/lib64/python3.6/site-packages/modin/backends/pandas/query_compiler.py in groupby_reduce(self, by, axis, groupby_args, map_func, map_args, reduce_func, reduce_args, numeric_only, drop)
1236             _reduce,
1237             new_columns=new_columns,
-> 1238             new_index=new_index,
1239         )
1240         result = self.__constructor__(new_modin_frame)

~/eksperyment/lib64/python3.6/site-packages/modin/engines/base/frame/data.py in groupby_reduce(self, axis, by, map_func, reduce_func, new_index, new_columns)
1148         """
1149         new_partitions = self._frame_mgr_cls.groupby_reduce(
-> 1150             axis, self._partitions, by._partitions, map_func, reduce_func
1151         )
1152         if new_columns is None:

~/eksperyment/lib64/python3.6/site-packages/modin/engines/base/frame/partition_manager.py in groupby_reduce(cls, axis, partitions, by, map_func, reduce_func)
66         if len(by_parts.shape) == 0:
67             by_parts = np.array([by_parts.item()])
---> 68         [obj.drain_call_queue() for obj in by_parts]
69         new_partitions = np.array(
70             [

~/eksperyment/lib64/python3.6/site-packages/modin/engines/base/frame/partition_manager.py in <listcomp>(.0)
66         if len(by_parts.shape) == 0:
67             by_parts = np.array([by_parts.item()])
---> 68         [obj.drain_call_queue() for obj in by_parts]
69         new_partitions = np.array(
70             [

AttributeError: 'numpy.ndarray' object has no attribute 'drain_call_queue'

# Fixed code
def groupby(
    self,
    by=None,
    axis=0,
    level=None,
    as_index=True,
    sort=True,
    group_keys=True,
    squeeze=False,
    observed=False,
):
    """Apply a groupby to this DataFrame. See _groupby() remote task.
    Args:
        by: The value to groupby.
        axis: The axis to groupby.
        level: The level of the groupby.
        as_index: Whether or not to store result as index.
        sort: Whether or not to sort the result by the index.
        group_keys: Whether or not to group the keys.
        squeeze: Whether or not to squeeze.
    Returns:
        A new DataFrame resulting from the groupby.
    """
    axis = self._get_axis_number(axis)
    idx_name = None
    # Drop here indicates whether or not to drop the data column before doing the
    # groupby. The typical pandas behavior is to drop when the data came from this
    # dataframe. When a string, Series directly from this dataframe, or list of
    # strings is passed in, the data used for the groupby is dropped before the
    # groupby takes place.
    drop = False

    if (
        not isinstance(by, (pandas.Series, Series))
        and is_list_like(by)
        and len(by) == 1
    ):
        by = by[0]

    if callable(by):
        by = self.index.map(by)
    elif isinstance(by, str):
        drop = by in self.columns
        idx_name = by
        if (
            self._query_compiler.has_multiindex(axis=axis)
            and by in self.axes[axis].names
        ):
            # In this case we pass the string value of the name through to the
            # partitions. This is more efficient than broadcasting the values.
            pass
        else:
            by = self.__getitem__(by)._query_compiler
    elif isinstance(by, Series):
        drop = by._parent is self
        idx_name = by.name
        by = by._query_compiler
    elif is_list_like(by):
        # fastpath for multi column groupby
        if (
            not isinstance(by, Series)
            and axis == 0
            and all(
                (
                    (isinstance(o, str) and (o in self))
                    or (isinstance(o, Series) and (o._parent is self))
                )
                for o in by
            )
        ):
            # We can just revert Series back to names because the parent is
            # this dataframe:
            by = [o.name if isinstance(o, Series) else o for o in by]
            by = self.__getitem__(by)._query_compiler
            drop = True
        else:
            mismatch = len(by) != len(self.axes[axis])
            if mismatch and all(
                isinstance(obj, str)
                and (
                    obj in self
                    or (hasattr(self.index, "names") and obj in self.index.names)
                )
                for obj in by
            ):
                # In the future, we will need to add logic to handle this, but for now
                # we default to pandas in this case.
                pass
            elif mismatch and any(
                isinstance(obj, str) and obj not in self.columns for obj in by
            ):
                names = [o.name if isinstance(o, Series) else o for o in by]
                raise KeyError(next(x for x in names if x not in self))
    return DataFrameGroupBy(
        self,
        by,
        axis,
        level,
        as_index,
        sort,
        group_keys,
        squeeze,
        idx_name,
        observed=observed,
        drop=drop,
    )