From 770f1e632f33aaf731bcb1aa5bc0f2d119fd01c5 Mon Sep 17 00:00:00 2001 From: Praateek Date: Fri, 26 Sep 2025 15:33:15 -0700 Subject: [PATCH 1/3] fc Signed-off-by: Praateek --- pandas/core/series.py | 2 +- pandas/tests/series/test_arithmetic.py | 44 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 11a59f261de5c..12a202edab1d3 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -6034,7 +6034,7 @@ def _flex_method(self, other, op, *, level=None, fill_value=None, axis: Axis = 0 if isinstance(other, Series): return self._binop(other, op, level=level, fill_value=fill_value) - elif isinstance(other, (np.ndarray, list, tuple)): + elif isinstance(other, (np.ndarray, list, tuple, ExtensionArray)): if len(other) != len(self): raise ValueError("Lengths must be equal") other = self._constructor(other, self.index, copy=False) diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index 35a9742d653db..556a596f37596 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -155,6 +155,41 @@ def _check_fill(meth, op, a, b, fill_value=0): # should accept axis=0 or axis='rows' op(a, b, axis=0) + def test_extarray_rhs_datetime_sub_with_fill_value(self): + # Ensure ExtensionArray (DatetimeArray) RHS is handled via array-like path + # and does not hit scalar isna branch. + left = Series( + [ + pd.Timestamp("2025-08-20"), + pd.Timestamp("2025-08-21"), + pd.Timestamp("2025-08-22"), + ], + dtype=np.dtype("datetime64[ns]") + ) + right = left._values # DatetimeArray + + result = left.sub(right, fill_value=left.iloc[0]) + # result dtype may vary (e.g., seconds vs ns), build expected from result dtype + expected = Series(np.zeros(3, dtype=np.dtype("timedelta64[ns]"))) + tm.assert_series_equal(result, expected) + + def test_extarray_rhs_timedelta_sub_with_fill_value(self): + left = Series([Timedelta(days=1), Timedelta(days=2), Timedelta(days=3)], dtype=np.dtype("timedelta64[ns]")) + right = left._values # TimedeltaArray + + result = left.sub(right, fill_value=left.iloc[0]) + expected = Series(np.zeros(3, dtype=np.dtype("timedelta64[ns]"))) + tm.assert_series_equal(result, expected) + + def test_extarray_rhs_period_eq_with_fill_value(self): + # Use equality to validate ExtensionArray RHS path for PeriodArray + left = Series(pd.period_range("2020Q1", periods=3, freq="Q")) + right = left._values # PeriodArray + + result = left.eq(right, fill_value=left.iloc[0]) + expected = Series([True, True, True]) + tm.assert_series_equal(result, expected) + class TestSeriesArithmetic: # Some of these may end up in tests/arithmetic, but are not yet sorted @@ -404,6 +439,15 @@ def test_comparison_flex_alignment(self, values, op): expected = Series(values, index=list("abcd")) tm.assert_series_equal(result, expected) + def test_extarray_rhs_categorical_eq_with_fill_value(self): + # Categorical RHS should be treated as array-like, not as scalar + left = Series(Categorical(["a", "b", "a"])) + right = left._values # Categorical + + result = left.eq(right, fill_value=left.iloc[0]) + expected = Series([True, True, True]) + tm.assert_series_equal(result, expected) + @pytest.mark.parametrize( "values, op, fill_value", [ From 09a4766b4103e59701ff9a760b52084571f32ab7 Mon Sep 17 00:00:00 2001 From: Praateek Date: Fri, 26 Sep 2025 15:36:12 -0700 Subject: [PATCH 2/3] pc Signed-off-by: Praateek --- pandas/tests/series/test_arithmetic.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index 556a596f37596..9fd91bc559cdb 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -164,7 +164,7 @@ def test_extarray_rhs_datetime_sub_with_fill_value(self): pd.Timestamp("2025-08-21"), pd.Timestamp("2025-08-22"), ], - dtype=np.dtype("datetime64[ns]") + dtype=np.dtype("datetime64[ns]"), ) right = left._values # DatetimeArray @@ -174,7 +174,10 @@ def test_extarray_rhs_datetime_sub_with_fill_value(self): tm.assert_series_equal(result, expected) def test_extarray_rhs_timedelta_sub_with_fill_value(self): - left = Series([Timedelta(days=1), Timedelta(days=2), Timedelta(days=3)], dtype=np.dtype("timedelta64[ns]")) + left = Series( + [Timedelta(days=1), Timedelta(days=2), Timedelta(days=3)], + dtype=np.dtype("timedelta64[ns]"), + ) right = left._values # TimedeltaArray result = left.sub(right, fill_value=left.iloc[0]) From 6a0824d164bc20f172ba727f7d32b3d8791a20e0 Mon Sep 17 00:00:00 2001 From: Praateek Date: Fri, 26 Sep 2025 15:48:21 -0700 Subject: [PATCH 3/3] update tests Signed-off-by: Praateek --- pandas/tests/series/test_arithmetic.py | 63 +++++++++++--------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index 9fd91bc559cdb..16caa55e36c0b 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -155,42 +155,25 @@ def _check_fill(meth, op, a, b, fill_value=0): # should accept axis=0 or axis='rows' op(a, b, axis=0) - def test_extarray_rhs_datetime_sub_with_fill_value(self): - # Ensure ExtensionArray (DatetimeArray) RHS is handled via array-like path - # and does not hit scalar isna branch. - left = Series( - [ - pd.Timestamp("2025-08-20"), - pd.Timestamp("2025-08-21"), - pd.Timestamp("2025-08-22"), - ], - dtype=np.dtype("datetime64[ns]"), - ) - right = left._values # DatetimeArray - - result = left.sub(right, fill_value=left.iloc[0]) - # result dtype may vary (e.g., seconds vs ns), build expected from result dtype - expected = Series(np.zeros(3, dtype=np.dtype("timedelta64[ns]"))) - tm.assert_series_equal(result, expected) + @pytest.mark.parametrize("kind", ["datetime", "timedelta"]) + def test_rhs_extension_array_sub_with_fill_value(self, kind): + if kind == "datetime": + left = Series( + [pd.Timestamp("2025-08-20"), pd.Timestamp("2025-08-21")], + dtype=np.dtype("datetime64[ns]"), + ) + else: + left = Series( + [Timedelta(days=1), Timedelta(days=2)], + dtype=np.dtype("timedelta64[ns]"), + ) - def test_extarray_rhs_timedelta_sub_with_fill_value(self): - left = Series( - [Timedelta(days=1), Timedelta(days=2), Timedelta(days=3)], - dtype=np.dtype("timedelta64[ns]"), - ) - right = left._values # TimedeltaArray + right = ( + left._values + ) # DatetimeArray or TimedeltaArray which is an ExtensionArray result = left.sub(right, fill_value=left.iloc[0]) - expected = Series(np.zeros(3, dtype=np.dtype("timedelta64[ns]"))) - tm.assert_series_equal(result, expected) - - def test_extarray_rhs_period_eq_with_fill_value(self): - # Use equality to validate ExtensionArray RHS path for PeriodArray - left = Series(pd.period_range("2020Q1", periods=3, freq="Q")) - right = left._values # PeriodArray - - result = left.eq(right, fill_value=left.iloc[0]) - expected = Series([True, True, True]) + expected = Series(np.zeros(len(left), dtype=np.dtype("timedelta64[ns]"))) tm.assert_series_equal(result, expected) @@ -442,10 +425,16 @@ def test_comparison_flex_alignment(self, values, op): expected = Series(values, index=list("abcd")) tm.assert_series_equal(result, expected) - def test_extarray_rhs_categorical_eq_with_fill_value(self): - # Categorical RHS should be treated as array-like, not as scalar - left = Series(Categorical(["a", "b", "a"])) - right = left._values # Categorical + @pytest.mark.parametrize( + "left", + [ + Series(Categorical(["a", "b", "a"])), + Series(pd.period_range("2020Q1", periods=3, freq="Q")), + ], + ids=["categorical", "period"], + ) + def test_rhs_extension_array_eq_with_fill_value(self, left): + right = left._values # this is an ExtensionArray result = left.eq(right, fill_value=left.iloc[0]) expected = Series([True, True, True])