Skip to content

DEPR: Index.insert dtype-inference #55257

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 9 commits into from
Dec 8, 2023
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ Other Deprecations
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_string` except ``buf``. (:issue:`54229`)
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_xml` except ``path_or_buffer``. (:issue:`54229`)
- Deprecated allowing passing :class:`BlockManager` objects to :class:`DataFrame` or :class:`SingleBlockManager` objects to :class:`Series` (:issue:`52419`)
- Deprecated behavior of :meth:`Index.insert` with an object-dtype index silently performing type inference on the result, explicitly call ``result.infer_objects(copy=False)`` for the old behavior instead (:issue:`51363`)
- Deprecated downcasting behavior in :meth:`Series.where`, :meth:`DataFrame.where`, :meth:`Series.mask`, :meth:`DataFrame.mask`, :meth:`Series.clip`, :meth:`DataFrame.clip`; in a future version these will not infer object-dtype columns to non-object dtype, or all-round floats to integer dtype. Call ``result.infer_objects(copy=False)`` on the result for object inference, or explicitly cast floats to ints. To opt in to the future version, use ``pd.set_option("future.no_silent_downcasting", True)`` (:issue:`53656`)
- Deprecated including the groups in computations when using :meth:`.DataFrameGroupBy.apply` and :meth:`.DataFrameGroupBy.resample`; pass ``include_groups=False`` to exclude the groups (:issue:`7155`)
- Deprecated indexing an :class:`Index` with a boolean indexer of length zero (:issue:`55820`)
Expand Down
18 changes: 14 additions & 4 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6939,14 +6939,24 @@ def insert(self, loc: int, item) -> Index:
loc = loc if loc >= 0 else loc - 1
new_values[loc] = item

idx = Index._with_infer(new_values, name=self.name)
out = Index._with_infer(new_values, name=self.name)
if (
using_pyarrow_string_dtype()
and is_string_dtype(idx.dtype)
and is_string_dtype(out.dtype)
and new_values.dtype == object
):
idx = idx.astype(new_values.dtype)
return idx
out = out.astype(new_values.dtype)
if self.dtype == object and out.dtype != object:
# GH#51363
warnings.warn(
"The behavior of Index.insert with object-dtype is deprecated, "
"in a future version this will return an object-dtype Index "
"instead of inferring a non-object dtype. To retain the old "
"behavior, do `idx.insert(loc, item).infer_objects(copy=False)`",
FutureWarning,
stacklevel=find_stack_level(),
)
return out

def drop(
self,
Expand Down
19 changes: 17 additions & 2 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1893,7 +1893,15 @@ def _setitem_with_indexer(self, indexer, value, name: str = "iloc"):
# just replacing the block manager here
# so the object is the same
index = self.obj._get_axis(i)
labels = index.insert(len(index), key)
with warnings.catch_warnings():
# TODO: re-issue this with setitem-specific message?
warnings.filterwarnings(
"ignore",
"The behavior of Index.insert with object-dtype "
"is deprecated",
category=FutureWarning,
)
labels = index.insert(len(index), key)

# We are expanding the Series/DataFrame values to match
# the length of thenew index `labels`. GH#40096 ensure
Expand Down Expand Up @@ -2186,7 +2194,14 @@ def _setitem_with_indexer_missing(self, indexer, value):
# and set inplace
if self.ndim == 1:
index = self.obj.index
new_index = index.insert(len(index), indexer)
with warnings.catch_warnings():
# TODO: re-issue this with setitem-specific message?
warnings.filterwarnings(
"ignore",
"The behavior of Index.insert with object-dtype is deprecated",
category=FutureWarning,
)
new_index = index.insert(len(index), indexer)

# we have a coerced indexer, e.g. a float
# that matches in an int64 Index, so
Expand Down
10 changes: 8 additions & 2 deletions pandas/core/internals/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1376,8 +1376,14 @@ def insert(self, loc: int, item: Hashable, value: ArrayLike, refs=None) -> None:
value : np.ndarray or ExtensionArray
refs : The reference tracking object of the value to set.
"""
# insert to the axis; this could possibly raise a TypeError
new_axis = self.items.insert(loc, item)
with warnings.catch_warnings():
# TODO: re-issue this with setitem-specific message?
warnings.filterwarnings(
"ignore",
"The behavior of Index.insert with object-dtype is deprecated",
category=FutureWarning,
)
new_axis = self.items.insert(loc, item)

if value.ndim == 2:
value = value.T
Expand Down
11 changes: 9 additions & 2 deletions pandas/tests/indexes/test_old_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,20 @@ def test_where(self, listlike_box, simple_index):
tm.assert_index_equal(result, expected)

def test_insert_base(self, index):
result = index[1:4]
trimmed = index[1:4]

if not len(index):
pytest.skip("Not applicable for empty index")

# test 0th element
assert index[0:4].equals(result.insert(0, index[0]))
warn = None
if index.dtype == object and index.inferred_type == "boolean":
# GH#51363
warn = FutureWarning
msg = "The behavior of Index.insert with object-dtype is deprecated"
with tm.assert_produces_warning(warn, match=msg):
result = trimmed.insert(0, index[0])
assert index[0:4].equals(result)

def test_insert_out_of_bounds(self, index):
# TypeError/IndexError matches what np.insert raises in these cases
Expand Down