Skip to content

CLN: Enforce deprecation get_group with tuples of length 1 #57743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
@@ -198,9 +198,11 @@ Removal of prior version deprecations/changes
- All arguments in :meth:`Series.to_dict` are now keyword only (:issue:`56493`)
- Changed the default value of ``observed`` in :meth:`DataFrame.groupby` and :meth:`Series.groupby` to ``True`` (:issue:`51811`)
- Enforced deprecation disallowing parsing datetimes with mixed time zones unless user passes ``utc=True`` to :func:`to_datetime` (:issue:`57275`)
- Enforced deprecation of :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` allowing the ``name`` argument to be a non-tuple when grouping by a list of length 1 (:issue:`54155`)
- Enforced deprecation of ``axis=None`` acting the same as ``axis=0`` in the DataFrame reductions ``sum``, ``prod``, ``std``, ``var``, and ``sem``, passing ``axis=None`` will now reduce over both axes; this is particularly the case when doing e.g. ``numpy.sum(df)`` (:issue:`21597`)
- Enforced silent-downcasting deprecation for :ref:`all relevant methods <whatsnew_220.silent_downcasting>` (:issue:`54710`)
- In :meth:`DataFrame.stack`, the default value of ``future_stack`` is now ``True``; specifying ``False`` will raise a ``FutureWarning`` (:issue:`55448`)
- Iterating over a :class:`.DataFrameGroupBy` or :class:`.SeriesGroupBy` will return tuples of length 1 for the groups when grouping by ``level`` a list of length 1 (:issue:`50064`)
- Methods ``apply``, ``agg``, and ``transform`` will no longer replace NumPy functions (e.g. ``np.sum``) and built-in functions (e.g. ``min``) with the equivalent pandas implementation; use string aliases (e.g. ``"sum"`` and ``"min"``) if you desire to use the pandas implementation (:issue:`53974`)
- Passing both ``freq`` and ``fill_value`` in :meth:`DataFrame.shift` and :meth:`Series.shift` and :meth:`.DataFrameGroupBy.shift` now raises a ``ValueError`` (:issue:`54818`)
- Removed :meth:`DateOffset.is_anchored` and :meth:`offsets.Tick.is_anchored` (:issue:`56594`)
29 changes: 7 additions & 22 deletions pandas/core/groupby/groupby.py
Original file line number Diff line number Diff line change
@@ -920,17 +920,9 @@ def get_group(self, name) -> DataFrame | Series:
):
# GH#25971
if isinstance(name, tuple) and len(name) == 1:
# Allow users to pass tuples of length 1 to silence warning
name = name[0]
elif not isinstance(name, tuple):
warnings.warn(
"When grouping with a length-1 list-like, "
"you will need to pass a length-1 tuple to get_group in a future "
"version of pandas. Pass `(name,)` instead of `name` to silence "
"this warning.",
FutureWarning,
stacklevel=find_stack_level(),
)
else:
raise KeyError(name)

inds = self._get_index(name)
if not len(inds):
@@ -1016,18 +1008,11 @@ def __iter__(self) -> Iterator[tuple[Hashable, NDFrameT]]:
keys = self.keys
level = self.level
result = self._grouper.get_iterator(self._selected_obj)
# error: Argument 1 to "len" has incompatible type "Hashable"; expected "Sized"
if is_list_like(level) and len(level) == 1: # type: ignore[arg-type]
# GH 51583
warnings.warn(
"Creating a Groupby object with a length-1 list-like "
"level parameter will yield indexes as tuples in a future version. "
"To keep indexes as scalars, create Groupby objects with "
"a scalar level parameter instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
if isinstance(keys, list) and len(keys) == 1:
# mypy: Argument 1 to "len" has incompatible type "Hashable"; expected "Sized"
if (
(is_list_like(level) and len(level) == 1) # type: ignore[arg-type]
or (isinstance(keys, list) and len(keys) == 1)
):
# GH#42795 - when keys is a list, return tuples even when length is 1
result = (((key,), group) for key, group in result)
return result
6 changes: 1 addition & 5 deletions pandas/tests/groupby/test_categorical.py
Original file line number Diff line number Diff line change
@@ -252,11 +252,7 @@ def test_level_get_group(observed):
names=["Index1", "Index2"],
),
)
msg = "you will need to pass a length-1 tuple"
with tm.assert_produces_warning(FutureWarning, match=msg):
# GH#25971 - warn when not passing a length-1 tuple
result = g.get_group("a")

result = g.get_group(("a",))
tm.assert_frame_equal(result, expected)


21 changes: 6 additions & 15 deletions pandas/tests/groupby/test_groupby.py
Original file line number Diff line number Diff line change
@@ -2533,19 +2533,14 @@ def test_groupby_string_dtype():
@pytest.mark.parametrize(
"level_arg, multiindex", [([0], False), ((0,), False), ([0], True), ((0,), True)]
)
def test_single_element_listlike_level_grouping_deprecation(level_arg, multiindex):
def test_single_element_listlike_level_grouping(level_arg, multiindex):
# GH 51583
df = DataFrame({"a": [1, 2], "b": [3, 4], "c": [5, 6]}, index=["x", "y"])
if multiindex:
df = df.set_index(["a", "b"])
depr_msg = (
"Creating a Groupby object with a length-1 list-like "
"level parameter will yield indexes as tuples in a future version. "
"To keep indexes as scalars, create Groupby objects with "
"a scalar level parameter instead."
)
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
[key for key, _ in df.groupby(level=level_arg)]
result = [key for key, _ in df.groupby(level=level_arg)]
expected = [(1,), (2,)] if multiindex else [("x",), ("y",)]
assert result == expected


@pytest.mark.parametrize("func", ["sum", "cumsum", "cumprod", "prod"])
@@ -2887,22 +2882,18 @@ def test_groupby_series_with_datetimeindex_month_name():
"kwarg, value, name, warn",
[
("by", "a", 1, None),
("by", ["a"], 1, FutureWarning),
("by", ["a"], (1,), None),
("level", 0, 1, None),
("level", [0], 1, FutureWarning),
("level", [0], (1,), None),
],
)
def test_depr_get_group_len_1_list_likes(test_series, kwarg, value, name, warn):
def test_get_group_len_1_list_likes(test_series, kwarg, value, name, warn):
# GH#25971
obj = DataFrame({"b": [3, 4, 5]}, index=Index([1, 1, 2], name="a"))
if test_series:
obj = obj["b"]
gb = obj.groupby(**{kwarg: value})
msg = "you will need to pass a length-1 tuple"
with tm.assert_produces_warning(warn, match=msg):
result = gb.get_group(name)
result = gb.get_group(name)
if test_series:
expected = Series([3, 4], index=Index([1, 1], name="a"), name="b")
else: