Repository: pandas-dev/pandas

Issue:
API/DEPR: Index.view _typ check, return type
Index.view has a `cls` argument (instead of dtype, which I would expect) and starts with:

```
        # we need to see if we are subclassing an
        # index type here
        if cls is not None and not hasattr(cls, "_typ"):
```

The "_typ" check must have been intended to catch types defined in pd.core.dtypes.generic, but it isn't clear to me why we do that.

Let's just have view take a dtype keyword like Series.view.

<b>update</b>: also it sometimes returns an Index and other times an ArrayLike.  let's choose just one.


Discussion:
Or deprecate it, like we want to do for Series (https://github.com/pandas-dev/pandas/issues/20251), and only keep it on the array level?

Patch:
diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst
index 8a1906d20c243..410dfa3fd5b4a 100644
--- a/doc/source/whatsnew/v2.2.0.rst
+++ b/doc/source/whatsnew/v2.2.0.rst
@@ -438,6 +438,7 @@ Other Deprecations
 - Deprecated :meth:`Series.view`, use :meth:`Series.astype` instead to change the dtype (:issue:`20251`)
 - Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, and ``DatetimeTZBlock``, use public APIs instead (:issue:`55139`)
 - Deprecated ``year``, ``month``, ``quarter``, ``day``, ``hour``, ``minute``, and ``second`` keywords in the :class:`PeriodIndex` constructor, use :meth:`PeriodIndex.from_fields` instead (:issue:`55960`)
+- Deprecated accepting a type as an argument in :meth:`Index.view`, call without any arguments instead (:issue:`55709`)
 - Deprecated allowing non-integer ``periods`` argument in :func:`date_range`, :func:`timedelta_range`, :func:`period_range`, and :func:`interval_range` (:issue:`56036`)
 - 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`)
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
index 3abe77b97fe58..678d7578a65c4 100644
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -1012,6 +1012,16 @@ def view(self, cls=None):
 
             result = self._data.view(cls)
         else:
+            if cls is not None:
+                warnings.warn(
+                    # GH#55709
+                    f"Passing a type in {type(self).__name__}.view is deprecated "
+                    "and will raise in a future version. "
+                    "Call view without any argument to retain the old behavior.",
+                    FutureWarning,
+                    stacklevel=find_stack_level(),
+                )
+
             result = self._view()
         if isinstance(result, Index):
             result._id = self._id


Test patch:
diff --git a/pandas/tests/indexes/datetimes/test_setops.py b/pandas/tests/indexes/datetimes/test_setops.py
index 3ed7fcc027a06..fc3a1d4721841 100644
--- a/pandas/tests/indexes/datetimes/test_setops.py
+++ b/pandas/tests/indexes/datetimes/test_setops.py
@@ -535,7 +535,7 @@ def test_intersection(self):
         assert isinstance(the_int, DatetimeIndex)
         assert the_int.freq == rng.freq
 
-        the_int = rng1.intersection(rng2.view(DatetimeIndex))
+        the_int = rng1.intersection(rng2)
         tm.assert_index_equal(the_int, expected)
 
         # non-overlapping
diff --git a/pandas/tests/indexes/numeric/test_numeric.py b/pandas/tests/indexes/numeric/test_numeric.py
index 944e215ee17bd..7ce55db6c0bbc 100644
--- a/pandas/tests/indexes/numeric/test_numeric.py
+++ b/pandas/tests/indexes/numeric/test_numeric.py
@@ -318,7 +318,9 @@ def test_cant_or_shouldnt_cast(self, dtype):
 
     def test_view_index(self, simple_index):
         index = simple_index
-        index.view(Index)
+        msg = "Passing a type in .*Index.view is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            index.view(Index)
 
     def test_prevent_casting(self, simple_index):
         index = simple_index
diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py
index ffb2dac840198..06e19eeca6766 100644
--- a/pandas/tests/indexes/ranges/test_range.py
+++ b/pandas/tests/indexes/ranges/test_range.py
@@ -199,7 +199,9 @@ def test_view(self):
         i_view = i.view("i8")
         tm.assert_numpy_array_equal(i.values, i_view)
 
-        i_view = i.view(RangeIndex)
+        msg = "Passing a type in RangeIndex.view is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            i_view = i.view(RangeIndex)
         tm.assert_index_equal(i, i_view)
 
     def test_dtype(self, simple_index):
@@ -382,7 +384,9 @@ def test_cant_or_shouldnt_cast(self, start, stop, step):
 
     def test_view_index(self, simple_index):
         index = simple_index
-        index.view(Index)
+        msg = "Passing a type in RangeIndex.view is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            index.view(Index)
 
     def test_prevent_casting(self, simple_index):
         index = simple_index
diff --git a/pandas/tests/indexes/test_datetimelike.py b/pandas/tests/indexes/test_datetimelike.py
index 27e01427006ec..21a686e8bc05b 100644
--- a/pandas/tests/indexes/test_datetimelike.py
+++ b/pandas/tests/indexes/test_datetimelike.py
@@ -89,7 +89,9 @@ def test_view(self, simple_index):
         result = type(simple_index)(idx)
         tm.assert_index_equal(result, idx)
 
-        idx_view = idx.view(type(simple_index))
+        msg = "Passing a type in .*Index.view is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            idx_view = idx.view(type(simple_index))
         result = type(simple_index)(idx)
         tm.assert_index_equal(result, idx_view)
 
diff --git a/pandas/tests/indexes/test_old_base.py b/pandas/tests/indexes/test_old_base.py
index 0fff6abcfc6a5..b467e93b75e96 100644
--- a/pandas/tests/indexes/test_old_base.py
+++ b/pandas/tests/indexes/test_old_base.py
@@ -960,7 +960,9 @@ def test_view(self, simple_index):
         idx_view = idx.view(dtype)
         tm.assert_index_equal(idx, index_cls(idx_view, name="Foo"), exact=True)
 
-        idx_view = idx.view(index_cls)
+        msg = "Passing a type in .*Index.view is deprecated"
+        with tm.assert_produces_warning(FutureWarning, match=msg):
+            idx_view = idx.view(index_cls)
         tm.assert_index_equal(idx, index_cls(idx_view, name="Foo"), exact=True)
 
     def test_format(self, simple_index):