Skip to content

Commit

Permalink
DEPR: Index.insert dtype-inference (#55257)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored Dec 8, 2023
1 parent e3073b5 commit 124b671
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
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

0 comments on commit 124b671

Please sign in to comment.