From 761ac0e839f34606e5e4f0b08f450cbb3a48504b Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Mon, 25 Aug 2025 04:26:39 +0530 Subject: [PATCH 1/9] DOC: Clarify list-like vs scalar in Series.eq docstring --- pandas/core/series.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index b40e71f2b5b42..52a045c2d0f37 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -6072,7 +6072,9 @@ def eq( Parameters ---------- other : Series or scalar value - The second operand in this operation. + The second operand in this operation. Only `np.ndarray`, `list`, `tuple`, + and `Series` are considered "list-like" by pandas. All other types will + be treated as scalar values. level : int or name Broadcast across a level, matching Index values on the passed MultiIndex level. From 2f98bd4d7ccaa694b8e7871a0ace11f40c91ae0a Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 26 Aug 2025 23:28:34 +0530 Subject: [PATCH 2/9] BUG: Remove special-casing for date objects in DatetimeIndex indexing (GH#62157) --- pandas/core/indexes/base.py | 6 ------ pandas/core/series.py | 4 +--- pandas/tests/frame/indexing/test_indexing.py | 11 +++++++++++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 59ac122e4f9ea..0426949c9e1a5 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -39,7 +39,6 @@ no_default, ) from pandas._libs.tslibs import ( - OutOfBoundsDatetime, Timestamp, tz_compare, ) @@ -6204,11 +6203,6 @@ def _maybe_downcast_for_indexing(self, other: Index) -> tuple[Index, Index]: # standardize on UTC return self.tz_convert("UTC"), other.tz_convert("UTC") - elif self.inferred_type == "date" and isinstance(other, ABCDatetimeIndex): - try: - return type(other)(self), other - except OutOfBoundsDatetime: - return self, other elif self.inferred_type == "timedelta" and isinstance(other, ABCTimedeltaIndex): # TODO: we dont have tests that get here return type(other)(self), other diff --git a/pandas/core/series.py b/pandas/core/series.py index 0972cbff8281e..63c9963fb7eac 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -6073,9 +6073,7 @@ def eq( Parameters ---------- other : Series or scalar value - The second operand in this operation. Only `np.ndarray`, `list`, `tuple`, - and `Series` are considered "list-like" by pandas. All other types will - be treated as scalar values. + The second operand in this operation. level : int or name Broadcast across a level, matching Index values on the passed MultiIndex level. diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 0c99b08cb30c4..f0510ac365957 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1880,6 +1880,17 @@ def test_add_new_column_infer_string(): tm.assert_frame_equal(df, expected) +def test_datetime_indexer_consistency_pyarrow_date32(): + # GH#62158 + ser = Series(["2016-01-01"], dtype="date32[pyarrow]") + ser3 = ser.astype("datetime64[ns]") + dti = Index(ser3) + # All should be consistent + assert dti.get_loc(ser[0]) == 0 + tm.assert_numpy_array_equal(dti.get_indexer(ser.values), [0]) + tm.assert_numpy_array_equal(dti.get_indexer(ser.values.astype(object)), [0]) + + class TestSetitemValidation: # This is adapted from pandas/tests/arrays/masked/test_indexing.py def _check_setitem_invalid(self, df, invalid, indexer): From 69ae80770438a2f1aac4b3e3addd43eafff40e22 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Wed, 27 Aug 2025 02:47:42 +0530 Subject: [PATCH 3/9] BUG: Remove special-casing for date objects in DatetimeIndex indexing (GH#62158) --- pandas/core/indexes/datetimes.py | 8 +++++++- pandas/tests/frame/methods/test_asfreq.py | 2 +- pandas/tests/indexes/datetimes/test_indexing.py | 15 ++++++++++----- pandas/tests/series/test_arithmetic.py | 3 ++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index ce6ea1ed980dd..f7dea0a6184b4 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -629,7 +629,13 @@ def get_loc(self, key): def _maybe_cast_slice_bound(self, label, side: str): # GH#42855 handle date here instead of get_slice_bound if isinstance(label, dt.date) and not isinstance(label, dt.datetime): - # Pandas supports slicing with dates, treated as datetimes at midnight. + warnings.warn( + "Indexing/slicing with datetime.date is deprecated and will be removed " + "in a future version of pandas. Please convert to pd.Timestamp or " + "datetime64[ns] before indexing.", + FutureWarning, + stacklevel=2, + ) # https://github.com/pandas-dev/pandas/issues/31501 label = Timestamp(label).to_pydatetime() diff --git a/pandas/tests/frame/methods/test_asfreq.py b/pandas/tests/frame/methods/test_asfreq.py index 1c3c41e2e0299..4b60834cae53f 100644 --- a/pandas/tests/frame/methods/test_asfreq.py +++ b/pandas/tests/frame/methods/test_asfreq.py @@ -190,7 +190,7 @@ def test_asfreq_with_date_object_index(self, frame_or_series): ts = frame_or_series(np.random.default_rng(2).standard_normal(20), index=rng) ts2 = ts.copy() - ts2.index = [x.date() for x in ts2.index] + ts2.index = to_datetime([x.date() for x in ts2.index]) result = ts2.asfreq("4h", method="ffill") expected = ts.asfreq("4h", method="ffill") diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index c44345273466c..603b28ed0fb65 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -562,17 +562,22 @@ def test_get_indexer(self): idx.get_indexer(idx[[0]], method="nearest", tolerance="foo") @pytest.mark.parametrize( - "target", + "target, expected", [ - [date(2020, 1, 1), Timestamp("2020-01-02")], - [Timestamp("2020-01-01"), date(2020, 1, 2)], + ( + [date(2020, 1, 1), Timestamp("2020-01-02")], + np.array([-1, 1], dtype=np.intp), + ), + ( + [Timestamp("2020-01-01"), Timestamp(date(2020, 1, 2))], + np.array([0, 1], dtype=np.intp), + ), ], ) - def test_get_indexer_mixed_dtypes(self, target): + def test_get_indexer_mixed_dtypes(self, target, expected): # https://github.com/pandas-dev/pandas/issues/33741 values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")]) result = values.get_indexer(target) - expected = np.array([0, 1], dtype=np.intp) tm.assert_numpy_array_equal(result, expected) @pytest.mark.parametrize( diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index 35a9742d653db..5c560b9981f85 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -763,7 +763,8 @@ def test_align_date_objects_with_datetimeindex(self): ts_slice = ts[5:] ts2 = ts_slice.copy() - ts2.index = [x.date() for x in ts2.index] + # Explicitly convert date objects to Timestamps for alignment + ts2.index = [pd.Timestamp(x.date()) for x in ts2.index] result = ts + ts2 result2 = ts2 + ts From 74410461a0a6dfea9f7502a49f48b6c205820b30 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 29 Aug 2025 13:24:05 +0530 Subject: [PATCH 4/9] Revert unintended changes in datetimes.py and test_asfreq.py --- pandas/core/indexes/datetimes.py | 15 +++------------ pandas/tests/frame/methods/test_asfreq.py | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index f7dea0a6184b4..9adbaadbdcdc8 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -2,10 +2,7 @@ import datetime as dt import operator -from typing import ( - TYPE_CHECKING, - Self, -) +from typing import TYPE_CHECKING import warnings import numpy as np @@ -58,6 +55,7 @@ DtypeObj, Frequency, IntervalClosedType, + Self, TimeAmbiguous, TimeNonexistent, npt, @@ -222,7 +220,6 @@ class DatetimeIndex(DatetimeTimedeltaMixin): to_pydatetime to_series to_frame - to_julian_date month_name day_name mean @@ -629,13 +626,7 @@ def get_loc(self, key): def _maybe_cast_slice_bound(self, label, side: str): # GH#42855 handle date here instead of get_slice_bound if isinstance(label, dt.date) and not isinstance(label, dt.datetime): - warnings.warn( - "Indexing/slicing with datetime.date is deprecated and will be removed " - "in a future version of pandas. Please convert to pd.Timestamp or " - "datetime64[ns] before indexing.", - FutureWarning, - stacklevel=2, - ) + # Pandas supports slicing with dates, treated as datetimes at midnight. # https://github.com/pandas-dev/pandas/issues/31501 label = Timestamp(label).to_pydatetime() diff --git a/pandas/tests/frame/methods/test_asfreq.py b/pandas/tests/frame/methods/test_asfreq.py index 4b60834cae53f..1c3c41e2e0299 100644 --- a/pandas/tests/frame/methods/test_asfreq.py +++ b/pandas/tests/frame/methods/test_asfreq.py @@ -190,7 +190,7 @@ def test_asfreq_with_date_object_index(self, frame_or_series): ts = frame_or_series(np.random.default_rng(2).standard_normal(20), index=rng) ts2 = ts.copy() - ts2.index = to_datetime([x.date() for x in ts2.index]) + ts2.index = [x.date() for x in ts2.index] result = ts2.asfreq("4h", method="ffill") expected = ts.asfreq("4h", method="ffill") From 149b9c4939c2be367f6db7cd08083a454a6e7889 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Fri, 29 Aug 2025 13:38:21 +0530 Subject: [PATCH 5/9] Revert unintended changes in datetimes.py and test_asfreq.py --- pandas/tests/frame/indexing/test_indexing.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index f0510ac365957..b89904b632c33 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1887,8 +1887,10 @@ def test_datetime_indexer_consistency_pyarrow_date32(): dti = Index(ser3) # All should be consistent assert dti.get_loc(ser[0]) == 0 - tm.assert_numpy_array_equal(dti.get_indexer(ser.values), [0]) - tm.assert_numpy_array_equal(dti.get_indexer(ser.values.astype(object)), [0]) + tm.assert_numpy_array_equal(dti.get_indexer(ser.values), np.array([0])) + tm.assert_numpy_array_equal( + dti.get_indexer(ser.values.astype(object)), np.array([0]) + ) class TestSetitemValidation: From 6c8b76a48916e0b0f9292b4b072329256c6eb922 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sat, 30 Aug 2025 02:35:15 +0530 Subject: [PATCH 6/9] Remove unintended changes in pandas/core/indexes/datetimes.py --- pandas/core/indexes/datetimes.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 9adbaadbdcdc8..ce6ea1ed980dd 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -2,7 +2,10 @@ import datetime as dt import operator -from typing import TYPE_CHECKING +from typing import ( + TYPE_CHECKING, + Self, +) import warnings import numpy as np @@ -55,7 +58,6 @@ DtypeObj, Frequency, IntervalClosedType, - Self, TimeAmbiguous, TimeNonexistent, npt, @@ -220,6 +222,7 @@ class DatetimeIndex(DatetimeTimedeltaMixin): to_pydatetime to_series to_frame + to_julian_date month_name day_name mean From 0a0f582812eae3579043c955fded8bfeb2891bc0 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sun, 31 Aug 2025 15:00:28 +0530 Subject: [PATCH 7/9] API: Remove implicit matching of datetime.date with DatetimeIndex/Timestamp in indexing and merging tests --- pandas/tests/frame/methods/test_asfreq.py | 7 ++++--- pandas/tests/indexes/datetimes/test_indexing.py | 7 ++++--- pandas/tests/reshape/merge/test_merge.py | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pandas/tests/frame/methods/test_asfreq.py b/pandas/tests/frame/methods/test_asfreq.py index 1c3c41e2e0299..727011ece9dc7 100644 --- a/pandas/tests/frame/methods/test_asfreq.py +++ b/pandas/tests/frame/methods/test_asfreq.py @@ -192,9 +192,10 @@ def test_asfreq_with_date_object_index(self, frame_or_series): ts2 = ts.copy() ts2.index = [x.date() for x in ts2.index] - result = ts2.asfreq("4h", method="ffill") - expected = ts.asfreq("4h", method="ffill") - tm.assert_equal(result, expected) + with pytest.raises( + TypeError, match="Cannot compare Timestamp with datetime.date" + ): + ts2.asfreq("4h", method="ffill") def test_asfreq_with_unsorted_index(self, frame_or_series): # GH#39805 diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index 603b28ed0fb65..a0d116fee35ba 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -516,9 +516,10 @@ class TestGetIndexer: def test_get_indexer_date_objs(self): rng = date_range("1/1/2000", periods=20) - result = rng.get_indexer(rng.map(lambda x: x.date())) - expected = rng.get_indexer(rng) - tm.assert_numpy_array_equal(result, expected) + with pytest.raises( + TypeError, match="Cannot compare Timestamp with datetime.date" + ): + rng.get_indexer(rng.map(lambda x: x.date())) def test_get_indexer(self): idx = date_range("2000-01-01", periods=3) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index a8e29ef03acc2..f129bc8631606 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -2132,9 +2132,9 @@ def test_dtype_on_categorical_dates(self): expected_outer = DataFrame( [ - [pd.Timestamp("2001-01-01").date(), 1.1, 1.3], - [pd.Timestamp("2001-01-02").date(), 1.3, np.nan], - [pd.Timestamp("2001-01-03").date(), np.nan, 1.4], + [pd.Timestamp("2001-01-01"), 1.1, 1.3], + [pd.Timestamp("2001-01-02"), 1.3, np.nan], + [pd.Timestamp("2001-01-03"), np.nan, 1.4], ], columns=["date", "num2", "num4"], ) @@ -2142,7 +2142,7 @@ def test_dtype_on_categorical_dates(self): tm.assert_frame_equal(result_outer, expected_outer) expected_inner = DataFrame( - [[pd.Timestamp("2001-01-01").date(), 1.1, 1.3]], + [[pd.Timestamp("2001-01-01"), 1.1, 1.3]], columns=["date", "num2", "num4"], ) result_inner = merge(df, df2, how="inner", on=["date"]) From 30a87b4b604330a0ccb711535b9ce3f4fed6338a Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Sun, 31 Aug 2025 15:29:40 +0530 Subject: [PATCH 8/9] API: Remove implicit matching of datetime.date with DatetimeIndex/Timestamp in indexing and merging tests --- pandas/tests/indexes/datetimes/test_indexing.py | 7 +++---- pandas/tests/reshape/merge/test_merge.py | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index a0d116fee35ba..7c1c7d5ed4816 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -516,10 +516,9 @@ class TestGetIndexer: def test_get_indexer_date_objs(self): rng = date_range("1/1/2000", periods=20) - with pytest.raises( - TypeError, match="Cannot compare Timestamp with datetime.date" - ): - rng.get_indexer(rng.map(lambda x: x.date())) + result = rng.get_indexer(rng.map(lambda x: x.date())) + expected = np.full(len(rng), -1, dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) def test_get_indexer(self): idx = date_range("2000-01-01", periods=3) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index f129bc8631606..dc900e8b638ca 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -2132,9 +2132,9 @@ def test_dtype_on_categorical_dates(self): expected_outer = DataFrame( [ - [pd.Timestamp("2001-01-01"), 1.1, 1.3], - [pd.Timestamp("2001-01-02"), 1.3, np.nan], - [pd.Timestamp("2001-01-03"), np.nan, 1.4], + [date("2001-01-01"), 1.1, 1.3], + [date("2001-01-02"), 1.3, np.nan], + [date("2001-01-03"), np.nan, 1.4], ], columns=["date", "num2", "num4"], ) @@ -2142,7 +2142,7 @@ def test_dtype_on_categorical_dates(self): tm.assert_frame_equal(result_outer, expected_outer) expected_inner = DataFrame( - [[pd.Timestamp("2001-01-01"), 1.1, 1.3]], + [[date("2001-01-01"), 1.1, 1.3]], columns=["date", "num2", "num4"], ) result_inner = merge(df, df2, how="inner", on=["date"]) From f8e4974f227592eaaf4508191c84988944a0760c Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Mon, 1 Sep 2025 10:25:32 +0530 Subject: [PATCH 9/9] API: Remove implicit matching of datetime.date with DatetimeIndex/Timestamp in indexing and merging tests --- pandas/tests/reshape/merge/test_merge.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py index dc900e8b638ca..416805e8bfa72 100644 --- a/pandas/tests/reshape/merge/test_merge.py +++ b/pandas/tests/reshape/merge/test_merge.py @@ -2132,9 +2132,9 @@ def test_dtype_on_categorical_dates(self): expected_outer = DataFrame( [ - [date("2001-01-01"), 1.1, 1.3], - [date("2001-01-02"), 1.3, np.nan], - [date("2001-01-03"), np.nan, 1.4], + [date(2001, 1, 1), 1.1, 1.3], + [date(2001, 1, 2), 1.3, np.nan], + [date(2001, 1, 3), np.nan, 1.4], ], columns=["date", "num2", "num4"], ) @@ -2142,7 +2142,7 @@ def test_dtype_on_categorical_dates(self): tm.assert_frame_equal(result_outer, expected_outer) expected_inner = DataFrame( - [[date("2001-01-01"), 1.1, 1.3]], + [[date(2001, 1, 1), 1.1, 1.3]], columns=["date", "num2", "num4"], ) result_inner = merge(df, df2, how="inner", on=["date"])