From d48e6463c01c6f8ae8793e62963aae3838630705 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 15 May 2020 17:49:58 +0200 Subject: [PATCH 1/4] DEPR: deprecate Index.__getitem__ with float key --- doc/source/whatsnew/v1.1.0.rst | 3 +++ pandas/core/common.py | 7 +++++++ pandas/tests/indexes/test_indexing.py | 14 ++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 73892da2cbf71..56f8e6e58e9e8 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -586,6 +586,9 @@ Deprecations - :func:`pandas.api.types.is_categorical` is deprecated and will be removed in a future version; use `:func:pandas.api.types.is_categorical_dtype` instead (:issue:`33385`) - :meth:`Index.get_value` is deprecated and will be removed in a future version (:issue:`19728`) - :meth:`DateOffset.__call__` is deprecated and will be removed in a future version, use ``offset + other`` instead (:issue:`34171`) +- Indexing an :class:`Index` object with a float key is deprecated, and will + raise an IndexError in the future. You can manually convert to an integer key + instead (:issue:`34191`). .. --------------------------------------------------------------------------- diff --git a/pandas/core/common.py b/pandas/core/common.py index 1ccca5193ab46..6425cbeef0c2b 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -9,6 +9,7 @@ from functools import partial import inspect from typing import Any, Collection, Iterable, List, Union +import warnings import numpy as np @@ -158,6 +159,12 @@ def cast_scalar_indexer(val): """ # assumes lib.is_scalar(val) if lib.is_float(val) and val.is_integer(): + warnings.warn( + "Indexing with a float is deprecated, and will raise an IndexError " + "in pandas 2.0. You can manually convert to an integer key instead.", + FutureWarning, + stacklevel=3, + ) return int(val) return val diff --git a/pandas/tests/indexes/test_indexing.py b/pandas/tests/indexes/test_indexing.py index a79bde9fd04e1..8910a3731cf8a 100644 --- a/pandas/tests/indexes/test_indexing.py +++ b/pandas/tests/indexes/test_indexing.py @@ -17,6 +17,7 @@ import pytest from pandas import Float64Index, Index, Int64Index, UInt64Index +import pandas._testing as tm class TestContains: @@ -82,3 +83,16 @@ def test_contains_with_float_index(self): assert 1.1 in float_index assert 1.0 not in float_index assert 1 not in float_index + + +@pytest.mark.parametrize( + "idx", [Index([1, 2, 3]), Index([0.1, 0.2, 0.3]), Index(["a", "b", "c"])] +) +def test_getitem_deprecated_float(idx): + # https://github.com/pandas-dev/pandas/issues/34191 + + with tm.assert_produces_warning(FutureWarning): + result = idx[1.0] + + expected = idx[1] + assert result == expected From b551587a2c22674660ae244bf4db90c1acb79569 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 15 May 2020 22:12:57 +0200 Subject: [PATCH 2/4] avoid the warning in get_loc --- pandas/core/common.py | 17 ++++++++++------- pandas/core/indexes/base.py | 2 +- pandas/core/indexes/multi.py | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index 6425cbeef0c2b..8bbb68df5ec24 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -145,13 +145,15 @@ def is_bool_indexer(key: Any) -> bool: return False -def cast_scalar_indexer(val): +def cast_scalar_indexer(val, warn_float=False): """ To avoid numpy DeprecationWarnings, cast float to integer where valid. Parameters ---------- val : scalar + warn_float : bool, default False + If True, raise deprecation warning for a float indexer. Returns ------- @@ -159,12 +161,13 @@ def cast_scalar_indexer(val): """ # assumes lib.is_scalar(val) if lib.is_float(val) and val.is_integer(): - warnings.warn( - "Indexing with a float is deprecated, and will raise an IndexError " - "in pandas 2.0. You can manually convert to an integer key instead.", - FutureWarning, - stacklevel=3, - ) + if warn_float: + warnings.warn( + "Indexing with a float is deprecated, and will raise an IndexError " + "in pandas 2.0. You can manually convert to an integer key instead.", + FutureWarning, + stacklevel=3, + ) return int(val) return val diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index b8a9827b5effd..1fcef08e96728 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4039,7 +4039,7 @@ def __getitem__(self, key): promote = self._shallow_copy if is_scalar(key): - key = com.cast_scalar_indexer(key) + key = com.cast_scalar_indexer(key, warn_float=True) return getitem(key) if isinstance(key, slice): diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index f1e1ebcaca1c4..5213137eb5c29 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1896,7 +1896,7 @@ def __reduce__(self): def __getitem__(self, key): if is_scalar(key): - key = com.cast_scalar_indexer(key) + key = com.cast_scalar_indexer(key, warn_float=True) retval = [] for lev, level_codes in zip(self.levels, self.codes): From bf9420af779b90c539eedb1908bbc9e2b41473a9 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 15 May 2020 22:49:00 +0200 Subject: [PATCH 3/4] avoid warning in plotting code --- pandas/plotting/_matplotlib/core.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 19a75eb151782..4015a933b2fac 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -8,6 +8,7 @@ from pandas.util._decorators import cache_readonly from pandas.core.dtypes.common import ( + is_float, is_hashable, is_integer, is_iterator, @@ -1188,6 +1189,8 @@ def _post_plot_logic(self, ax, data): from matplotlib.ticker import FixedLocator def get_label(i): + if is_float(i) and i.is_integer(): + i = int(i) try: return pprint_thing(data.index[i]) except Exception: From 2ed0d4a4db270c861d060c711615fb2dc7a1c750 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Fri, 22 May 2020 08:23:49 +0200 Subject: [PATCH 4/4] update --- doc/source/whatsnew/v1.1.0.rst | 2 +- pandas/core/common.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 56f8e6e58e9e8..9467667840dbd 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -587,7 +587,7 @@ Deprecations - :meth:`Index.get_value` is deprecated and will be removed in a future version (:issue:`19728`) - :meth:`DateOffset.__call__` is deprecated and will be removed in a future version, use ``offset + other`` instead (:issue:`34171`) - Indexing an :class:`Index` object with a float key is deprecated, and will - raise an IndexError in the future. You can manually convert to an integer key + raise an ``IndexError`` in the future. You can manually convert to an integer key instead (:issue:`34191`). .. --------------------------------------------------------------------------- diff --git a/pandas/core/common.py b/pandas/core/common.py index 8bbb68df5ec24..575eaba361106 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -153,7 +153,7 @@ def cast_scalar_indexer(val, warn_float=False): ---------- val : scalar warn_float : bool, default False - If True, raise deprecation warning for a float indexer. + If True, issue deprecation warning for a float indexer. Returns -------