Skip to content

DEPR: maybe_promote with pydate #49487

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 7, 2022
Merged
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/v2.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ Removal of prior version deprecations/changes
- Changed behavior of empty data passed into :class:`Series`; the default dtype will be ``object`` instead of ``float64`` (:issue:`29405`)
- Changed the behavior of :meth:`DatetimeIndex.union`, :meth:`DatetimeIndex.intersection`, and :meth:`DatetimeIndex.symmetric_difference` with mismatched timezones to convert to UTC instead of casting to object dtype (:issue:`39328`)
- Changed the behavior of :func:`to_datetime` with argument "now" with ``utc=False`` to match ``Timestamp("now")`` (:issue:`18705`)
- Changed the behavior of :meth:`Index.reindex`, :meth:`Series.reindex`, and :meth:`DataFrame.reindex` with a ``datetime64`` dtype and a ``datetime.date`` object for ``fill_value``; these are no longer considered equivalent to ``datetime.datetime`` objects so the reindex casts to object dtype (:issue:`39767`)
- Changed behavior of :meth:`SparseArray.astype` when given a dtype that is not explicitly ``SparseDtype``, cast to the exact requested dtype rather than silently using a ``SparseDtype`` instead (:issue:`34457`)
- Changed behavior of :meth:`Index.ravel` to return a view on the original :class:`Index` instead of a ``np.ndarray`` (:issue:`36900`)
- Changed behavior of :meth:`Index.to_frame` with explicit ``name=None`` to use ``None`` for the column name instead of the index's name or default ``0`` (:issue:`45523`)
Expand Down
42 changes: 7 additions & 35 deletions pandas/core/dtypes/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from __future__ import annotations

from datetime import (
date,
datetime,
timedelta,
)
Expand Down Expand Up @@ -615,41 +614,14 @@ def _maybe_promote(dtype: np.dtype, fill_value=np.nan):
if inferred == dtype:
return dtype, fv

# TODO(2.0): once this deprecation is enforced, this whole case
# becomes equivalent to:
# dta = DatetimeArray._from_sequence([], dtype="M8[ns]")
# try:
# fv = dta._validate_setitem_value(fill_value)
# return dta.dtype, fv
# except (ValueError, TypeError):
# return _dtype_obj, fill_value
if isinstance(fill_value, date) and not isinstance(fill_value, datetime):
# deprecate casting of date object to match infer_dtype_from_scalar
# and DatetimeArray._validate_setitem_value
try:
fv = Timestamp(fill_value).to_datetime64()
except OutOfBoundsDatetime:
pass
else:
warnings.warn(
"Using a `date` object for fill_value with `datetime64[ns]` "
"dtype is deprecated. In a future version, this will be cast "
"to object dtype. Pass `fill_value=Timestamp(date_obj)` instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return dtype, fv
elif isinstance(fill_value, str):
try:
# explicitly wrap in str to convert np.str_
fv = Timestamp(str(fill_value))
except (ValueError, TypeError):
pass
else:
if isna(fv) or fv.tz is None:
return dtype, fv.asm8
from pandas.core.arrays import DatetimeArray

return np.dtype("object"), fill_value
dta = DatetimeArray._from_sequence([], dtype="M8[ns]")
try:
fv = dta._validate_setitem_value(fill_value)
return dta.dtype, fv
except (ValueError, TypeError):
return _dtype_obj, fill_value

elif issubclass(dtype.type, np.timedelta64):
inferred, fv = infer_dtype_from_scalar(fill_value, pandas_dtype=True)
Expand Down
12 changes: 4 additions & 8 deletions pandas/tests/dtypes/cast/test_promote.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from pandas.core.dtypes.missing import isna

import pandas as pd
import pandas._testing as tm


@pytest.fixture(
Expand Down Expand Up @@ -403,15 +402,12 @@ def test_maybe_promote_any_with_datetime64(any_numpy_dtype_reduced, fill_value):
expected_dtype = np.dtype(object)
exp_val_for_scalar = fill_value

warn = None
msg = "Using a `date` object for fill_value"
if type(fill_value) is datetime.date and dtype.kind == "M":
# Casting date to dt64 is deprecated
warn = FutureWarning
# Casting date to dt64 is deprecated, in 2.0 enforced to cast to object
expected_dtype = np.dtype(object)
exp_val_for_scalar = fill_value

with tm.assert_produces_warning(warn, match=msg):
# stacklevel is chosen to make sense when called from higher-level functions
_check_promote(dtype, fill_value, expected_dtype, exp_val_for_scalar)
_check_promote(dtype, fill_value, expected_dtype, exp_val_for_scalar)


@pytest.mark.parametrize(
Expand Down
14 changes: 8 additions & 6 deletions pandas/tests/frame/methods/test_reindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,30 +136,32 @@ def test_reindex_copies(self):

@td.skip_array_manager_not_yet_implemented
def test_reindex_date_fill_value(self):
# passing date to dt64 is deprecated
# passing date to dt64 is deprecated; enforced in 2.0 to cast to object
arr = date_range("2016-01-01", periods=6).values.reshape(3, 2)
df = DataFrame(arr, columns=["A", "B"], index=range(3))

ts = df.iloc[0, 0]
fv = ts.date()

with tm.assert_produces_warning(FutureWarning):
res = df.reindex(index=range(4), columns=["A", "B", "C"], fill_value=fv)
res = df.reindex(index=range(4), columns=["A", "B", "C"], fill_value=fv)

expected = DataFrame(
{"A": df["A"].tolist() + [ts], "B": df["B"].tolist() + [ts], "C": [ts] * 4}
{"A": df["A"].tolist() + [fv], "B": df["B"].tolist() + [fv], "C": [fv] * 4},
dtype=object,
)
tm.assert_frame_equal(res, expected)

# only reindexing rows
with tm.assert_produces_warning(FutureWarning):
res = df.reindex(index=range(4), fill_value=fv)
res = df.reindex(index=range(4), fill_value=fv)
tm.assert_frame_equal(res, expected[["A", "B"]])

# same with a datetime-castable str
res = df.reindex(
index=range(4), columns=["A", "B", "C"], fill_value="2016-01-01"
)
expected = DataFrame(
{"A": df["A"].tolist() + [ts], "B": df["B"].tolist() + [ts], "C": [ts] * 4},
)
tm.assert_frame_equal(res, expected)

def test_reindex_with_multi_index(self):
Expand Down