Skip to content

Commit ef08105

Browse files
jbrockmendelclaude
andauthored
DEPR: deprecate dates-with-datetime64 in _maybe_downcast_for_indexing (#64871)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0b27819 commit ef08105

6 files changed

Lines changed: 41 additions & 5 deletions

File tree

doc/source/whatsnew/v3.1.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ Deprecations
103103
- Deprecated arithmetic operations between pandas objects (:class:`DataFrame`, :class:`Series`, :class:`Index`, and pandas-implemented :class:`ExtensionArray` subclasses) and list-likes other than ``list``, ``np.ndarray``, :class:`ExtensionArray`, :class:`Index`, :class:`Series`, :class:`DataFrame`. For e.g. ``tuple`` or ``range``, explicitly cast these to a supported object instead. In a future version, these will be treated as scalar-like for pointwise operation (:issue:`62423`)
104104
- Deprecated automatic dtype promotion when reindexing with a ``fill_value`` that cannot be held by the original dtype. Explicitly cast to a common dtype instead (:issue:`53910`)
105105
- Deprecated grouping by an index level name when the name matches multiple levels of a :class:`MultiIndex`. Use the level number instead (:issue:`49434`)
106+
- Deprecated implicit conversion of ``datetime.date`` objects to :class:`Timestamp` when indexing or joining a :class:`DatetimeIndex`. Use :func:`to_datetime` to explicitly convert to :class:`DatetimeIndex` instead (:issue:`62158`)
106107
- Deprecated passing a ``dict`` to :meth:`DataFrame.from_records`, use the :class:`DataFrame` constructor or :meth:`DataFrame.from_dict` instead (:issue:`22025`)
107108
- Deprecated passing a non-dict (e.g. a list of dicts) to :meth:`DataFrame.from_dict`. Use the :class:`DataFrame` constructor instead (:issue:`58862`)
108109
- Deprecated passing unnecessary ``*args`` and ``**kwargs`` to :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.cummax`, :meth:`.SeriesGroupBy.skew`, :meth:`.DataFrameGroupBy.skew`, :meth:`.SeriesGroupBy.take`, and :meth:`.DataFrameGroupBy.take`. The ``skipna`` parameter for the cum* methods is now an explicit keyword argument (:issue:`50407`)

pandas/core/indexes/base.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6603,9 +6603,18 @@ def _maybe_downcast_for_indexing(self, other: Index) -> tuple[Index, Index]:
66036603

66046604
elif self.inferred_type == "date" and isinstance(other, ABCDatetimeIndex):
66056605
try:
6606-
return type(other)(self), other
6606+
result = type(other)(self), other
66076607
except OutOfBoundsDatetime:
66086608
return self, other
6609+
else:
6610+
warnings.warn(
6611+
# GH#62158 deprecate special-case treatment of date objects
6612+
"Indexing a DatetimeIndex with a sequence of datetime.date "
6613+
"objects is deprecated. Use Timestamp objects instead.",
6614+
Pandas4Warning,
6615+
stacklevel=find_stack_level(),
6616+
)
6617+
return result
66096618
elif self.inferred_type == "timedelta" and isinstance(other, ABCTimedeltaIndex):
66106619
# TODO: we dont have tests that get here
66116620
return type(other)(self), other

pandas/tests/frame/methods/test_asfreq.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
from pandas._libs.tslibs.offsets import MonthEnd
7+
from pandas.errors import Pandas4Warning
78

89
from pandas import (
910
DataFrame,
@@ -192,7 +193,10 @@ def test_asfreq_with_date_object_index(self, frame_or_series):
192193
ts2 = ts.copy()
193194
ts2.index = [x.date() for x in ts2.index]
194195

195-
result = ts2.asfreq("4h", method="ffill")
196+
# GH#62158 date-object Index reindexed against DatetimeIndex
197+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
198+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
199+
result = ts2.asfreq("4h", method="ffill")
196200
expected = ts.asfreq("4h", method="ffill")
197201
tm.assert_equal(result, expected)
198202

pandas/tests/indexes/datetimes/test_indexing.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,11 @@ def test_get_indexer(self):
606606
def test_get_indexer_mixed_dtypes(self, target):
607607
# https://github.com/pandas-dev/pandas/issues/33741
608608
values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
609-
result = values.get_indexer(target)
609+
# GH#62158 mixed date/Timestamp list infers as "date", triggering
610+
# the _maybe_downcast_for_indexing fallback
611+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
612+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
613+
result = values.get_indexer(target)
610614
expected = np.array([0, 1], dtype=np.intp)
611615
tm.assert_numpy_array_equal(result, expected)
612616

@@ -619,9 +623,12 @@ def test_get_indexer_mixed_dtypes(self, target):
619623
],
620624
)
621625
def test_get_indexer_out_of_bounds_date(self, target, positions):
626+
# GH#62158
622627
values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
623628

624-
result = values.get_indexer(target)
629+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
630+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
631+
result = values.get_indexer(target)
625632
expected = np.array(positions, dtype=np.intp)
626633
tm.assert_numpy_array_equal(result, expected)
627634

pandas/tests/indexes/datetimes/test_join.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from datetime import (
2+
date,
23
datetime,
34
timezone,
45
)
56

67
import numpy as np
78
import pytest
89

10+
from pandas.errors import Pandas4Warning
11+
912
from pandas import (
1013
DataFrame,
1114
DatetimeIndex,
@@ -151,3 +154,14 @@ def test_join_preserves_freq(self, tz):
151154
assert result.freq is None
152155
expected = dti.delete(5)
153156
tm.assert_index_equal(result, expected)
157+
158+
159+
def test_join_date_objects_with_datetimeindex():
160+
# GH#62158
161+
dti = date_range("2016-01-01", periods=3)
162+
date_idx = Index([date(2016, 1, 1), date(2016, 1, 2), date(2016, 1, 3)])
163+
164+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
165+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
166+
result = dti.join(date_idx, how="inner")
167+
tm.assert_index_equal(result, dti)

pandas/tests/series/test_arithmetic.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,8 @@ def test_align_date_objects_with_datetimeindex(self):
895895
ts2 = ts_slice.copy()
896896
ts2.index = [x.date() for x in ts2.index]
897897

898-
msg = "object-dtype Index of datetime.date objects is deprecated"
898+
# GH#62158 alignment joins date-object Index with DatetimeIndex
899+
msg = "Alignment of a DataFrame/Series with a DatetimeIndex"
899900
with tm.assert_produces_warning(Pandas4Warning, match=msg):
900901
result = ts + ts2
901902
result2 = ts2 + ts

0 commit comments

Comments
 (0)