Repository: pandas-dev/pandas
Pull request #57851 (2024-03-15 05:41:57)

CLN: Remove unused code

tqa236: Hi Marc, I think it's indeed unrelated and it's also beyond my understanding to debug it as well.

Just FYO, Matthew is debugging it here: https://github.com/pandas-dev/pandas/pull/57845
datapythonista: Thanks. Yes, I meant to have a look to make sure it's unrelated.

Patch:
diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst
index 7263329d2e..aceef7a5d6 100644
--- a/doc/source/whatsnew/v3.0.0.rst
+++ b/doc/source/whatsnew/v3.0.0.rst
@@ -201,6 +201,7 @@ Removal of prior version deprecations/changes
 - Changed the default value of ``observed`` in :meth:`DataFrame.groupby` and :meth:`Series.groupby` to ``True`` (:issue:`51811`)
 - Enforced deprecation disallowing parsing datetimes with mixed time zones unless user passes ``utc=True`` to :func:`to_datetime` (:issue:`57275`)
 - Enforced deprecation of :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` allowing the ``name`` argument to be a non-tuple when grouping by a list of length 1 (:issue:`54155`)
+- Enforced deprecation of :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` for object-dtype (:issue:`57820`)
 - Enforced deprecation of ``axis=None`` acting the same as ``axis=0`` in the DataFrame reductions ``sum``, ``prod``, ``std``, ``var``, and ``sem``, passing ``axis=None`` will now reduce over both axes; this is particularly the case when doing e.g. ``numpy.sum(df)`` (:issue:`21597`)
 - Enforced deprecation of passing a dictionary to :meth:`SeriesGroupBy.agg` (:issue:`52268`)
 - Enforced deprecation of string ``AS`` denoting frequency in :class:`YearBegin` and strings ``AS-DEC``, ``AS-JAN``, etc. denoting annual frequencies with various fiscal year starts (:issue:`57793`)
diff --git a/pandas/core/apply.py b/pandas/core/apply.py
index f2fb503be8..de2fd9394e 100644
--- a/pandas/core/apply.py
+++ b/pandas/core/apply.py
@@ -12,7 +12,6 @@ from typing import (
     Literal,
     cast,
 )
-import warnings
 
 import numpy as np
 
@@ -30,7 +29,6 @@ from pandas._typing import (
 from pandas.compat._optional import import_optional_dependency
 from pandas.errors import SpecificationError
 from pandas.util._decorators import cache_readonly
-from pandas.util._exceptions import find_stack_level
 
 from pandas.core.dtypes.cast import is_nested_object
 from pandas.core.dtypes.common import (
@@ -1992,23 +1990,3 @@ def include_axis(op_name: Literal["agg", "apply"], colg: Series | DataFrame) ->
     return isinstance(colg, ABCDataFrame) or (
         isinstance(colg, ABCSeries) and op_name == "agg"
     )
-
-
-def warn_alias_replacement(
-    obj: AggObjType,
-    func: Callable,
-    alias: str,
-) -> None:
-    if alias.startswith("np."):
-        full_alias = alias
-    else:
-        full_alias = f"{type(obj).__name__}.{alias}"
-        alias = f'"{alias}"'
-    warnings.warn(
-        f"The provided callable {func} is currently using "
-        f"{full_alias}. In a future version of pandas, "
-        f"the provided callable will be used directly. To keep current "
-        f"behavior pass the string {alias} instead.",
-        category=FutureWarning,
-        stacklevel=find_stack_level(),
-    )
diff --git a/pandas/core/arrays/sparse/array.py b/pandas/core/arrays/sparse/array.py
index 8d94662ab4..bf44e5e099 100644
--- a/pandas/core/arrays/sparse/array.py
+++ b/pandas/core/arrays/sparse/array.py
@@ -673,12 +673,6 @@ class SparseArray(OpsMixin, PandasObject, ExtensionArray):
     def _null_fill_value(self) -> bool:
         return self._dtype._is_na_fill_value
 
-    def _fill_value_matches(self, fill_value) -> bool:
-        if self._null_fill_value:
-            return isna(fill_value)
-        else:
-            return self.fill_value == fill_value
-
     @property
     def nbytes(self) -> int:
         return self.sp_values.nbytes + self.sp_index.nbytes
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index e57b33d096..d46fdffdd5 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -7816,17 +7816,11 @@ class NDFrame(PandasObject, indexing.IndexingMixin):
             obj, should_transpose = self, False
         else:
             obj, should_transpose = (self.T, True) if axis == 1 else (self, False)
+            # GH#53631
             if np.any(obj.dtypes == object):
-                # GH#53631
-                if not (obj.ndim == 2 and np.all(obj.dtypes == object)):
-                    # don't warn in cases that already raise
-                    warnings.warn(
-                        f"{type(self).__name__}.interpolate with object dtype is "
-                        "deprecated and will raise in a future version. Call "
-                        "obj.infer_objects(copy=False) before interpolating instead.",
-                        FutureWarning,
-                        stacklevel=find_stack_level(),
-                    )
+                raise TypeError(
+                    f"{type(self).__name__} cannot interpolate with object dtype."
+                )
 
         if method in fillna_methods and "fill_value" in kwargs:
             raise ValueError(
@@ -7842,13 +7836,6 @@ class NDFrame(PandasObject, indexing.IndexingMixin):
 
         limit_direction = missing.infer_limit_direction(limit_direction, method)
 
-        if obj.ndim == 2 and np.all(obj.dtypes == object):
-            raise TypeError(
-                "Cannot interpolate with all object-dtype columns "
-                "in the DataFrame. Try setting at least one "
-                "column to a numeric dtype."
-            )
-
         if method.lower() in fillna_methods:
             # TODO(3.0): remove this case
             # TODO: warn/raise on limit_direction or kwargs which are ignored?
diff --git a/pandas/core/groupby/categorical.py b/pandas/core/groupby/categorical.py
index 037ca81477..49130d91a0 100644
--- a/pandas/core/groupby/categorical.py
+++ b/pandas/core/groupby/categorical.py
@@ -10,9 +10,7 @@ from pandas.core.arrays.categorical import (
 )
 
 
-def recode_for_groupby(
-    c: Categorical, sort: bool, observed: bool
-) -> tuple[Categorical, Categorical | None]:
+def recode_for_groupby(c: Categorical, sort: bool, observed: bool) -> Categorical:
     """
     Code the categories to ensure we can groupby for categoricals.
 
@@ -42,8 +40,6 @@ def recode_for_groupby(
         appearance in codes (unless ordered=True, in which case the
         original order is preserved), followed by any unrepresented
         categories in the original order.
-    Categorical or None
-        If we are observed, return the original categorical, otherwise None
     """
     # we only care about observed values
     if observed:
@@ -63,11 +59,11 @@ def recode_for_groupby(
         # return a new categorical that maps our new codes
         # and categories
         dtype = CategoricalDtype(categories, ordered=c.ordered)
-        return Categorical._simple_new(codes, dtype=dtype), c
+        return Categorical._simple_new(codes, dtype=dtype)
 
     # Already sorted according to c.categories; all is fine
     if sort:
-        return c, None
+        return c
 
     # sort=False should order groups in as-encountered order (GH-8868)
 
@@ -84,4 +80,4 @@ def recode_for_groupby(
     else:
         take_codes = unique_notnan_codes
 
-    return Categorical(c, c.unique().categories.take(take_codes)), None
+    return Categorical(c, c.unique().categories.take(take_codes))
diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py
index 3040f9c64b..239d78b3b8 100644
--- a/pandas/core/groupby/grouper.py
+++ b/pandas/core/groupby/grouper.py
@@ -238,7 +238,6 @@ class Grouper:
 
     sort: bool
     dropna: bool
-    _gpr_index: Index | None
     _grouper: Index | None
 
     _attributes: tuple[str, ...] = ("key", "level", "freq", "sort", "dropna")
@@ -266,8 +265,6 @@ class Grouper:
 
         self._grouper_deprecated = None
         self._indexer_deprecated: npt.NDArray[np.intp] | None = None
-        self._obj_deprecated = None
-        self._gpr_index = None
         self.binner = None
         self._grouper = None
         self._indexer: npt.NDArray[np.intp] | None = None
@@ -380,10 +377,6 @@ class Grouper:
             ax = ax.take(indexer)
             obj = obj.take(indexer, axis=0)
 
-        # error: Incompatible types in assignment (expression has type
-        # "NDFrameT", variable has type "None")
-        self._obj_deprecated = obj  # type: ignore[assignment]
-        self._gpr_index = ax
         return obj, ax, indexer
 
     @final
@@ -433,7 +426,6 @@ class Grouping:
     """
 
     _codes: npt.NDArray[np.signedinteger] | None = None
-    _all_grouper: Categorical | None
     _orig_cats: Index | None
     _index: Index
 
@@ -452,7 +444,6 @@ class Grouping:
         self.level = level
         self._orig_grouper = grouper
         grouping_vector = _convert_grouper(index, grouper)
-        self._all_grouper = None
         self._orig_cats = None
         self._index = index
         self._sort = sort
@@ -536,9 +527,7 @@ class Grouping:
         elif isinstance(getattr(grouping_vector, "dtype", None), CategoricalDtype):
             # a passed Categorical
             self._orig_cats = grouping_vector.categories
-            grouping_vector, self._all_grouper = recode_for_groupby(
-                grouping_vector, sort, observed
-            )
+            grouping_vector = recode_for_groupby(grouping_vector, sort, observed)
 
         self.grouping_vector = grouping_vector
 
diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py
index 46716bb8bf..d920ebc60d 100644
--- a/pandas/core/internals/managers.py
+++ b/pandas/core/internals/managers.py
@@ -267,12 +267,6 @@ class BaseBlockManager(PandasObject):
     # Python3 compat
     __bool__ = __nonzero__
 
-    def _normalize_axis(self, axis: AxisInt) -> int:
-        # switch axis to follow BlockManager logic
-        if self.ndim == 2:
-            axis = 1 if axis == 0 else 0
-        return axis
-
     def set_axis(self, axis: AxisInt, new_labels: Index) -> None:
         # Caller is responsible for ensuring we have an Index object.
         self._validate_set_axis(axis, new_labels)
@@ -446,14 +440,6 @@ class BaseBlockManager(PandasObject):
         out = type(self).from_blocks(result_blocks, self.axes)
         return out
 
-    def apply_with_block(
-        self,
-        f,
-        align_keys: list[str] | None = None,
-        **kwargs,
-    ) -> Self:
-        raise AbstractMethodError(self)
-
     @final
     def isna(self, func) -> Self:
         return self.apply("apply", func=func)


Test patch:
diff --git a/pandas/tests/copy_view/test_interp_fillna.py b/pandas/tests/copy_view/test_interp_fillna.py
index e88896c9ec..8fe58e59b9 100644
--- a/pandas/tests/copy_view/test_interp_fillna.py
+++ b/pandas/tests/copy_view/test_interp_fillna.py
@@ -111,20 +111,12 @@ def test_interp_fill_functions_inplace(func, dtype):
     assert view._mgr._has_no_reference(0)
 
 
-def test_interpolate_cleaned_fill_method():
-    # Check that "method is set to None" case works correctly
+def test_interpolate_cannot_with_object_dtype():
     df = DataFrame({"a": ["a", np.nan, "c"], "b": 1})
-    df_orig = df.copy()
-
-    msg = "DataFrame.interpolate with object dtype"
-    with tm.assert_produces_warning(FutureWarning, match=msg):
-        result = df.interpolate(method="linear")
 
-    assert np.shares_memory(get_array(result, "a"), get_array(df, "a"))
-    result.iloc[0, 0] = Timestamp("2021-12-31")
-
-    assert not np.shares_memory(get_array(result, "a"), get_array(df, "a"))
-    tm.assert_frame_equal(df, df_orig)
+    msg = "DataFrame cannot interpolate with object dtype"
+    with pytest.raises(TypeError, match=msg):
+        df.interpolate()
 
 
 def test_interpolate_object_convert_no_op():
diff --git a/pandas/tests/frame/methods/test_interpolate.py b/pandas/tests/frame/methods/test_interpolate.py
index 73ba3545ea..2ba3bbd310 100644
--- a/pandas/tests/frame/methods/test_interpolate.py
+++ b/pandas/tests/frame/methods/test_interpolate.py
@@ -76,29 +76,14 @@ class TestDataFrameInterpolate:
                 "D": list("abcd"),
             }
         )
-        expected = DataFrame(
-            {
-                "A": [1.0, 2.0, 3.0, 4.0],
-                "B": [1.0, 4.0, 9.0, 9.0],
-                "C": [1, 2, 3, 5],
-                "D": list("abcd"),
-            }
-        )
-        msg = "DataFrame.interpolate with object dtype"
-        with tm.assert_produces_warning(FutureWarning, match=msg):
-            result = df.interpolate()
-        tm.assert_frame_equal(result, expected)
+        msg = "DataFrame cannot interpolate with object dtype"
+        with pytest.raises(TypeError, match=msg):
+            df.interpolate()
 
-        # check we didn't operate inplace GH#45791
         cvalues = df["C"]._values
         dvalues = df["D"].values
-        assert np.shares_memory(cvalues, result["C"]._values)
-        assert np.shares_memory(dvalues, result["D"]._values)
-
-        with tm.assert_produces_warning(FutureWarning, match=msg):
-            res = df.interpolate(inplace=True)
-        assert res is None
-        tm.assert_frame_equal(df, expected)
+        with pytest.raises(TypeError, match=msg):
+            df.interpolate(inplace=True)
 
         # check we DID operate inplace
         assert np.shares_memory(df["C"]._values, cvalues)
@@ -117,14 +102,16 @@ class TestDataFrameInterpolate:
             }
         )
 
-        msg = "DataFrame.interpolate with object dtype"
-        warning = FutureWarning if not using_infer_string else None
-        with tm.assert_produces_warning(warning, match=msg):
+        msg = "DataFrame cannot interpolate with object dtype"
+        if not using_infer_string:
+            with pytest.raises(TypeError, match=msg):
+                df.set_index("C").interpolate()
+        else:
             result = df.set_index("C").interpolate()
-        expected = df.set_index("C")
-        expected.loc[3, "A"] = 3
-        expected.loc[5, "B"] = 9
-        tm.assert_frame_equal(result, expected)
+            expected = df.set_index("C")
+            expected.loc[3, "A"] = 3
+            expected.loc[5, "B"] = 9
+            tm.assert_frame_equal(result, expected)
 
     def test_interp_empty(self):
         # https://github.com/pandas-dev/pandas/issues/35598
@@ -315,22 +302,14 @@ class TestDataFrameInterpolate:
                 "E": [1, 2, 3, 4],
             }
         )
-        msg = (
-            "Cannot interpolate with all object-dtype columns "
-            "in the DataFrame. Try setting at least one "
-            "column to a numeric dtype."
-        )
+        msg = "DataFrame cannot interpolate with object dtype"
         with pytest.raises(TypeError, match=msg):
             df.astype("object").interpolate(axis=axis)
 
     def test_interp_raise_on_all_object_dtype(self):
         # GH 22985
         df = DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}, dtype="object")
-        msg = (
-            "Cannot interpolate with all object-dtype columns "
-            "in the DataFrame. Try setting at least one "
-            "column to a numeric dtype."
-        )
+        msg = "DataFrame cannot interpolate with object dtype"
         with pytest.raises(TypeError, match=msg):
             df.interpolate()
 
diff --git a/pandas/tests/series/methods/test_interpolate.py b/pandas/tests/series/methods/test_interpolate.py
index db101d87a2..e4726f3ec6 100644
--- a/pandas/tests/series/methods/test_interpolate.py
+++ b/pandas/tests/series/methods/test_interpolate.py
@@ -846,10 +846,10 @@ class TestSeriesInterpolateData:
 
     def test_interpolate_asfreq_raises(self):
         ser = Series(["a", None, "b"], dtype=object)
-        msg2 = "Series.interpolate with object dtype"
+        msg2 = "Series cannot interpolate with object dtype"
         msg = "Invalid fill method"
-        with pytest.raises(ValueError, match=msg):
-            with tm.assert_produces_warning(FutureWarning, match=msg2):
+        with pytest.raises(TypeError, match=msg2):
+            with pytest.raises(ValueError, match=msg):
                 ser.interpolate(method="asfreq")
 
     def test_interpolate_fill_value(self):