From 91e5b7b62b9949e250ee4561dc1cc00ad91436f4 Mon Sep 17 00:00:00 2001 From: adhil-cloud Date: Mon, 9 Feb 2026 15:36:41 +0530 Subject: [PATCH 1/5] TST: Add regression test for groupby.var/std arrow dtype retention (GH#54627) --- pandas/tests/extension/test_arrow.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 17e90f29eddc8..b968c0266177f 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3363,6 +3363,30 @@ def test_groupby_count_return_arrow_dtype(data_missing): tm.assert_frame_equal(result, expected) +def test_groupby_var_returns_arrow_dtype(): + # GH#54627 + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series([123, 12, 50, 75], dtype="int64[pyarrow]"), + } + ) + result = df.groupby("A").var() + assert result.dtypes["B"] == ArrowDtype(pa.float64()) + + +def test_groupby_std_returns_arrow_dtype(): + # GH#54627 + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series([123, 12, 50, 75], dtype="int64[pyarrow]"), + } + ) + result = df.groupby("A").std() + assert result.dtypes["B"] == ArrowDtype(pa.float64()) + + def test_fixed_size_list(): # GH#55000 ser = pd.Series( From 955e69c7b10cf3441717cddec195b538b225d6b7 Mon Sep 17 00:00:00 2001 From: adhil-cloud Date: Mon, 9 Feb 2026 16:10:27 +0530 Subject: [PATCH 2/5] TST: Add regression test for groupby.var/std arrow dtype retention (GH#54627) --- pandas/core/arrays/arrow/array.py | 3 ++ pandas/tests/extension/test_arrow.py | 60 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pandas/core/arrays/arrow/array.py b/pandas/core/arrays/arrow/array.py index 86fe806202e0b..a8d407cb67d5d 100644 --- a/pandas/core/arrays/arrow/array.py +++ b/pandas/core/arrays/arrow/array.py @@ -2775,6 +2775,9 @@ def _to_masked(self): na_value = 1 elif pa.types.is_boolean(pa_dtype): na_value = True + elif pa.types.is_decimal(pa_dtype): + # GH#54627 + return type(self)(self._pa_array.cast(pa.float64()))._to_masked() else: raise NotImplementedError diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index b968c0266177f..1630b2d553234 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3387,6 +3387,66 @@ def test_groupby_std_returns_arrow_dtype(): assert result.dtypes["B"] == ArrowDtype(pa.float64()) +def test_groupby_var_returns_arrow_dtype_float32(): + # GH#54627 + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series([123.0, 12.0, 50.0, 75.0], dtype="float32[pyarrow]"), + } + ) + result = df.groupby("A").var() + # Pandas preserves float32 precision for float32 inputs + assert result.dtypes["B"] == ArrowDtype(pa.float32()) + + +def test_groupby_std_returns_arrow_dtype_float32(): + # GH#54627 + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series([123.0, 12.0, 50.0, 75.0], dtype="float32[pyarrow]"), + } + ) + result = df.groupby("A").std() + # Pandas preserves float32 precision for float32 inputs + assert result.dtypes["B"] == ArrowDtype(pa.float32()) + + +def test_groupby_var_returns_arrow_dtype_decimal(): + # GH#54627 + from decimal import Decimal + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series( + [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], + dtype=ArrowDtype(pa.decimal128(6, 3)) + ), + } + ) + result = df.groupby("A").var() + # Decimals are cast to float64, so result should be float64 + assert result.dtypes["B"] == ArrowDtype(pa.float64()) + + +def test_groupby_std_returns_arrow_dtype_decimal(): + # GH#54627 + from decimal import Decimal + df = pd.DataFrame( + { + "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), + "B": pd.Series( + [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], + dtype=ArrowDtype(pa.decimal128(6, 3)) + ), + } + ) + result = df.groupby("A").std() + # Decimals are cast to float64, so result should be float64 + assert result.dtypes["B"] == ArrowDtype(pa.float64()) + + def test_fixed_size_list(): # GH#55000 ser = pd.Series( From 7dd999295141a33f09309b960743a26906afbe10 Mon Sep 17 00:00:00 2001 From: adhil-cloud Date: Mon, 9 Feb 2026 16:47:04 +0530 Subject: [PATCH 3/5] TST: clean up comments for added test in test_arrow.py (GH#54627) --- pandas/tests/extension/test_arrow.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 1630b2d553234..22c8f6aab2b35 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3396,7 +3396,6 @@ def test_groupby_var_returns_arrow_dtype_float32(): } ) result = df.groupby("A").var() - # Pandas preserves float32 precision for float32 inputs assert result.dtypes["B"] == ArrowDtype(pa.float32()) @@ -3409,7 +3408,6 @@ def test_groupby_std_returns_arrow_dtype_float32(): } ) result = df.groupby("A").std() - # Pandas preserves float32 precision for float32 inputs assert result.dtypes["B"] == ArrowDtype(pa.float32()) @@ -3426,7 +3424,6 @@ def test_groupby_var_returns_arrow_dtype_decimal(): } ) result = df.groupby("A").var() - # Decimals are cast to float64, so result should be float64 assert result.dtypes["B"] == ArrowDtype(pa.float64()) @@ -3443,7 +3440,6 @@ def test_groupby_std_returns_arrow_dtype_decimal(): } ) result = df.groupby("A").std() - # Decimals are cast to float64, so result should be float64 assert result.dtypes["B"] == ArrowDtype(pa.float64()) From 4a13aef393122ec93e6443c5055f054be6ebb0d2 Mon Sep 17 00:00:00 2001 From: adhil-cloud Date: Mon, 9 Feb 2026 17:02:03 +0530 Subject: [PATCH 4/5] STY: Fix ruff linting and formatting --- pandas/tests/extension/test_arrow.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 22c8f6aab2b35..ab819925f8634 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3414,12 +3414,13 @@ def test_groupby_std_returns_arrow_dtype_float32(): def test_groupby_var_returns_arrow_dtype_decimal(): # GH#54627 from decimal import Decimal + df = pd.DataFrame( { "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), "B": pd.Series( - [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], - dtype=ArrowDtype(pa.decimal128(6, 3)) + [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], + dtype=ArrowDtype(pa.decimal128(6, 3)), ), } ) @@ -3430,12 +3431,13 @@ def test_groupby_var_returns_arrow_dtype_decimal(): def test_groupby_std_returns_arrow_dtype_decimal(): # GH#54627 from decimal import Decimal + df = pd.DataFrame( { "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), "B": pd.Series( - [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], - dtype=ArrowDtype(pa.decimal128(6, 3)) + [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], + dtype=ArrowDtype(pa.decimal128(6, 3)), ), } ) From b9dfc66a74f86b68dbc02e77eec5f2ab0032d980 Mon Sep 17 00:00:00 2001 From: adhil-cloud Date: Mon, 9 Feb 2026 18:48:35 +0530 Subject: [PATCH 5/5] TST: Added only required tests --- pandas/core/arrays/arrow/array.py | 3 -- pandas/tests/extension/test_arrow.py | 58 ---------------------------- 2 files changed, 61 deletions(-) diff --git a/pandas/core/arrays/arrow/array.py b/pandas/core/arrays/arrow/array.py index a8d407cb67d5d..86fe806202e0b 100644 --- a/pandas/core/arrays/arrow/array.py +++ b/pandas/core/arrays/arrow/array.py @@ -2775,9 +2775,6 @@ def _to_masked(self): na_value = 1 elif pa.types.is_boolean(pa_dtype): na_value = True - elif pa.types.is_decimal(pa_dtype): - # GH#54627 - return type(self)(self._pa_array.cast(pa.float64()))._to_masked() else: raise NotImplementedError diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index ab819925f8634..b968c0266177f 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3387,64 +3387,6 @@ def test_groupby_std_returns_arrow_dtype(): assert result.dtypes["B"] == ArrowDtype(pa.float64()) -def test_groupby_var_returns_arrow_dtype_float32(): - # GH#54627 - df = pd.DataFrame( - { - "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), - "B": pd.Series([123.0, 12.0, 50.0, 75.0], dtype="float32[pyarrow]"), - } - ) - result = df.groupby("A").var() - assert result.dtypes["B"] == ArrowDtype(pa.float32()) - - -def test_groupby_std_returns_arrow_dtype_float32(): - # GH#54627 - df = pd.DataFrame( - { - "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), - "B": pd.Series([123.0, 12.0, 50.0, 75.0], dtype="float32[pyarrow]"), - } - ) - result = df.groupby("A").std() - assert result.dtypes["B"] == ArrowDtype(pa.float32()) - - -def test_groupby_var_returns_arrow_dtype_decimal(): - # GH#54627 - from decimal import Decimal - - df = pd.DataFrame( - { - "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), - "B": pd.Series( - [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], - dtype=ArrowDtype(pa.decimal128(6, 3)), - ), - } - ) - result = df.groupby("A").var() - assert result.dtypes["B"] == ArrowDtype(pa.float64()) - - -def test_groupby_std_returns_arrow_dtype_decimal(): - # GH#54627 - from decimal import Decimal - - df = pd.DataFrame( - { - "A": pd.Series([True, True, False, False], dtype="bool[pyarrow]"), - "B": pd.Series( - [Decimal("123.0"), Decimal("12.0"), Decimal("50.0"), Decimal("75.0")], - dtype=ArrowDtype(pa.decimal128(6, 3)), - ), - } - ) - result = df.groupby("A").std() - assert result.dtypes["B"] == ArrowDtype(pa.float64()) - - def test_fixed_size_list(): # GH#55000 ser = pd.Series(