Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

DEPR: to_pydatetime return Index[object] #52459

Merged
merged 10 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from 7 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/v2.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ Deprecations
- Deprecated 'broadcast_axis' keyword in :meth:`Series.align` and :meth:`DataFrame.align`, upcast before calling ``align`` with ``left = DataFrame({col: left for col in right.columns}, index=right.index)`` (:issue:`51856`)
- Deprecated the 'axis' keyword in :meth:`.GroupBy.idxmax`, :meth:`.GroupBy.idxmin`, :meth:`.GroupBy.fillna`, :meth:`.GroupBy.take`, :meth:`.GroupBy.skew`, :meth:`.GroupBy.rank`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cummax`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.pct_change`, :meth:`GroupBy.diff`, :meth:`.GroupBy.shift`, and :meth:`DataFrameGroupBy.corrwith`; for ``axis=1`` operate on the underlying :class:`DataFrame` instead (:issue:`50405`, :issue:`51046`)
- Deprecated the "fastpath" keyword in :class:`Categorical` constructor, use :meth:`Categorical.from_codes` instead (:issue:`20110`)
- Deprecated behavior of :meth:`Series.dt.to_pydatetime`, in a future version this will return a :class:`Series` containing python ``datetime`` objects instead of an ``ndarray`` of datetimes; this matches the behavior of other :meth:`Series.dt` properties (:issue:`20306`)
- Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`)
- Deprecated logical operations (``|``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``), wrap a sequence in a :class:`Series` or numpy array before operating instead (:issue:`51521`)
- Deprecated the methods :meth:`Series.bool` and :meth:`DataFrame.bool` (:issue:`51749`)
Expand Down
4 changes: 4 additions & 0 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ def pytest_collection_modifyitems(items, config) -> None:
ignored_doctest_warnings = [
# Docstring divides by zero to show behavior difference
("missing.mask_zero_div_zero", "divide by zero encountered"),
(
"to_pydatetime",
"The behavior of DatetimeProperties.to_pydatetime is deprecated",
),
(
"pandas.core.generic.NDFrame.bool",
"(Series|DataFrame).bool is now deprecated and will be removed "
Expand Down
21 changes: 21 additions & 0 deletions pandas/core/indexes/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
TYPE_CHECKING,
cast,
)
import warnings

import numpy as np

from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.common import (
is_datetime64_dtype,
is_integer_dtype,
Expand Down Expand Up @@ -214,6 +217,15 @@ def _delegate_method(self, name: str, *args, **kwargs):
return result

def to_pydatetime(self):
# GH#20306
warnings.warn(
f"The behavior of {type(self).__name__}.to_pydatetime is deprecated, "
"in a future version this will return a Series containing python "
"datetime objects instead of an ndarray. To retain the old behavior, "
"call `np.array` on the result",
FutureWarning,
stacklevel=find_stack_level(),
)
return cast(ArrowExtensionArray, self._parent.array)._dt_to_pydatetime()

def isocalendar(self):
Expand Down Expand Up @@ -333,6 +345,15 @@ def to_pydatetime(self) -> np.ndarray:
array([datetime.datetime(2018, 3, 10, 0, 0),
datetime.datetime(2018, 3, 10, 0, 0)], dtype=object)
"""
# GH#20306
warnings.warn(
f"The behavior of {type(self).__name__}.to_pydatetime is deprecated, "
"in a future version this will return a Series containing python "
"datetime objects instead of an ndarray. To retain the old behavior, "
"call `np.array` on the result",
FutureWarning,
stacklevel=find_stack_level(),
)
return self._get_values().to_pydatetime()

@property
Expand Down
8 changes: 7 additions & 1 deletion pandas/io/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,13 @@ def insert_data(self) -> tuple[list[str], list[np.ndarray]]:

for i, (_, ser) in enumerate(temp.items()):
if ser.dtype.kind == "M":
d = ser.dt.to_pydatetime()
if isinstance(ser._values, ArrowExtensionArray):
with warnings.catch_warnings():
warnings.filterwarnings("ignore")
# GH#52459 to_pydatetime will return Index[object]
d = ser.dt.to_pydatetime()
Copy link
Member

Choose a reason for hiding this comment

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

Probably good to call np.asarray on d ahead of the deprecation enforcement since data_list is typed list[np.ndarray]

else:
d = ser._values.to_pydatetime()
elif ser.dtype.kind == "m":
vals = ser._values
if isinstance(vals, ArrowExtensionArray):
Expand Down
8 changes: 6 additions & 2 deletions pandas/tests/extension/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2287,12 +2287,16 @@ def test_dt_to_pydatetime():
data = [datetime(2022, 1, 1), datetime(2023, 1, 1)]
ser = pd.Series(data, dtype=ArrowDtype(pa.timestamp("ns")))

result = ser.dt.to_pydatetime()
msg = "The behavior of ArrowTemporalProperties.to_pydatetime is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.dt.to_pydatetime()
expected = np.array(data, dtype=object)
tm.assert_numpy_array_equal(result, expected)
assert all(type(res) is datetime for res in result)

expected = ser.astype("datetime64[ns]").dt.to_pydatetime()
msg = "The behavior of DatetimeProperties.to_pydatetime is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
expected = ser.astype("datetime64[ns]").dt.to_pydatetime()
tm.assert_numpy_array_equal(result, expected)


Expand Down
3 changes: 3 additions & 0 deletions pandas/tests/series/accessors/test_cat_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ def test_dt_accessor_api_for_categorical(self, idx):
if func == "to_period":
# dropping TZ
warnings.simplefilter("ignore", UserWarning)
if func == "to_pydatetime":
# deprecated to return Index[object]
warnings.simplefilter("ignore", FutureWarning)
res = getattr(cat.dt, func)(*args, **kwargs)
exp = getattr(ser.dt, func)(*args, **kwargs)

Expand Down
8 changes: 6 additions & 2 deletions pandas/tests/series/accessors/test_dt_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ def test_dt_namespace_accessor_datetime64(self, freq):
for prop in ok_for_dt_methods:
getattr(ser.dt, prop)

result = ser.dt.to_pydatetime()
msg = "The behavior of DatetimeProperties.to_pydatetime is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.dt.to_pydatetime()
assert isinstance(result, np.ndarray)
assert result.dtype == object

Expand Down Expand Up @@ -152,7 +154,9 @@ def test_dt_namespace_accessor_datetime64tz(self):
for prop in ok_for_dt_methods:
getattr(ser.dt, prop)

result = ser.dt.to_pydatetime()
msg = "The behavior of DatetimeProperties.to_pydatetime is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.dt.to_pydatetime()
assert isinstance(result, np.ndarray)
assert result.dtype == object

Expand Down