# Buggy code
def _aggregate(self, arg, *args, **kwargs):
    """
    provide an implementation for the aggregators

    Parameters
    ----------
    arg : string, dict, function
    *args : args to pass on to the function
    **kwargs : kwargs to pass on to the function

    Returns
    -------
    tuple of result, how

    Notes
    -----
    how can be a string describe the required post-processing, or
    None if not required
    """
    is_aggregator = lambda x: isinstance(x, (list, tuple, dict))

    _axis = kwargs.pop("_axis", None)
    if _axis is None:
        _axis = getattr(self, "axis", 0)

    if isinstance(arg, str):
        return self._try_aggregate_string_function(arg, *args, **kwargs), None

    if isinstance(arg, dict):
        # aggregate based on the passed dict
        if _axis != 0:  # pragma: no cover
            raise ValueError("Can only pass dict with axis=0")

        obj = self._selected_obj

        # if we have a dict of any non-scalars
        # eg. {'A' : ['mean']}, normalize all to
        # be list-likes
        if any(is_aggregator(x) for x in arg.values()):
            new_arg = {}
            for k, v in arg.items():
                if not isinstance(v, (tuple, list, dict)):
                    new_arg[k] = [v]
                else:
                    new_arg[k] = v

                # the keys must be in the columns
                # for ndim=2, or renamers for ndim=1

                # ok for now, but deprecated
                # {'A': { 'ra': 'mean' }}
                # {'A': { 'ra': ['mean'] }}
                # {'ra': ['mean']}

                # not ok
                # {'ra' : { 'A' : 'mean' }}
                if isinstance(v, dict):
                    raise SpecificationError("nested renamer is not supported")
                elif isinstance(obj, ABCSeries):
                    raise SpecificationError("nested renamer is not supported")
                elif isinstance(obj, ABCDataFrame) and k not in obj.columns:
                    raise KeyError(f"Column '{k}' does not exist!")

            arg = new_arg

        else:
            # deprecation of renaming keys
            # GH 15931
            keys = list(arg.keys())
            if isinstance(obj, ABCDataFrame) and len(
                obj.columns.intersection(keys)
            ) != len(keys):
                cols = sorted(set(keys) - set(obj.columns.intersection(keys)))
                raise SpecificationError(f"Column(s) {cols} do not exist")

        from pandas.core.reshape.concat import concat

        def _agg_1dim(name, how, subset=None):
            """
            aggregate a 1-dim with how
            """
            colg = self._gotitem(name, ndim=1, subset=subset)
            if colg.ndim != 1:
                raise SpecificationError(
                    "nested dictionary is ambiguous in aggregation"
                )
            return colg.aggregate(how)

        def _agg_2dim(how):
            """
            aggregate a 2-dim with how
            """
            colg = self._gotitem(self._selection, ndim=2, subset=obj)
            return colg.aggregate(how)

        def _agg(arg, func):
            """
            run the aggregations over the arg with func
            return a dict
            """
            result = {}
            for fname, agg_how in arg.items():
                result[fname] = func(fname, agg_how)
            return result

        # set the final keys
        keys = list(arg.keys())
        result = {}

        if self._selection is not None:
            sl = set(self._selection_list)

            # we are a Series like object,
            # but may have multiple aggregations
            if len(sl) == 1:
                result = _agg(
                    arg, lambda fname, agg_how: _agg_1dim(self._selection, agg_how)
                )

            # we are selecting the same set as we are aggregating
            elif not len(sl - set(keys)):
                result = _agg(arg, _agg_1dim)

            # we are a DataFrame, with possibly multiple aggregations
            else:
                result = _agg(arg, _agg_2dim)

        # no selection
        else:
            try:
                result = _agg(arg, _agg_1dim)
            except SpecificationError:
                # we are aggregating expecting all 1d-returns
                # but we have 2d
                result = _agg(arg, _agg_2dim)

        # combine results

        def is_any_series() -> bool:
            # return a boolean if we have *any* nested series
            return any(isinstance(r, ABCSeries) for r in result.values())

        def is_any_frame() -> bool:
            # return a boolean if we have *any* nested series
            return any(isinstance(r, ABCDataFrame) for r in result.values())

        if isinstance(result, list):
            return concat(result, keys=keys, axis=1, sort=True), True

        elif is_any_frame():
            # we have a dict of DataFrames
            # return a MI DataFrame

            keys_to_use = [k for k in keys if not result[k].empty]
            # Have to check, if at least one DataFrame is not empty.
            keys_to_use = keys_to_use if keys_to_use != [] else keys
            return (
                concat([result[k] for k in keys_to_use], keys=keys_to_use, axis=1),
                True,
            )

        elif isinstance(self, ABCSeries) and is_any_series():
            # we have a dict of Series
            # return a MI Series
            try:
                result = concat(result)
            except TypeError as err:
                # we want to give a nice error here if
                # we have non-same sized objects, so
                # we don't automatically broadcast

                raise ValueError(
                    "cannot perform both aggregation "
                    "and transformation operations "
                    "simultaneously"
                ) from err

            return result, True

        # fall thru
        from pandas import DataFrame, Series

        try:
            result = DataFrame(result)
        except ValueError:
            # we have a dict of scalars
            result = Series(result, name=getattr(self, "name", None))

        return result, True
    elif is_list_like(arg):
        # we require a list, but not an 'str'
        return self._aggregate_multiple_funcs(arg, _axis=_axis), None
    else:
        result = None

    f = self._get_cython_func(arg)
    if f and not args and not kwargs:
        return getattr(self, f)(), None

    # caller can react
    return result, True


# Traceback (ValueError)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/base.py in _aggregate(self, arg, *args, **kwargs)
470             try:
--> 471                 result = DataFrame(result)
472             except ValueError:

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/frame.py in __init__(self, data, index, columns, dtype, copy)
467         elif isinstance(data, dict):
--> 468             mgr = init_dict(data, index, columns, dtype=dtype)
469         elif isinstance(data, ma.MaskedArray):

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/internals/construction.py in init_dict(data, index, columns, dtype)
282         ]
--> 283     return arrays_to_mgr(arrays, data_names, index, columns, dtype=dtype)
284

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/internals/construction.py in arrays_to_mgr(arrays, arr_names, index, columns, dtype, verify_integrity)
77         if index is None:
---> 78             index = extract_index(arrays)
79         else:

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/internals/construction.py in extract_index(data)
386         if not indexes and not raw_lengths:
--> 387             raise ValueError("If using all scalar values, you must pass an index")
388

ValueError: If using all scalar values, you must pass an index

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/frame.py in aggregate(self, func, axis, *args, **kwargs)
7358         try:
-> 7359             result, how = self._aggregate(func, axis=axis, *args, **kwargs)
7360         except TypeError as err:

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/frame.py in _aggregate(self, arg, axis, *args, **kwargs)
7383             return result, how
-> 7384         return super()._aggregate(arg, *args, **kwargs)
7385

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/base.py in _aggregate(self, arg, *args, **kwargs)
474                 # we have a dict of scalars
--> 475                 result = Series(result, name=getattr(self, "name", None))
476

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/series.py in __init__(self, data, index, dtype, name, copy, fastpath)
228
--> 229             name = ibase.maybe_extract_name(name, data, type(self))
230

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/indexes/base.py in maybe_extract_name(name, obj, cls)
5658     if not is_hashable(name):
-> 5659         raise TypeError(f"{cls.__name__}.name must be a hashable type")
5660

TypeError: Series.name must be a hashable type

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
<ipython-input-6-efe06ed8dce0> in <module>
2 data = {"name": ["abc", "xyz"]}
3 df = pd.DataFrame(data)
----> 4 print(df.agg({'name': 'count'}))

~/.virtualenvs/dimensions-connectors/lib/python3.7/site-packages/pandas/core/frame.py in aggregate(self, func, axis, *args, **kwargs)
7363                 f"incompatible data and dtype: {err}"
7364             )
-> 7365             raise exc from err
7366         if result is None:
7367             return self.apply(func, axis=axis, args=args, **kwargs)

TypeError: DataFrame constructor called with incompatible data and dtype: Series.name must be a hashable type

# Fixed code
def _aggregate(self, arg, *args, **kwargs):
    """
    provide an implementation for the aggregators

    Parameters
    ----------
    arg : string, dict, function
    *args : args to pass on to the function
    **kwargs : kwargs to pass on to the function

    Returns
    -------
    tuple of result, how

    Notes
    -----
    how can be a string describe the required post-processing, or
    None if not required
    """
    is_aggregator = lambda x: isinstance(x, (list, tuple, dict))

    _axis = kwargs.pop("_axis", None)
    if _axis is None:
        _axis = getattr(self, "axis", 0)

    if isinstance(arg, str):
        return self._try_aggregate_string_function(arg, *args, **kwargs), None

    if isinstance(arg, dict):
        # aggregate based on the passed dict
        if _axis != 0:  # pragma: no cover
            raise ValueError("Can only pass dict with axis=0")

        obj = self._selected_obj

        # if we have a dict of any non-scalars
        # eg. {'A' : ['mean']}, normalize all to
        # be list-likes
        if any(is_aggregator(x) for x in arg.values()):
            new_arg = {}
            for k, v in arg.items():
                if not isinstance(v, (tuple, list, dict)):
                    new_arg[k] = [v]
                else:
                    new_arg[k] = v

                # the keys must be in the columns
                # for ndim=2, or renamers for ndim=1

                # ok for now, but deprecated
                # {'A': { 'ra': 'mean' }}
                # {'A': { 'ra': ['mean'] }}
                # {'ra': ['mean']}

                # not ok
                # {'ra' : { 'A' : 'mean' }}
                if isinstance(v, dict):
                    raise SpecificationError("nested renamer is not supported")
                elif isinstance(obj, ABCSeries):
                    raise SpecificationError("nested renamer is not supported")
                elif isinstance(obj, ABCDataFrame) and k not in obj.columns:
                    raise KeyError(f"Column '{k}' does not exist!")

            arg = new_arg

        else:
            # deprecation of renaming keys
            # GH 15931
            keys = list(arg.keys())
            if isinstance(obj, ABCDataFrame) and len(
                obj.columns.intersection(keys)
            ) != len(keys):
                cols = sorted(set(keys) - set(obj.columns.intersection(keys)))
                raise SpecificationError(f"Column(s) {cols} do not exist")

        from pandas.core.reshape.concat import concat

        def _agg_1dim(name, how, subset=None):
            """
            aggregate a 1-dim with how
            """
            colg = self._gotitem(name, ndim=1, subset=subset)
            if colg.ndim != 1:
                raise SpecificationError(
                    "nested dictionary is ambiguous in aggregation"
                )
            return colg.aggregate(how)

        def _agg_2dim(how):
            """
            aggregate a 2-dim with how
            """
            colg = self._gotitem(self._selection, ndim=2, subset=obj)
            return colg.aggregate(how)

        def _agg(arg, func):
            """
            run the aggregations over the arg with func
            return a dict
            """
            result = {}
            for fname, agg_how in arg.items():
                result[fname] = func(fname, agg_how)
            return result

        # set the final keys
        keys = list(arg.keys())
        result = {}

        if self._selection is not None:
            sl = set(self._selection_list)

            # we are a Series like object,
            # but may have multiple aggregations
            if len(sl) == 1:
                result = _agg(
                    arg, lambda fname, agg_how: _agg_1dim(self._selection, agg_how)
                )

            # we are selecting the same set as we are aggregating
            elif not len(sl - set(keys)):
                result = _agg(arg, _agg_1dim)

            # we are a DataFrame, with possibly multiple aggregations
            else:
                result = _agg(arg, _agg_2dim)

        # no selection
        else:
            try:
                result = _agg(arg, _agg_1dim)
            except SpecificationError:
                # we are aggregating expecting all 1d-returns
                # but we have 2d
                result = _agg(arg, _agg_2dim)

        # combine results

        def is_any_series() -> bool:
            # return a boolean if we have *any* nested series
            return any(isinstance(r, ABCSeries) for r in result.values())

        def is_any_frame() -> bool:
            # return a boolean if we have *any* nested series
            return any(isinstance(r, ABCDataFrame) for r in result.values())

        if isinstance(result, list):
            return concat(result, keys=keys, axis=1, sort=True), True

        elif is_any_frame():
            # we have a dict of DataFrames
            # return a MI DataFrame

            keys_to_use = [k for k in keys if not result[k].empty]
            # Have to check, if at least one DataFrame is not empty.
            keys_to_use = keys_to_use if keys_to_use != [] else keys
            return (
                concat([result[k] for k in keys_to_use], keys=keys_to_use, axis=1),
                True,
            )

        elif isinstance(self, ABCSeries) and is_any_series():
            # we have a dict of Series
            # return a MI Series
            try:
                result = concat(result)
            except TypeError as err:
                # we want to give a nice error here if
                # we have non-same sized objects, so
                # we don't automatically broadcast

                raise ValueError(
                    "cannot perform both aggregation "
                    "and transformation operations "
                    "simultaneously"
                ) from err

            return result, True

        # fall thru
        from pandas import DataFrame, Series

        try:
            result = DataFrame(result)
        except ValueError:
            # we have a dict of scalars

            # GH 36212 use name only if self is a series
            name = self.name if (self.ndim == 1) else None

            result = Series(result, name=name)

        return result, True
    elif is_list_like(arg):
        # we require a list, but not an 'str'
        return self._aggregate_multiple_funcs(arg, _axis=_axis), None
    else:
        result = None

    f = self._get_cython_func(arg)
    if f and not args and not kwargs:
        return getattr(self, f)(), None

    # caller can react
    return result, True