Repository: pandas-dev/pandas-stubs (language: python)

Issue:
groupby methods can return Series or DataFrame based on `as_index` variable
**Describe the bug**
Depending on the boolean `as_index`, methods on groupby objects will return different type.
This is a follow up for #203,

**To Reproduce**
1. Provide a minimal runnable `pandas` example that is not properly checked by the stubs.
2. Indicate which type checker you are using (`mypy` or  `pyright`).
3. Show the error message received from that type checker while checking your example.


**Please complete the following information:**
 - OS: [e.g. Windows, Linux, MacOS]
 - OS Version [e.g. 22]
 - python version
 - version of type checker
 - version of installed `pandas-stubs`


**Additional context**
Add any other context about the problem here.



Discussion / hints:
Do you think you can create an inventory of methods here in this issue as a checklist, and then as you incrementally fix them, we can know which ones are fixed?
Yes let me add that here so we can see where we are at!
Outstanding methods to typehint:
✅  size
🔴  value_counts
Maybe there are other methods, feel free to append.
I tried a bunch of methods, and I think the only one left to worry about is `value_counts()`.
Agreed, will take care of `value_counts` in a bit, I tried the other methods and they all return `DataFrame` whether we pass `as_index` as True or False.

Fix patch:
diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi
index 512599ac..8172b1b4 100644
--- a/pandas-stubs/core/groupby/generic.pyi
+++ b/pandas-stubs/core/groupby/generic.pyi
@@ -302,7 +302,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT, _TT]):
     ) -> PlotAxes | Series: ...  # Series[PlotAxes]
     @overload
     def value_counts(
-        self,
+        self: DataFrameGroupBy[ByT, Literal[True]],
         subset: ListLike | None = ...,
         normalize: Literal[False] = ...,
         sort: bool = ...,
@@ -311,13 +311,31 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT, _TT]):
     ) -> Series[int]: ...
     @overload
     def value_counts(
-        self,
+        self: DataFrameGroupBy[ByT, Literal[True]],
         subset: ListLike | None,
         normalize: Literal[True],
         sort: bool = ...,
         ascending: bool = ...,
         dropna: bool = ...,
     ) -> Series[float]: ...
+    @overload
+    def value_counts(
+        self: DataFrameGroupBy[ByT, Literal[False]],
+        subset: ListLike | None = ...,
+        normalize: Literal[False] = ...,
+        sort: bool = ...,
+        ascending: bool = ...,
+        dropna: bool = ...,
+    ) -> DataFrame: ...
+    @overload
+    def value_counts(
+        self: DataFrameGroupBy[ByT, Literal[False]],
+        subset: ListLike | None,
+        normalize: Literal[True],
+        sort: bool = ...,
+        ascending: bool = ...,
+        dropna: bool = ...,
+    ) -> DataFrame: ...
     def take(
         self, indices: TakeIndexer, axis: Axis | None | NoDefault = ..., **kwargs
     ) -> DataFrame: ...


Test patch:
diff --git a/tests/test_frame.py b/tests/test_frame.py
index 7a167f53..bee41a20 100644
--- a/tests/test_frame.py
+++ b/tests/test_frame.py
@@ -1026,6 +1026,7 @@ def test_types_pivot_table() -> None:
 
 
 def test_types_groupby_as_index() -> None:
+    """Test type of groupby.size method depending on `as_index`."""
     df = pd.DataFrame({"a": [1, 2, 3]})
     check(
         assert_type(
@@ -1043,6 +1044,25 @@ def test_types_groupby_as_index() -> None:
     )
 
 
+def test_types_groupby_as_index_value_counts() -> None:
+    """Test type of groupby.value_counts method depending on `as_index`."""
+    df = pd.DataFrame({"a": [1, 2, 3]})
+    check(
+        assert_type(
+            df.groupby("a", as_index=False).value_counts(),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            df.groupby("a", as_index=True).value_counts(),
+            "pd.Series[int]",
+        ),
+        pd.Series,
+    )
+
+
 def test_types_groupby_size() -> None:
     """Test for GH886."""
     data = [