Repository: pandas-dev/pandas

Issue:
DEPR: Index.format?
Does anyone actually use this?  Internally we use it for some html/latex rendering but we don't use most of the keywords so it would be simpler to refactor to use a private method for those.

I've been trying to unravel the various EA formatting methods to try to use the same patterns everywhere, align keywords, etc.  Doing this for Index.format wouldn't be _that_ hard, but it would be easier to just deprecate it if it isn't used externally.



Discussion:
It's used externally.

Github code search shows at least catboost uses it

https://github.com/catboost/catboost/blob/922ad64b4f09a13be5e0310709833e1f63fa7140/contrib/python/pandas/py3/pandas/io/formats/format.py#L365-L374

There are a couple others too, see
https://github.com/search?q=index.format+language%3APython&type=code&l=Python
The catboost example looks like they just vendored all of pandas.  The others are look like largely matches on the word "format" which isn't using our Index.format.

Patch:
diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst
index 09067d541d01b..3bd817b6cb1f0 100644
--- a/doc/source/whatsnew/v2.2.0.rst
+++ b/doc/source/whatsnew/v2.2.0.rst
@@ -233,6 +233,7 @@ For example:
 Other Deprecations
 ^^^^^^^^^^^^^^^^^^
 - Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`)
+- Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`)
 - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_clipboard`. (:issue:`54229`)
 - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_csv` except ``path_or_buf``. (:issue:`54229`)
 - Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_dict`. (:issue:`54229`)
@@ -260,6 +261,7 @@ Other Deprecations
 - Deprecated the extension test classes ``BaseNoReduceTests``, ``BaseBooleanReduceTests``, and ``BaseNumericReduceTests``, use ``BaseReduceTests`` instead (:issue:`54663`)
 - Deprecated the option ``mode.data_manager`` and the ``ArrayManager``; only the ``BlockManager`` will be available in future versions (:issue:`55043`)
 - Deprecating downcasting the results of :meth:`DataFrame.fillna`, :meth:`Series.fillna`, :meth:`DataFrame.ffill`, :meth:`Series.ffill`, :meth:`DataFrame.bfill`, :meth:`Series.bfill` in object-dtype cases. To opt in to the future version, use ``pd.set_option("future.no_silent_downcasting", True)`` (:issue:`54261`)
+-
 
 .. ---------------------------------------------------------------------------
 .. _whatsnew_220.performance:
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
index c3cab965041e0..e8ea4729e8232 100644
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -1370,6 +1370,14 @@ def format(
         """
         Render a string representation of the Index.
         """
+        warnings.warn(
+            # GH#55413
+            f"{type(self).__name__}.format is deprecated and will be removed "
+            "in a future version. Convert using index.astype(str) or "
+            "index.map(formatter) instead.",
+            FutureWarning,
+            stacklevel=find_stack_level(),
+        )
         header = []
         if name:
             header.append(
@@ -1383,6 +1391,31 @@ def format(
 
         return self._format_with_header(header=header, na_rep=na_rep)
 
+    _default_na_rep = "NaN"
+
+    @final
+    def _format_flat(
+        self,
+        *,
+        include_name: bool,
+        formatter: Callable | None = None,
+    ) -> list[str_t]:
+        """
+        Render a string representation of the Index.
+        """
+        header = []
+        if include_name:
+            header.append(
+                pprint_thing(self.name, escape_chars=("\t", "\r", "\n"))
+                if self.name is not None
+                else ""
+            )
+
+        if formatter is not None:
+            return header + list(self.map(formatter))
+
+        return self._format_with_header(header=header, na_rep=self._default_na_rep)
+
     def _format_with_header(self, *, header: list[str_t], na_rep: str_t) -> list[str_t]:
         from pandas.io.formats.format import format_array
 
diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py
index 94ad556219b35..42af9556e04e1 100644
--- a/pandas/core/indexes/datetimelike.py
+++ b/pandas/core/indexes/datetimelike.py
@@ -14,6 +14,7 @@
     cast,
     final,
 )
+import warnings
 
 import numpy as np
 
@@ -42,6 +43,7 @@
     cache_readonly,
     doc,
 )
+from pandas.util._exceptions import find_stack_level
 
 from pandas.core.dtypes.common import (
     is_integer,
@@ -187,6 +189,7 @@ def _convert_tolerance(self, tolerance, target):
 
     # --------------------------------------------------------------------
     # Rendering Methods
+    _default_na_rep = "NaT"
 
     def format(
         self,
@@ -198,6 +201,14 @@ def format(
         """
         Render a string representation of the Index.
         """
+        warnings.warn(
+            # GH#55413
+            f"{type(self).__name__}.format is deprecated and will be removed "
+            "in a future version. Convert using index.astype(str) or "
+            "index.map(formatter) instead.",
+            FutureWarning,
+            stacklevel=find_stack_level(),
+        )
         header = []
         if name:
             header.append(
diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py
index c5cab225fa7b1..3ef3cb6d56ed1 100644
--- a/pandas/core/indexes/multi.py
+++ b/pandas/core/indexes/multi.py
@@ -1383,6 +1383,15 @@ def format(
         sparsify=None,
         adjoin: bool = True,
     ) -> list:
+        warnings.warn(
+            # GH#55413
+            f"{type(self).__name__}.format is deprecated and will be removed "
+            "in a future version. Convert using index.astype(str) or "
+            "index.map(formatter) instead.",
+            FutureWarning,
+            stacklevel=find_stack_level(),
+        )
+
         if name is not None:
             names = name
 
@@ -1445,6 +1454,69 @@ def format(
         else:
             return result_levels
 
+    def _format_multi(
+        self,
+        *,
+        include_names: bool,
+        sparsify: bool | None | lib.NoDefault,
+        formatter: Callable | None = None,
+    ) -> list:
+        if len(self) == 0:
+            return []
+
+        stringified_levels = []
+        for lev, level_codes in zip(self.levels, self.codes):
+            na = _get_na_rep(lev.dtype)
+
+            if len(lev) > 0:
+                taken = formatted = lev.take(level_codes)
+                formatted = taken._format_flat(include_name=False, formatter=formatter)
+
+                # we have some NA
+                mask = level_codes == -1
+                if mask.any():
+                    formatted = np.array(formatted, dtype=object)
+                    formatted[mask] = na
+                    formatted = formatted.tolist()
+
+            else:
+                # weird all NA case
+                formatted = [
+                    pprint_thing(na if isna(x) else x, escape_chars=("\t", "\r", "\n"))
+                    for x in algos.take_nd(lev._values, level_codes)
+                ]
+            stringified_levels.append(formatted)
+
+        result_levels = []
+        for lev, lev_name in zip(stringified_levels, self.names):
+            level = []
+
+            if include_names:
+                level.append(
+                    pprint_thing(lev_name, escape_chars=("\t", "\r", "\n"))
+                    if lev_name is not None
+                    else ""
+                )
+
+            level.extend(np.array(lev, dtype=object))
+            result_levels.append(level)
+
+        if sparsify is None:
+            sparsify = get_option("display.multi_sparse")
+
+        if sparsify:
+            sentinel: Literal[""] | bool | lib.NoDefault = ""
+            # GH3547 use value of sparsify as sentinel if it's "Falsey"
+            assert isinstance(sparsify, bool) or sparsify is lib.no_default
+            if sparsify is lib.no_default:
+                sentinel = sparsify
+            # little bit of a kludge job for #1217
+            result_levels = sparsify_labels(
+                result_levels, start=int(include_names), sentinel=sentinel
+            )
+
+        return result_levels
+
     # --------------------------------------------------------------------
     # Names Methods
 
diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py
index b344d9849f16c..684cd4340cd2b 100644
--- a/pandas/io/formats/excel.py
+++ b/pandas/io/formats/excel.py
@@ -623,8 +623,8 @@ def _format_header_mi(self) -> Iterable[ExcelCell]:
             return
 
         columns = self.columns
-        level_strs = columns.format(
-            sparsify=self.merge_cells, adjoin=False, names=False
+        level_strs = columns._format_multi(
+            sparsify=self.merge_cells, include_names=False
         )
         level_lengths = get_level_lengths(level_strs)
         coloffset = 0
@@ -813,8 +813,8 @@ def _format_hierarchical_rows(self) -> Iterable[ExcelCell]:
 
             if self.merge_cells:
                 # Format hierarchical rows as merged cells.
-                level_strs = self.df.index.format(
-                    sparsify=True, adjoin=False, names=False
+                level_strs = self.df.index._format_multi(
+                    sparsify=True, include_names=False
                 )
                 level_lengths = get_level_lengths(level_strs)
 
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
index cac83e2a48972..9d75f4cf3ab49 100644
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -312,8 +312,14 @@ def to_string(self) -> str:
         if len(series) == 0:
             return f"{type(self.series).__name__}([], {footer})"
 
-        have_header = _has_names(series.index)
-        fmt_index = self.tr_series.index.format(name=True)
+        index = series.index
+        have_header = _has_names(index)
+        if isinstance(index, MultiIndex):
+            fmt_index = index._format_multi(include_names=True, sparsify=None)
+            adj = printing.get_adjustment()
+            fmt_index = adj.adjoin(2, *fmt_index).split("\n")
+        else:
+            fmt_index = index._format_flat(include_name=True)
         fmt_values = self._get_formatted_values()
 
         if self.is_truncated_vertically:
@@ -776,7 +782,7 @@ def _get_formatted_column_labels(self, frame: DataFrame) -> list[list[str]]:
         columns = frame.columns
 
         if isinstance(columns, MultiIndex):
-            fmt_columns = columns.format(sparsify=False, adjoin=False)
+            fmt_columns = columns._format_multi(sparsify=False, include_names=False)
             fmt_columns = list(zip(*fmt_columns))
             dtypes = self.frame.dtypes._values
 
@@ -801,7 +807,7 @@ def space_format(x, y):
 
             str_columns = [list(x) for x in zip(*str_columns)]
         else:
-            fmt_columns = columns.format()
+            fmt_columns = columns._format_flat(include_name=False)
             dtypes = self.frame.dtypes
             need_leadsp = dict(zip(fmt_columns, map(is_numeric_dtype, dtypes)))
             str_columns = [
@@ -820,14 +826,15 @@ def _get_formatted_index(self, frame: DataFrame) -> list[str]:
         fmt = self._get_formatter("__index__")
 
         if isinstance(index, MultiIndex):
-            fmt_index = index.format(
+            fmt_index = index._format_multi(
                 sparsify=self.sparsify,
-                adjoin=False,
-                names=self.show_row_idx_names,
+                include_names=self.show_row_idx_names,
                 formatter=fmt,
             )
         else:
-            fmt_index = [index.format(name=self.show_row_idx_names, formatter=fmt)]
+            fmt_index = [
+                index._format_flat(include_name=self.show_row_idx_names, formatter=fmt)
+            ]
 
         fmt_index = [
             tuple(
diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py
index b1a3504d46b27..794ce77b3b45e 100644
--- a/pandas/io/formats/html.py
+++ b/pandas/io/formats/html.py
@@ -282,7 +282,7 @@ def _write_col_header(self, indent: int) -> None:
                 sentinel = lib.no_default
             else:
                 sentinel = False
-            levels = self.columns.format(sparsify=sentinel, adjoin=False, names=False)
+            levels = self.columns._format_multi(sparsify=sentinel, include_names=False)
             level_lengths = get_level_lengths(levels, sentinel)
             inner_lvl = len(level_lengths) - 1
             for lnum, (records, values) in enumerate(zip(level_lengths, levels)):
@@ -437,7 +437,8 @@ def _write_regular_rows(
             if fmt is not None:
                 index_values = self.fmt.tr_frame.index.map(fmt)
             else:
-                index_values = self.fmt.tr_frame.index.format()
+                # only reached with non-Multi index
+                index_values = self.fmt.tr_frame.index._format_flat(include_name=False)
 
         row: list[str] = []
         for i in range(nrows):
@@ -480,13 +481,13 @@ def _write_hierarchical_rows(
         nrows = len(frame)
 
         assert isinstance(frame.index, MultiIndex)
-        idx_values = frame.index.format(sparsify=False, adjoin=False, names=False)
+        idx_values = frame.index._format_multi(sparsify=False, include_names=False)
         idx_values = list(zip(*idx_values))
 
         if self.fmt.sparsify:
             # GH3547
             sentinel = lib.no_default
-            levels = frame.index.format(sparsify=sentinel, adjoin=False, names=False)
+            levels = frame.index._format_multi(sparsify=sentinel, include_names=False)
 
             level_lengths = get_level_lengths(levels, sentinel)
             inner_lvl = len(level_lengths) - 1
@@ -579,7 +580,7 @@ def _write_hierarchical_rows(
                     )
 
                 idx_values = list(
-                    zip(*frame.index.format(sparsify=False, adjoin=False, names=False))
+                    zip(*frame.index._format_multi(sparsify=False, include_names=False))
                 )
                 row = []
                 row.extend(idx_values[i])
@@ -606,7 +607,8 @@ def _get_formatted_values(self) -> dict[int, list[str]]:
         return {i: self.fmt.format_col(i) for i in range(self.ncols)}
 
     def _get_columns_formatted_values(self) -> list[str]:
-        return self.columns.format()
+        # only reached with non-Multi Index
+        return self.columns._format_flat(include_name=False)
 
     def write_style(self) -> None:
         # We use the "scoped" attribute here so that the desired
diff --git a/pandas/io/formats/style_render.py b/pandas/io/formats/style_render.py
index 829ed4a33f6a4..416b263ba8497 100644
--- a/pandas/io/formats/style_render.py
+++ b/pandas/io/formats/style_render.py
@@ -1652,9 +1652,9 @@ def _get_level_lengths(
         Result is a dictionary of (level, initial_position): span
     """
     if isinstance(index, MultiIndex):
-        levels = index.format(sparsify=lib.no_default, adjoin=False)
+        levels = index._format_multi(sparsify=lib.no_default, include_names=False)
     else:
-        levels = index.format()
+        levels = index._format_flat(include_name=False)
 
     if hidden_elements is None:
         hidden_elements = []


Test patch:
diff --git a/pandas/tests/indexes/base_class/test_formats.py b/pandas/tests/indexes/base_class/test_formats.py
index 9053d45dee623..20f94010f56f8 100644
--- a/pandas/tests/indexes/base_class/test_formats.py
+++ b/pandas/tests/indexes/base_class/test_formats.py
@@ -4,6 +4,7 @@
 import pandas._config.config as cf
 
 from pandas import Index
+import pandas._testing as tm
 
 
 class TestIndexRendering:
@@ -133,7 +134,9 @@ def test_summary_bug(self):
     def test_index_repr_bool_nan(self):
         # GH32146
         arr = Index([True, False, np.nan], dtype=object)
-        exp1 = arr.format()
+        msg = "Index.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            exp1 = arr.format()
         out1 = ["True", "False", "NaN"]
         assert out1 == exp1
 
@@ -145,4 +148,6 @@ def test_format_different_scalar_lengths(self):
         # GH#35439
         idx = Index(["aaaaaaaaa", "b"])
         expected = ["aaaaaaaaa", "b"]
-        assert idx.format() == expected
+        msg = r"Index\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert idx.format() == expected
diff --git a/pandas/tests/indexes/categorical/test_formats.py b/pandas/tests/indexes/categorical/test_formats.py
index 7dbcaaa8d4ba6..ea3e4ce213e67 100644
--- a/pandas/tests/indexes/categorical/test_formats.py
+++ b/pandas/tests/indexes/categorical/test_formats.py
@@ -4,6 +4,7 @@
 import pandas._config.config as cf
 
 from pandas import CategoricalIndex
+import pandas._testing as tm
 
 
 class TestCategoricalIndexRepr:
@@ -11,7 +12,9 @@ def test_format_different_scalar_lengths(self):
         # GH#35439
         idx = CategoricalIndex(["aaaaaaaaa", "b"])
         expected = ["aaaaaaaaa", "b"]
-        assert idx.format() == expected
+        msg = r"CategoricalIndex\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert idx.format() == expected
 
     def test_string_categorical_index_repr(self):
         # short
diff --git a/pandas/tests/indexes/datetimes/test_datetimelike.py b/pandas/tests/indexes/datetimes/test_datetimelike.py
index a6bee20d3d3ec..a012a2985b41c 100644
--- a/pandas/tests/indexes/datetimes/test_datetimelike.py
+++ b/pandas/tests/indexes/datetimes/test_datetimelike.py
@@ -1,5 +1,6 @@
 """ generic tests from the Datetimelike class """
 from pandas import date_range
+import pandas._testing as tm
 
 
 class TestDatetimeIndex:
@@ -7,4 +8,6 @@ def test_format(self):
         # GH35439
         idx = date_range("20130101", periods=5)
         expected = [f"{x:%Y-%m-%d}" for x in idx]
-        assert idx.format() == expected
+        msg = r"DatetimeIndex\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert idx.format() == expected
diff --git a/pandas/tests/indexes/datetimes/test_formats.py b/pandas/tests/indexes/datetimes/test_formats.py
index 9fb5db9e034ee..6bd978b66c941 100644
--- a/pandas/tests/indexes/datetimes/test_formats.py
+++ b/pandas/tests/indexes/datetimes/test_formats.py
@@ -285,13 +285,17 @@ def test_format_with_name_time_info(self):
         # bug I fixed 12/20/2011
         dates = pd.date_range("2011-01-01 04:00:00", periods=10, name="something")
 
-        formatted = dates.format(name=True)
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = dates.format(name=True)
         assert formatted[0] == "something"
 
     def test_format_datetime_with_time(self):
         dti = DatetimeIndex([datetime(2012, 2, 7), datetime(2012, 2, 7, 23)])
 
-        result = dti.format()
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            result = dti.format()
         expected = ["2012-02-07 00:00:00", "2012-02-07 23:00:00"]
         assert len(result) == 2
         assert result == expected
diff --git a/pandas/tests/indexes/multi/test_formats.py b/pandas/tests/indexes/multi/test_formats.py
index 011f61fac90e8..bbe94824eefa1 100644
--- a/pandas/tests/indexes/multi/test_formats.py
+++ b/pandas/tests/indexes/multi/test_formats.py
@@ -6,24 +6,31 @@
     Index,
     MultiIndex,
 )
+import pandas._testing as tm
 
 
 def test_format(idx):
-    idx.format()
-    idx[:0].format()
+    msg = "MultiIndex.format is deprecated"
+    with tm.assert_produces_warning(FutureWarning, match=msg):
+        idx.format()
+        idx[:0].format()
 
 
 def test_format_integer_names():
     index = MultiIndex(
         levels=[[0, 1], [0, 1]], codes=[[0, 0, 1, 1], [0, 1, 0, 1]], names=[0, 1]
     )
-    index.format(names=True)
+    msg = "MultiIndex.format is deprecated"
+    with tm.assert_produces_warning(FutureWarning, match=msg):
+        index.format(names=True)
 
 
 def test_format_sparse_config(idx):
     # GH1538
+    msg = "MultiIndex.format is deprecated"
     with pd.option_context("display.multi_sparse", False):
-        result = idx.format()
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            result = idx.format()
     assert result[1] == "foo  two"
 
 
@@ -37,8 +44,9 @@ def test_format_sparse_display():
             [0, 0, 0, 0, 0, 0],
         ],
     )
-
-    result = index.format()
+    msg = "MultiIndex.format is deprecated"
+    with tm.assert_produces_warning(FutureWarning, match=msg):
+        result = index.format()
     assert result[3] == "1  0  0  0"
 
 
diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py
index 22bb63d67f57f..1bb8d66332cd0 100644
--- a/pandas/tests/indexes/period/test_period.py
+++ b/pandas/tests/indexes/period/test_period.py
@@ -275,8 +275,11 @@ def test_map(self):
     def test_format_empty(self):
         # GH35712
         empty_idx = PeriodIndex([], freq="Y")
-        assert empty_idx.format() == []
-        assert empty_idx.format(name=True) == [""]
+        msg = r"PeriodIndex\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format() == []
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format(name=True) == [""]
 
     def test_period_index_frequency_ME_error_message(self):
         msg = "Invalid frequency: 2ME"
diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py
index 132704434829e..95756b04bca69 100644
--- a/pandas/tests/indexes/ranges/test_range.py
+++ b/pandas/tests/indexes/ranges/test_range.py
@@ -240,7 +240,9 @@ def test_cache(self):
             pass
         assert idx._cache == {}
 
-        idx.format()
+        msg = "RangeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            idx.format()
         assert idx._cache == {}
 
         df = pd.DataFrame({"a": range(10)}, index=idx)
@@ -566,8 +568,11 @@ def test_engineless_lookup(self):
     def test_format_empty(self):
         # GH35712
         empty_idx = RangeIndex(0)
-        assert empty_idx.format() == []
-        assert empty_idx.format(name=True) == [""]
+        msg = r"RangeIndex\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format() == []
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format(name=True) == [""]
 
     @pytest.mark.parametrize(
         "ri",
diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py
index 6afab569797f2..04ab2020b4c7a 100644
--- a/pandas/tests/indexes/test_base.py
+++ b/pandas/tests/indexes/test_base.py
@@ -666,13 +666,17 @@ def test_format_bug(self):
         # include us since the default for Timestamp shows these but Index
         # formatting does not we are skipping)
         now = datetime.now()
+        msg = r"Index\.format is deprecated"
+
         if not str(now).endswith("000"):
             index = Index([now])
-            formatted = index.format()
+            with tm.assert_produces_warning(FutureWarning, match=msg):
+                formatted = index.format()
             expected = [str(index[0])]
             assert formatted == expected
 
-        Index([]).format()
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            Index([]).format()
 
     @pytest.mark.parametrize("vals", [[1, 2.0 + 3.0j, 4.0], ["a", "b", "c"]])
     def test_format_missing(self, vals, nulls_fixture):
@@ -682,7 +686,9 @@ def test_format_missing(self, vals, nulls_fixture):
         index = Index(vals, dtype=object)
         # TODO: case with complex dtype?
 
-        formatted = index.format()
+        msg = r"Index\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = index.format()
         null_repr = "NaN" if isinstance(nulls_fixture, float) else str(nulls_fixture)
         expected = [str(index[0]), str(index[1]), str(index[2]), null_repr]
 
diff --git a/pandas/tests/indexes/test_old_base.py b/pandas/tests/indexes/test_old_base.py
index 79dc423f12a85..32adbc693390b 100644
--- a/pandas/tests/indexes/test_old_base.py
+++ b/pandas/tests/indexes/test_old_base.py
@@ -559,15 +559,20 @@ def test_format(self, simple_index):
             pytest.skip("Tested elsewhere.")
         idx = simple_index
         expected = [str(x) for x in idx]
-        assert idx.format() == expected
+        msg = r"Index\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert idx.format() == expected
 
     def test_format_empty(self, simple_index):
         # GH35712
         if isinstance(simple_index, (PeriodIndex, RangeIndex)):
             pytest.skip("Tested elsewhere")
         empty_idx = type(simple_index)([])
-        assert empty_idx.format() == []
-        assert empty_idx.format(name=True) == [""]
+        msg = r"Index\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format() == []
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert empty_idx.format(name=True) == [""]
 
     def test_fillna(self, index):
         # GH 11343
@@ -955,7 +960,9 @@ def test_format(self, simple_index):
         idx = simple_index
         max_width = max(len(str(x)) for x in idx)
         expected = [str(x).ljust(max_width) for x in idx]
-        assert idx.format() == expected
+        msg = r"Index\.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert idx.format() == expected
 
     def test_insert_non_na(self, simple_index):
         # GH#43921 inserting an element that we know we can hold should
diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py
index e4ce969daab53..18af18ade85f4 100644
--- a/pandas/tests/io/excel/test_writers.py
+++ b/pandas/tests/io/excel/test_writers.py
@@ -809,7 +809,7 @@ def test_to_excel_multiindex_cols(self, merge_cells, frame, path):
                 reader, sheet_name="test1", header=header, index_col=[0, 1]
             )
         if not merge_cells:
-            fm = frame.columns.format(sparsify=False, adjoin=False, names=False)
+            fm = frame.columns._format_multi(sparsify=False, include_names=False)
             frame.columns = [".".join(map(str, q)) for q in zip(*fm)]
         tm.assert_frame_equal(frame, df)
 
diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py
index 57f1f082708ae..d18c333d79244 100644
--- a/pandas/tests/io/formats/test_format.py
+++ b/pandas/tests/io/formats/test_format.py
@@ -3333,7 +3333,9 @@ def test_period_format_and_strftime_default(self):
         per = pd.PeriodIndex([datetime(2003, 1, 1, 12), None], freq="h")
 
         # Default formatting
-        formatted = per.format()
+        msg = "PeriodIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = per.format()
         assert formatted[0] == "2003-01-01 12:00"  # default: minutes not shown
         assert formatted[1] == "NaT"
         # format is equivalent to strftime(None)...
@@ -3342,35 +3344,40 @@ def test_period_format_and_strftime_default(self):
 
         # Same test with nanoseconds freq
         per = pd.period_range("2003-01-01 12:01:01.123456789", periods=2, freq="ns")
-        formatted = per.format()
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = per.format()
         assert (formatted == per.strftime(None)).all()
         assert formatted[0] == "2003-01-01 12:01:01.123456789"
         assert formatted[1] == "2003-01-01 12:01:01.123456790"
 
     def test_period_custom(self):
         # GH#46252 custom formatting directives %l (ms) and %u (us)
+        msg = "PeriodIndex.format is deprecated"
 
         # 3 digits
         per = pd.period_range("2003-01-01 12:01:01.123", periods=2, freq="ms")
-        formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
         assert formatted[0] == "03 12:01:01 (ms=123 us=123000 ns=123000000)"
         assert formatted[1] == "03 12:01:01 (ms=124 us=124000 ns=124000000)"
 
         # 6 digits
         per = pd.period_range("2003-01-01 12:01:01.123456", periods=2, freq="us")
-        formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
         assert formatted[0] == "03 12:01:01 (ms=123 us=123456 ns=123456000)"
         assert formatted[1] == "03 12:01:01 (ms=123 us=123457 ns=123457000)"
 
         # 9 digits
         per = pd.period_range("2003-01-01 12:01:01.123456789", periods=2, freq="ns")
-        formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = per.format(date_format="%y %I:%M:%S (ms=%l us=%u ns=%n)")
         assert formatted[0] == "03 12:01:01 (ms=123 us=123456 ns=123456789)"
         assert formatted[1] == "03 12:01:01 (ms=123 us=123456 ns=123456790)"
 
     def test_period_tz(self):
         # Formatting periods created from a datetime with timezone.
-
+        msg = r"PeriodIndex\.format is deprecated"
         # This timestamp is in 2013 in Europe/Paris but is 2012 in UTC
         dt = pd.to_datetime(["2013-01-01 00:00:00+01:00"], utc=True)
 
@@ -3378,13 +3385,15 @@ def test_period_tz(self):
         # Since tz is currently set as utc, we'll see 2012
         with tm.assert_produces_warning(UserWarning, match="will drop timezone"):
             per = dt.to_period(freq="h")
-        assert per.format()[0] == "2012-12-31 23:00"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert per.format()[0] == "2012-12-31 23:00"
 
         # If tz is currently set as paris before conversion, we'll see 2013
         dt = dt.tz_convert("Europe/Paris")
         with tm.assert_produces_warning(UserWarning, match="will drop timezone"):
             per = dt.to_period(freq="h")
-        assert per.format()[0] == "2013-01-01 00:00"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            assert per.format()[0] == "2013-01-01 00:00"
 
     @pytest.mark.parametrize(
         "locale_str",
@@ -3411,7 +3420,9 @@ def test_period_non_ascii_fmt(self, locale_str):
 
             # Index
             per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h")
-            formatted = per.format(date_format="%y é")
+            msg = "PeriodIndex.format is deprecated"
+            with tm.assert_produces_warning(FutureWarning, match=msg):
+                formatted = per.format(date_format="%y é")
             assert formatted[0] == "03 é"
             assert formatted[1] == "03 é"
 
@@ -3443,33 +3454,45 @@ def test_period_custom_locale_directive(self, locale_str):
 
             # Index
             per = pd.period_range("2003-01-01 01:00:00", periods=2, freq="12h")
-            formatted = per.format(date_format="%y %I:%M:%S%p")
+            msg = "PeriodIndex.format is deprecated"
+            with tm.assert_produces_warning(FutureWarning, match=msg):
+                formatted = per.format(date_format="%y %I:%M:%S%p")
             assert formatted[0] == f"03 01:00:00{am_local}"
             assert formatted[1] == f"03 01:00:00{pm_local}"
 
 
 class TestDatetimeIndexFormat:
     def test_datetime(self):
-        formatted = pd.to_datetime([datetime(2003, 1, 1, 12), NaT]).format()
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = pd.to_datetime([datetime(2003, 1, 1, 12), NaT]).format()
         assert formatted[0] == "2003-01-01 12:00:00"
         assert formatted[1] == "NaT"
 
     def test_date(self):
-        formatted = pd.to_datetime([datetime(2003, 1, 1), NaT]).format()
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = pd.to_datetime([datetime(2003, 1, 1), NaT]).format()
         assert formatted[0] == "2003-01-01"
         assert formatted[1] == "NaT"
 
     def test_date_tz(self):
-        formatted = pd.to_datetime([datetime(2013, 1, 1)], utc=True).format()
+        dti = pd.to_datetime([datetime(2013, 1, 1)], utc=True)
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = dti.format()
         assert formatted[0] == "2013-01-01 00:00:00+00:00"
 
-        formatted = pd.to_datetime([datetime(2013, 1, 1), NaT], utc=True).format()
+        dti = pd.to_datetime([datetime(2013, 1, 1), NaT], utc=True)
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = dti.format()
         assert formatted[0] == "2013-01-01 00:00:00+00:00"
 
     def test_date_explicit_date_format(self):
-        formatted = pd.to_datetime([datetime(2003, 2, 1), NaT]).format(
-            date_format="%m-%d-%Y", na_rep="UT"
-        )
+        dti = pd.to_datetime([datetime(2003, 2, 1), NaT])
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            formatted = dti.format(date_format="%m-%d-%Y", na_rep="UT")
         assert formatted[0] == "02-01-2003"
         assert formatted[1] == "UT"
 
diff --git a/pandas/tests/series/test_repr.py b/pandas/tests/series/test_repr.py
index 86474a38d29fb..86addb9dadfad 100644
--- a/pandas/tests/series/test_repr.py
+++ b/pandas/tests/series/test_repr.py
@@ -258,7 +258,9 @@ def test_index_repr_in_frame_with_nan(self):
 
     def test_format_pre_1900_dates(self):
         rng = date_range("1/1/1850", "1/1/1950", freq="Y-DEC")
-        rng.format()
+        msg = "DatetimeIndex.format is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            rng.format()
         ts = Series(1, index=rng)
         repr(ts)