diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 563ae6d1d2ed1..2bb933f6bdb60 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -789,6 +789,7 @@ Deprecations - :meth:`Categorical.to_dense` is deprecated and will be removed in a future version, use ``np.asarray(cat)`` instead (:issue:`32639`) - The ``fastpath`` keyword in the ``SingleBlockManager`` constructor is deprecated and will be removed in a future version (:issue:`33092`) - Providing ``suffixes`` as a ``set`` in :func:`pandas.merge` is deprecated. Provide a tuple instead (:issue:`33740`, :issue:`34741`). +- Indexing a series with a multi-dimensional indexer like ``[:, None]`` to return an ndarray now raises a ``FutureWarning``. Convert to a NumPy array before indexing instead (:issue:`27837`) - :meth:`Index.is_mixed` is deprecated and will be removed in a future version, check ``index.inferred_type`` directly instead (:issue:`32922`) - Passing any arguments but the first one to :func:`read_html` as diff --git a/pandas/core/indexers.py b/pandas/core/indexers.py index 6dbcfef46fa98..d9aa02db3e42a 100644 --- a/pandas/core/indexers.py +++ b/pandas/core/indexers.py @@ -295,7 +295,7 @@ def length_of_indexer(indexer, target=None) -> int: raise AssertionError("cannot find the length of the indexer") -def deprecate_ndim_indexing(result): +def deprecate_ndim_indexing(result, stacklevel=3): """ Helper function to raise the deprecation warning for multi-dimensional indexing on 1D Series/Index. @@ -306,11 +306,11 @@ def deprecate_ndim_indexing(result): """ if np.ndim(result) > 1: warnings.warn( - "Support for multi-dimensional indexing (e.g. `index[:, None]`) " - "on an Index is deprecated and will be removed in a future " + "Support for multi-dimensional indexing (e.g. `obj[:, None]`) " + "is deprecated and will be removed in a future " "version. Convert to a numpy array before indexing instead.", - DeprecationWarning, - stacklevel=3, + FutureWarning, + stacklevel=stacklevel, ) diff --git a/pandas/core/series.py b/pandas/core/series.py index be4099d56d43a..6c1d21e4526cf 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -78,7 +78,7 @@ sanitize_array, ) from pandas.core.generic import NDFrame -from pandas.core.indexers import unpack_1tuple +from pandas.core.indexers import deprecate_ndim_indexing, unpack_1tuple from pandas.core.indexes.accessors import CombinedDatetimelikeProperties from pandas.core.indexes.api import Float64Index, Index, MultiIndex, ensure_index import pandas.core.indexes.base as ibase @@ -950,13 +950,9 @@ def _get_with(self, key): def _get_values_tuple(self, key): # mpl hackaround if com.any_none(*key): - # suppress warning from slicing the index with a 2d indexer. - # eventually we'll want Series itself to warn. - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", "Support for multi-dim", DeprecationWarning - ) - return self._get_values(key) + result = self._get_values(key) + deprecate_ndim_indexing(result, stacklevel=5) + return result if not isinstance(self.index, MultiIndex): raise ValueError("Can only tuple-index with a MultiIndex") diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 30c58506f619d..c8b780455f862 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -855,7 +855,7 @@ def test_engine_reference_cycle(self): def test_getitem_2d_deprecated(self): # GH#30588 idx = self.create_index() - with tm.assert_produces_warning(DeprecationWarning, check_stacklevel=False): + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): res = idx[:, None] assert isinstance(res, np.ndarray), type(res) diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index b1faaa2115f55..6d6193ceaf27d 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -95,7 +95,7 @@ def test_dti_business_getitem(self): def test_dti_business_getitem_matplotlib_hackaround(self): rng = pd.bdate_range(START, END) - with tm.assert_produces_warning(DeprecationWarning): + with tm.assert_produces_warning(FutureWarning): # GH#30588 multi-dimensional indexing deprecated values = rng[:, None] expected = rng.values[:, None] @@ -122,7 +122,7 @@ def test_dti_custom_getitem(self): def test_dti_custom_getitem_matplotlib_hackaround(self): rng = pd.bdate_range(START, END, freq="C") - with tm.assert_produces_warning(DeprecationWarning): + with tm.assert_produces_warning(FutureWarning): # GH#30588 multi-dimensional indexing deprecated values = rng[:, None] expected = rng.values[:, None] diff --git a/pandas/tests/indexes/interval/test_base.py b/pandas/tests/indexes/interval/test_base.py index 891640234d26e..c316655fbda8a 100644 --- a/pandas/tests/indexes/interval/test_base.py +++ b/pandas/tests/indexes/interval/test_base.py @@ -84,5 +84,5 @@ def test_getitem_2d_deprecated(self): # GH#30588 multi-dim indexing is deprecated, but raising is also acceptable idx = self.create_index() with pytest.raises(ValueError, match="multi-dimensional indexing not allowed"): - with tm.assert_produces_warning(DeprecationWarning, check_stacklevel=False): + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): idx[:, None] diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 099c7ced5e2ce..eaf48421dc071 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -56,7 +56,7 @@ def test_can_hold_identifiers(self): @pytest.mark.parametrize("index", ["datetime"], indirect=True) def test_new_axis(self, index): - with tm.assert_produces_warning(DeprecationWarning): + with tm.assert_produces_warning(FutureWarning): # GH#30588 multi-dimensional indexing deprecated new_index = index[None, :] assert new_index.ndim == 2 @@ -2531,7 +2531,7 @@ def test_shape_of_invalid_index(): # that the returned shape is consistent with this underlying array for # compat with matplotlib (see https://github.com/pandas-dev/pandas/issues/27775) idx = pd.Index([0, 1, 2, 3]) - with tm.assert_produces_warning(DeprecationWarning): + with tm.assert_produces_warning(FutureWarning): # GH#30588 multi-dimensional indexing deprecated assert idx[:, None].shape == (4, 1) diff --git a/pandas/tests/series/indexing/test_getitem.py b/pandas/tests/series/indexing/test_getitem.py index 164c63483f71f..6b7cda89a4714 100644 --- a/pandas/tests/series/indexing/test_getitem.py +++ b/pandas/tests/series/indexing/test_getitem.py @@ -51,11 +51,7 @@ class TestSeriesGetitemSlices: def test_getitem_slice_2d(self, datetime_series): # GH#30588 multi-dimensional indexing deprecated - # This is currently failing because the test was relying on - # the DeprecationWarning coming through Index.__getitem__. - # We want to implement a warning specifically for Series.__getitem__ - # at which point this will become a Deprecation/FutureWarning - with tm.assert_produces_warning(None): + with tm.assert_produces_warning(FutureWarning): # GH#30867 Don't want to support this long-term, but # for now ensure that the warning from Index # doesn't comes through via Series.__getitem__. @@ -135,3 +131,9 @@ def test_getitem_generator(string_series): expected = string_series[string_series > 0] tm.assert_series_equal(result, expected) tm.assert_series_equal(result2, expected) + + +def test_getitem_ndim_deprecated(): + s = pd.Series([0, 1]) + with tm.assert_produces_warning(FutureWarning): + s[:, None]