Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ Other API changes
- :meth:`CategoricalIndex.append` no longer attempts to cast different-dtype indexes to the caller's dtype (:issue:`41626`)
- :meth:`ExtensionDtype.construct_array_type` is now a regular method instead of a ``classmethod`` (:issue:`58663`)
- Comparison operations between :class:`Index` and :class:`Series` now consistently return :class:`Series` regardless of which object is on the left or right (:issue:`36759`)
- Indexing and comparison with sequences of ``datetime.date`` objects are now consistent with scalar ``datetime.date`` behavior in :class:`DatetimeIndex` (:issue:`62158`)
- Numpy functions like ``np.isinf`` that return a bool dtype when called on a :class:`Index` object now return a bool-dtype :class:`Index` instead of ``np.ndarray`` (:issue:`52676`)

.. ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class DatetimeArray(dtl.TimelikeOps, dtl.DatelikeOps):
_is_recognized_dtype: Callable[[DtypeObj], bool] = lambda x: lib.is_np_dtype(
x, "M"
) or isinstance(x, DatetimeTZDtype)
_infer_matches = ("datetime", "datetime64", "date")
_infer_matches = ("datetime", "datetime64")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might be worth doing, but the motivating issue I opened was only about the check in indexes.base

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my testing after removing the check in indexes.base, the example in the original issue still fails because of _infer_matches called under _validate_listlike

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, looking at the other places where _infer_matches is used, im OK with that change, but will need to make sure we have appropriate testing and whatsnew note for e.g. equals

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this change affects equals too, so we'll want test+whatsnew for that?


@property
def _scalar_type(self) -> type[Timestamp]:
Expand Down
6 changes: 0 additions & 6 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
no_default,
)
from pandas._libs.tslibs import (
OutOfBoundsDatetime,
Timestamp,
tz_compare,
)
Expand Down Expand Up @@ -6221,11 +6220,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
Expand Down
12 changes: 6 additions & 6 deletions pandas/tests/frame/methods/test_asfreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@ def test_asfreq_fillvalue(self):
tm.assert_series_equal(expected_series, actual_series)

def test_asfreq_with_date_object_index(self, frame_or_series):
# GH#62158 date objects lose indexing special case
rng = date_range("1/1/2000", periods=20)
ts = frame_or_series(np.random.default_rng(2).standard_normal(20), index=rng)
ts.index = [x.date() for x in ts.index]

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"
):
ts.asfreq("4h", method="ffill")

def test_asfreq_with_unsorted_index(self, frame_or_series):
# GH#39805
Expand Down
23 changes: 15 additions & 8 deletions pandas/tests/indexes/datetimes/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,10 +536,11 @@ def test_get_indexer_pyarrow(self, as_td):
tm.assert_numpy_array_equal(result2, expected)

def test_get_indexer_date_objs(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of removing the test entirely, test the new behavior, with a comment about the history/change

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(havent looked closely, but this likely applies to tests below)

# GH#62158 date objects lose indexing special case
rng = date_range("1/1/2000", periods=20)

result = rng.get_indexer(rng.map(lambda x: x.date()))
expected = rng.get_indexer(rng)

expected = np.full(len(rng), -1, dtype=np.intp)
tm.assert_numpy_array_equal(result, expected)

def test_get_indexer(self):
Expand Down Expand Up @@ -584,17 +585,23 @@ 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"), date(2020, 1, 2)],
np.array([0, -1], dtype=np.intp),
),
],
)
def test_get_indexer_mixed_dtypes(self, target):
# https://github.com/pandas-dev/pandas/issues/33741
def test_get_indexer_mixed_dtypes(self, target, expected):
# GH#33741 regression test: mixed dtypes should not error
# GH#62158 date objects lose indexing special case
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(
Expand Down
27 changes: 23 additions & 4 deletions pandas/tests/io/parser/dtypes/test_categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,24 @@ def test_categorical_coerces_numeric(all_parsers):
def test_categorical_coerces_datetime(all_parsers):
parser = all_parsers
dti = pd.DatetimeIndex(["2017-01-01", "2018-01-01", "2019-01-01"], freq=None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this removed?


dtype = {"b": CategoricalDtype(dti)}

data = "b\n2017-01-01\n2018-01-01\n2019-01-01"
expected = DataFrame({"b": Categorical(dtype["b"].categories)})

result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_frame_equal(result, expected)
if parser.engine == "pyarrow":
msg = "Constructing a Categorical with a dtype and values containing"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we getting the warning here? seems like something we wouldn't want to show users

with tm.assert_produces_warning(
Pandas4Warning, match=msg, check_stacklevel=False
):
result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_series_equal(
result["b"].isna(), pd.Series([True, True, True], name="b")
Copy link
Member

@jbrockmendel jbrockmendel Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just assert result["b"].isna().all()

)
else:
result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_frame_equal(result, expected)


def test_categorical_coerces_timestamp(all_parsers):
Expand All @@ -291,8 +302,16 @@ def test_categorical_coerces_timestamp(all_parsers):
data = "b\n2014-01-01\n2014-01-01"
expected = DataFrame({"b": Categorical([Timestamp("2014")] * 2)})

result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_frame_equal(result, expected)
if parser.engine == "pyarrow":
msg = "Constructing a Categorical with a dtype and values containing"
with tm.assert_produces_warning(
Pandas4Warning, match=msg, check_stacklevel=False
):
result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_series_equal(result["b"].isna(), pd.Series([True, True], name="b"))
else:
result = parser.read_csv(StringIO(data), dtype=dtype)
tm.assert_frame_equal(result, expected)


def test_categorical_coerces_timedelta(all_parsers):
Expand Down
8 changes: 5 additions & 3 deletions pandas/tests/series/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ def test_datetime_understood(self, unit):
tm.assert_series_equal(result, expected)

def test_align_date_objects_with_datetimeindex(self):
# GH#62158: datetime.date objects no longer auto-align with Timestamps
rng = date_range("1/1/2000", periods=20)
ts = Series(np.random.default_rng(2).standard_normal(20), index=rng)

Expand All @@ -849,10 +850,11 @@ def test_align_date_objects_with_datetimeindex(self):

result = ts + ts2
result2 = ts2 + ts
expected = ts + ts[5:]
expected.index = expected.index._with_freq(None)
expected = Series(dtype=float, index=result.index)
expected2 = Series(dtype=float, index=result2.index)

tm.assert_series_equal(result, expected)
tm.assert_series_equal(result2, expected)
tm.assert_series_equal(result2, expected2)


class TestNamePreservation:
Expand Down
Loading