Repository: dask/dask

Issue:
Can no longer provide `split_out=None` as a default in `groupby.aggregate`
**What happened**:

Since a combination of #9453 and #9302, one can no longer provide `split_out=None` to `groupby.aggregate` to obtain the default `split_out` value (eventually `split_out=None` defaults to `split_out=1` deep inside `apply_concat_apply`).

(cc @rjzamora, @ian-r-rose)

**What you expected to happen**:

`split_out=None` should default to something sensible. The question arises as to whether one should change the API of all the aggregate functions to default to `split_out=None` rather than `split_out=1` or if we should just handle it locally. (The lack of true option-types in Python bites again 😢)

**Minimal Complete Verifiable Example**:

```python
import dask.dataframe
import pandas as pd

df = pd.DataFrame({"grouping": [1, 2, 1, 1, 3, 2, 1, 1], "a": list(range(8))})

ddf = dask.dataframe.from_pandas(df)

groups = ddf.groupby("grouping").aggregate("sum", split_out=None).compute()

TypeError                                 Traceback (most recent call last)
Input In [5], in <cell line: 1>()
----> 1 ddf.groupby("grouping").aggregate("sum", split_out=None).compute()

File ~/Documents/src/dask/dask/dataframe/groupby.py:2265, in DataFrameGroupBy.aggregate(self, arg, split_every, split_out, shuffle)
   2262 if arg == "size":
   2263     return self.size()
-> 2265 return super().aggregate(
   2266     arg, split_every=split_every, split_out=split_out, shuffle=shuffle
   2267 )

File ~/Documents/src/dask/dask/dataframe/groupby.py:1685, in _GroupBy.aggregate(self, arg, split_every, split_out, shuffle)
   1682 @_aggregate_docstring()
   1683 def aggregate(self, arg, split_every=None, split_out=1, shuffle=None):
   1684     if shuffle is None:
-> 1685         if split_out > 1:
   1686             shuffle = shuffle or config.get("shuffle", None) or "tasks"
   1687         else:

TypeError: '>' not supported between instances of 'NoneType' and 'int'
```

A similar issue occurs in `apply_concat_apply` as well:

```
dask.dataframe.core.aca(ddf, chunk=len, aggregate=sum, combine=sum, sort=True)
in apply_concat_apply(args, chunk, aggregate, combine, meta, token, chunk_kwargs, aggregate_kwargs, combine_kwargs, split_every, split_out, split_out_setup, split_out_setup_kwargs, sort, ignore_index, **kwargs)
   6447 # Handle sort behavior
   6448 if sort is not None:
-> 6449     if sort and split_out > 1:
   6450         raise NotImplementedError(
   6451             "Cannot guarantee sorted keys for `split_out>1`."
   6452             " Try using split_out=1, or grouping with sort=False."
   6453         )
   6454     aggregate_kwargs = aggregate_kwargs or {}

TypeError: '>' not supported between instances of 'NoneType' and 'int'
```


Discussion:
Thanks for the report @wence- 

Sigh...I'd really prefer to take default argument values seriously, and be a bit stricter with the types. So in my ideal world, `split_out` would always be an integer, and `None` would be invalid. But the breaking of existing workflows is not really what we intended here. So I'd probably prefer to handle it locally, and just check for `None` in the above snippet.

Resolving patch:
diff --git a/dask/dataframe/groupby.py b/dask/dataframe/groupby.py
--- a/dask/dataframe/groupby.py
+++ b/dask/dataframe/groupby.py
@@ -1681,6 +1681,13 @@ def get_group(self, key):
 
     @_aggregate_docstring()
     def aggregate(self, arg, split_every=None, split_out=1, shuffle=None):
+        if split_out is None:
+            warnings.warn(
+                "split_out=None is deprecated, please use a positive integer, "
+                "or allow the default of 1",
+                category=FutureWarning,
+            )
+            split_out = 1
         if shuffle is None:
             if split_out > 1:
                 shuffle = shuffle or config.get("shuffle", None) or "tasks"


Test patch:
diff --git a/dask/dataframe/tests/test_groupby.py b/dask/dataframe/tests/test_groupby.py
--- a/dask/dataframe/tests/test_groupby.py
+++ b/dask/dataframe/tests/test_groupby.py
@@ -2941,3 +2941,10 @@ def test_groupby_iter_fails():
     ddf = dd.from_pandas(df, npartitions=1)
     with pytest.raises(NotImplementedError, match="computing the groups"):
         list(ddf.groupby("A"))
+
+
+def test_groupby_None_split_out_warns():
+    df = pd.DataFrame({"a": [1, 1, 2], "b": [2, 3, 4]})
+    ddf = dd.from_pandas(df, npartitions=1)
+    with pytest.warns(FutureWarning, match="split_out=None"):
+        ddf.groupby("a").agg({"b": "max"}, split_out=None)