Repository: modin-project/modin

Issue:
Named aggregation doesn't work in DataFrame.agg
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**:

Ubuntu 19.10

- **Modin version** (`modin.__version__`):

0.8.1.1+31.ga0a3ebb

- **Python version**:

Python 3.8.3

- **Code we can use to reproduce**:

```python
import numpy as np
import modin.pandas as pd
#import pandas as pd

df = pd.DataFrame({
    "col1": [ 1,  2,  1,  2,  1,  3,  3,  2,  3],
    "col2": [11, 12, 13, 14, 15, 16, 17, 18, 19],
    "col3": [ 4,  4,  4,  4,  5,  5,  5,  5,  5],
    "col4": [ 1,  1,  1,  1,  1,  1,  1,  1,  1]
})
print(df, '\n')

df1 = df.agg(new_col=('col2', max))
print(df1, '\n')
df2 = df.agg(new_col1=('col2', 'max'), new_col2=('col2', 'min'), new_col3=('col2', 'sum'),
              new_col4=('col4', 'max'), new_col5=('col4', 'min'), new_col6=('col4', 'sum'))
print(df2, '\n')
```

<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
<!-- Describe the problem clearly here. -->

Running this code results in an exception:
```
Traceback (most recent call last):
  File "agg_test2.py", line 13, in <module>
    df1 = df.agg(new_col=('col2', max))
  File "/localdisk/gashiman/modin/modin/pandas/base.py", line 504, in aggregate
    return self.apply(func, axis=axis, args=args, **kwargs)
  File "/localdisk/gashiman/modin/modin/pandas/dataframe.py", line 289, in apply
    query_compiler = super(DataFrame, self).apply(
  File "/localdisk/gashiman/modin/modin/pandas/base.py", line 716, in apply
    raise TypeError("{} object is not callable".format(type(func)))
TypeError: <class 'NoneType'> object is not callable
```
This bug may be related to how named aggregation worked in groupby before #2254 was fixed.

### Source code / logs
<!-- Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. -->



Discussion:

Resolving patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -517,22 +517,22 @@ def aggregate(self, func=None, axis=0, *args, **kwargs):
 
     agg = aggregate
 
-    def _aggregate(self, arg, *args, **kwargs):
+    def _aggregate(self, func, *args, **kwargs):
         _axis = kwargs.pop("_axis", 0)
         kwargs.pop("_level", None)
 
-        if isinstance(arg, str):
+        if isinstance(func, str):
             kwargs.pop("is_transform", None)
-            return self._string_function(arg, *args, **kwargs)
+            return self._string_function(func, *args, **kwargs)
 
         # Dictionaries have complex behavior because they can be renamed here.
-        elif isinstance(arg, dict):
-            return self._default_to_pandas("agg", arg, *args, **kwargs)
-        elif is_list_like(arg) or callable(arg):
+        elif func is None or isinstance(func, dict):
+            return self._default_to_pandas("agg", func, *args, **kwargs)
+        elif is_list_like(func) or callable(func):
             kwargs.pop("is_transform", None)
-            return self.apply(arg, axis=_axis, args=args, **kwargs)
+            return self.apply(func, axis=_axis, args=args, **kwargs)
         else:
-            raise TypeError("type {} is not callable".format(type(arg)))
+            raise TypeError("type {} is not callable".format(type(func)))
 
     def _string_function(self, func, *args, **kwargs):
         assert isinstance(func, str)


Test patch:
diff --git a/modin/pandas/test/dataframe/test_udf.py b/modin/pandas/test/dataframe/test_udf.py
--- a/modin/pandas/test/dataframe/test_udf.py
+++ b/modin/pandas/test/dataframe/test_udf.py
@@ -42,6 +42,18 @@
 matplotlib.use("Agg")
 
 
+def test_agg_dict():
+    md_df, pd_df = create_test_dfs(test_data_values[0])
+    agg_dict = {pd_df.columns[0]: "sum", pd_df.columns[-1]: ("sum", "count")}
+    eval_general(md_df, pd_df, lambda df: df.agg(agg_dict), raising_exceptions=True)
+
+    agg_dict = {
+        "new_col1": (pd_df.columns[0], "sum"),
+        "new_col2": (pd_df.columns[-1], "count"),
+    }
+    eval_general(md_df, pd_df, lambda df: df.agg(**agg_dict), raising_exceptions=True)
+
+
 @pytest.mark.parametrize("axis", [0, 1])
 @pytest.mark.parametrize(
     "func",