Skip to content

Commit 9176a75

Browse files
committed
Revert "DEPR: warn on silent dtype changes during setitem-with-expansion"
This reverts commit 817819d.
1 parent 817819d commit 9176a75

5 files changed

Lines changed: 12 additions & 87 deletions

File tree

doc/source/whatsnew/v0.19.0.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,6 @@ A ``Series`` will now correctly promote its dtype for assignment with incompat v
762762
**New behavior**:
763763

764764
.. ipython:: python
765-
:okwarning:
766765
767766
s["a"] = pd.Timestamp("2016-01-01")
768767
s["b"] = 3.0

doc/source/whatsnew/v3.1.0.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ Deprecations
106106
- Deprecated passing a non-dict (e.g. a list of dicts) to :meth:`DataFrame.from_dict`. Use the :class:`DataFrame` constructor instead (:issue:`58862`)
107107
- 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`)
108108
- Deprecated setting values with :meth:`DataFrame.at` and :meth:`Series.at` when the key does not exist in the index, which previously expanded the object. Use ``.loc`` instead (:issue:`48323`)
109-
- Deprecated silent dtype changes during setitem-with-expansion (e.g. ``ser.loc[new_key] = incompatible_value``). In a future version, the existing dtype will be retained instead of being silently changed. To keep the current behavior, cast the object to the desired dtype before the operation. The exception is int/uint to float when the value introduces ``NaN``, which is still allowed per PDEP-6 (:issue:`45070`)
110109
- Deprecated the ``.name`` property of offset objects (e.g., :class:`~pandas.tseries.offsets.Day`, :class:`~pandas.tseries.offsets.Hour`). Use ``.rule_code`` instead (:issue:`64207`)
111110
- Deprecated the ``dropna`` keyword in :meth:`DataFrame.to_hdf`, :meth:`HDFStore.put`, :meth:`HDFStore.append`, and :meth:`HDFStore.append_to_multiple`, and the ``io.hdf.dropna_table`` option. Use :meth:`DataFrame.dropna` before writing instead (:issue:`32038`)
112111
- Deprecated the ``float_precision`` argument in :func:`read_csv`, :func:`read_table`, and :func:`read_fwf`. All float precision modes now use the same converter (:issue:`64395`)

pandas/core/frame.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14492,9 +14492,7 @@ def _append_internal(
1449214492
for i in range(len(self.columns)):
1449314493
arr = self.iloc[:, i].array
1449414494

14495-
casted = infer_and_maybe_downcast(
14496-
arr, row_df.iloc[:, i]._values, warn_if_cast=False
14497-
)
14495+
casted = infer_and_maybe_downcast(arr, row_df.iloc[:, i]._values)
1449814496

1449914497
row_df.isetitem(i, casted)
1450014498

pandas/core/indexing.py

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
construct_1d_array_from_inferred_fill_value,
6161
infer_fill_value,
6262
is_valid_na_for_dtype,
63-
isna,
6463
na_value_for_dtype,
6564
)
6665

@@ -962,29 +961,20 @@ def __setitem__(self, key, value) -> None:
962961
iloc._setitem_with_indexer(indexer, value, self.name)
963962

964963
if self.obj.shape[0] != orig_nrows:
965-
# For empty DataFrames, suppress the deprecation warning —
966-
# the placeholder dtypes aren't meaningful to preserve.
967-
warn = self.obj.ndim == 1 or orig_nrows > 0
968-
self._post_expansion_casting(
969-
orig_dtype_info, orig_columns, warn_if_cast=warn
970-
)
964+
self._post_expansion_casting(orig_dtype_info, orig_columns)
971965

972966
def _post_expansion_casting(
973967
self,
974968
orig_dtype_info: DtypeObj | npt.NDArray[np.object_],
975969
orig_columns: Index | None,
976-
*,
977-
warn_if_cast: bool = True,
978970
) -> None:
979971
# setitem-with-expansion added new rows. Try to retain
980972
# original dtypes
981973
if self.obj.ndim == 1:
982974
assert not isinstance(orig_dtype_info, np.ndarray)
983975
if orig_dtype_info != self.obj.dtype:
984976
orig_arr = pd_array([], dtype=orig_dtype_info)
985-
new_arr = infer_and_maybe_downcast(
986-
orig_arr, self.obj._values, warn_if_cast=warn_if_cast
987-
)
977+
new_arr = infer_and_maybe_downcast(orig_arr, self.obj._values)
988978
new_ser = self.obj._constructor(
989979
new_arr, index=self.obj.index, name=self.obj.name
990980
)
@@ -1000,9 +990,7 @@ def _post_expansion_casting(
1000990
for idx in np.flatnonzero(changed_dtypes):
1001991
orig_arr = pd_array([], dtype=orig_dtypes[idx])
1002992
new_arr = infer_and_maybe_downcast(
1003-
orig_arr,
1004-
self.obj.iloc[:, idx]._values,
1005-
warn_if_cast=warn_if_cast,
993+
orig_arr, self.obj.iloc[:, idx]._values
1006994
)
1007995
self.obj.isetitem(idx, new_arr)
1008996

@@ -1014,9 +1002,7 @@ def _post_expansion_casting(
10141002
if new_dtype != orig_dtype:
10151003
orig_arr = pd_array([], dtype=orig_dtype)
10161004
new_arr = infer_and_maybe_downcast(
1017-
orig_arr,
1018-
self.obj[col]._values,
1019-
warn_if_cast=warn_if_cast,
1005+
orig_arr, self.obj[col]._values
10201006
)
10211007
self.obj[col] = new_arr
10221008
else:
@@ -2872,15 +2858,12 @@ def _setitem_with_indexer_missing(self, indexer, value):
28722858
# Every NA value is suitable for object, no conversion needed
28732859
value = na_value_for_dtype(self.obj.dtype, compat=False)
28742860

2875-
new_values = infer_and_maybe_downcast(
2876-
self.obj.array, [value], warn_if_cast=False
2877-
)
2861+
new_values = infer_and_maybe_downcast(self.obj.array, [value])
28782862

28792863
if len(self.obj._values):
28802864
# GH#22717 handle casting compatibility that np.concatenate
28812865
# does incorrectly
28822866
new_values = concat_compat([self.obj._values, new_values])
2883-
28842867
self.obj._mgr = self.obj._constructor(
28852868
new_values, index=new_index, name=self.obj.name
28862869
)._mgr
@@ -3555,12 +3538,7 @@ def check_dict_or_set_indexers(key) -> None:
35553538
)
35563539

35573540

3558-
def infer_and_maybe_downcast(
3559-
orig: ExtensionArray,
3560-
new_arr,
3561-
*,
3562-
warn_if_cast: bool = True,
3563-
) -> ArrayLike:
3541+
def infer_and_maybe_downcast(orig: ExtensionArray, new_arr) -> ArrayLike:
35643542
new_arr = orig._cast_pointwise_result(new_arr)
35653543

35663544
dtype = orig.dtype
@@ -3572,36 +3550,4 @@ def infer_and_maybe_downcast(
35723550

35733551
if is_np_dtype(new_arr.dtype, "f") and is_np_dtype(dtype, "iu"):
35743552
new_arr = maybe_downcast_to_dtype(new_arr, dtype)
3575-
elif (
3576-
warn_if_cast and is_np_dtype(dtype, "fc") and is_np_dtype(new_arr.dtype, "iufc")
3577-
):
3578-
# _cast_pointwise_result may have inferred a narrower numeric dtype
3579-
# (e.g. int64 from a float64 array with integer values).
3580-
# Cast back to the original dtype since float/complex can hold
3581-
# int/float values without loss.
3582-
new_arr = new_arr.astype(dtype, copy=False)
3583-
3584-
if warn_if_cast and new_arr.dtype != dtype:
3585-
# PDEP6 exception: int/uint -> float when result contains NaN
3586-
pdep6_allowed = (
3587-
is_np_dtype(dtype, "iu")
3588-
and is_np_dtype(new_arr.dtype, "f")
3589-
and isna(new_arr).any()
3590-
)
3591-
# If the original dtype can hold the new values (e.g. object
3592-
# can hold anything), retaining it in the future is fine.
3593-
orig_can_hold = can_hold_element(orig, new_arr)
3594-
if not pdep6_allowed and not orig_can_hold:
3595-
warnings.warn(
3596-
f"Setting an item of incompatible dtype is deprecated "
3597-
f"and will raise in a future version of pandas. "
3598-
f"The existing dtype is {dtype} but the new values "
3599-
f"have dtype {new_arr.dtype}. In a future version, the "
3600-
f"existing dtype will be retained. Cast the object to "
3601-
f"{new_arr.dtype} before this operation to retain the "
3602-
f"current behavior.",
3603-
Pandas4Warning,
3604-
stacklevel=find_stack_level(),
3605-
)
3606-
36073553
return new_arr

pandas/tests/series/indexing/test_setitem.py

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010

1111
from pandas.compat import HAS_PYARROW
1212
from pandas.compat.numpy import np_version_gt2
13-
from pandas.errors import (
14-
IndexingError,
15-
Pandas4Warning,
16-
)
13+
from pandas.errors import IndexingError
1714

1815
from pandas.core.dtypes.common import is_list_like
1916

@@ -521,30 +518,21 @@ def test_append_timedelta_does_not_cast(self, td, using_infer_string, request):
521518
# GH#22717 inserting a Timedelta should _not_ cast to int64
522519
expected = Series(["x", td], index=[0, "td"], dtype=object)
523520

524-
# With infer_string, dtype changes from str -> object; without it,
525-
# the Series is already object so no dtype change occurs.
526-
warn = Pandas4Warning if using_infer_string else None
527-
528521
ser = Series(["x"])
529-
with tm.assert_produces_warning(warn):
530-
ser["td"] = td
522+
ser["td"] = td
531523
tm.assert_series_equal(ser, expected)
532524
assert isinstance(ser["td"], Timedelta)
533525

534526
ser = Series(["x"])
535-
with tm.assert_produces_warning(warn):
536-
ser.loc["td"] = Timedelta("9 days")
527+
ser.loc["td"] = Timedelta("9 days")
537528
tm.assert_series_equal(ser, expected)
538529
assert isinstance(ser["td"], Timedelta)
539530

540531
def test_setitem_with_expansion_type_promotion(self):
541532
# GH#12599
542533
ser = Series(dtype=object)
543534
ser["a"] = Timestamp("2016-01-01")
544-
# After the first insert ser has datetime64 dtype; inserting a float
545-
# is incompatible with that.
546-
with tm.assert_produces_warning(Pandas4Warning):
547-
ser["b"] = 3.0
535+
ser["b"] = 3.0
548536
ser["c"] = "foo"
549537
expected = Series([Timestamp("2016-01-01"), 3.0, "foo"], index=["a", "b", "c"])
550538
tm.assert_series_equal(ser, expected)
@@ -600,6 +588,7 @@ def test_setitem_enlarge_with_na(
600588
def test_setitem_enlargement_object_none(self, nulls_fixture, using_infer_string):
601589
# GH#48665
602590
ser = Series(["a", "b"])
591+
ser[3] = nulls_fixture
603592

604593
dtype = (
605594
"str"
@@ -608,12 +597,6 @@ def test_setitem_enlargement_object_none(self, nulls_fixture, using_infer_string
608597
else object
609598
)
610599

611-
# Warn when the dtype changes (str -> object for Decimal without
612-
# pyarrow); no warning when the dtype is preserved.
613-
warn = Pandas4Warning if ser.dtype != dtype else None
614-
with tm.assert_produces_warning(warn):
615-
ser[3] = nulls_fixture
616-
617600
expected = Series(["a", "b", nulls_fixture], index=[0, 1, 3], dtype=dtype)
618601
tm.assert_series_equal(ser, expected)
619602
if dtype == "str":

0 commit comments

Comments
 (0)