From 3772f4c37c67f47a4ba9f17e5fec434e48bbbe94 Mon Sep 17 00:00:00 2001 From: jreback Date: Wed, 9 Apr 2014 16:35:05 -0400 Subject: [PATCH] DEPR: Indexers will warn FutureWarning when used with a scalar indexer and a non-floating point Index (GH4892) --- doc/source/release.rst | 3 ++ doc/source/v0.14.0.txt | 21 +++++++++++++ pandas/core/index.py | 15 +++++++-- pandas/index.pyx | 2 ++ pandas/tests/test_indexing.py | 59 +++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/doc/source/release.rst b/doc/source/release.rst index e37a7c7eab861..aaa91f30f5013 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -189,6 +189,9 @@ Deprecations ``FutureWarning`` is raised to alert that the old ``cols`` arguments will not be supported in a future release (:issue:`6645`) +- Indexers will warn ``FutureWarning`` when used with a scalar indexer and + a non-floating point Index (:issue:`4892`) + Prior Version Deprecations/Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/v0.14.0.txt b/doc/source/v0.14.0.txt index 05569dbdba702..8f33269fd406b 100644 --- a/doc/source/v0.14.0.txt +++ b/doc/source/v0.14.0.txt @@ -390,6 +390,27 @@ Deprecations ``FutureWarning`` is raised to alert that the old ``cols`` arguments will not be supported in a future release (:issue:`6645`) +- Indexers will warn ``FutureWarning`` when used with a scalar indexer and + a non-floating point Index (:issue:`4892`) + + .. code-block:: python + + # non-floating point indexes can only be indexed by integers / labels + In [1]: Series(1,np.arange(5))[3.0] + pandas/core/index.py:469: FutureWarning: scalar indexers for index type Int64Index should be integers and not floating point + Out[1]: 1 + + In [5]: Series(1,np.arange(5)).iloc[3.0] + pandas/core/index.py:469: FutureWarning: scalar indexers for index type Int64Index should be integers and not floating point + Out[5]: 1 + + # these are Float64Indexes, so integer or floating point is acceptable + In [3]: Series(1,np.arange(5.))[3] + Out[3]: 1 + + In [4]: Series(1,np.arange(5.))[3.0] + Out[4]: 1 + .. _whatsnew_0140.enhancements: Enhancements diff --git a/pandas/core/index.py b/pandas/core/index.py index e8403bfe8b4f8..a581a8753ae51 100644 --- a/pandas/core/index.py +++ b/pandas/core/index.py @@ -1,6 +1,7 @@ # pylint: disable=E1101,E1103,W0232 import datetime from functools import partial +import warnings from pandas.compat import range, zip, lrange, lzip, u, reduce from pandas import compat import numpy as np @@ -468,11 +469,19 @@ def to_int(): return ikey if typ == 'iloc': - if not (is_integer(key) or is_float(key)): - self._convert_indexer_error(key, 'label') - return to_int() + if is_integer(key): + return key + elif is_float(key): + if not self.is_floating(): + warnings.warn("scalar indexers for index type {0} should be integers and not floating point".format( + type(self).__name__),FutureWarning) + return to_int() + return self._convert_indexer_error(key, 'label') if is_float(key): + if not self.is_floating(): + warnings.warn("scalar indexers for index type {0} should be integers and not floating point".format( + type(self).__name__),FutureWarning) return to_int() return key diff --git a/pandas/index.pyx b/pandas/index.pyx index 8aa4f69a1ec8e..e5cfa3f7c6f16 100644 --- a/pandas/index.pyx +++ b/pandas/index.pyx @@ -355,6 +355,8 @@ cdef class Int64Engine(IndexEngine): hash(val) if util.is_bool_object(val): raise KeyError(val) + elif util.is_float_object(val): + raise KeyError(val) cdef _maybe_get_bool_indexer(self, object val): cdef: diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index ea1e07dbf6acc..f730d415a6acc 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -94,6 +94,7 @@ class TestIndexing(tm.TestCase): _typs = set(['ints','labels','mixed','ts','floats','empty']) def setUp(self): + import warnings warnings.filterwarnings(action='ignore', category=FutureWarning) @@ -3220,6 +3221,64 @@ def test_ix_empty_list_indexer_is_ok(self): assert_frame_equal(df.ix[:,[]], df.iloc[:, :0]) # vertical empty assert_frame_equal(df.ix[[],:], df.iloc[:0, :]) # horizontal empty + def test_deprecate_float_indexers(self): + + # GH 4892 + # deprecate allowing float indexers that are equal to ints to be used + # as indexers in non-float indices + + import warnings + warnings.filterwarnings(action='error', category=FutureWarning) + + for index in [ tm.makeStringIndex, tm.makeUnicodeIndex, + tm.makeDateIndex, tm.makePeriodIndex ]: + + i = index(5) + s = Series(np.arange(len(i)),index=i) + self.assertRaises(FutureWarning, lambda : + s.iloc[3.0]) + self.assertRaises(FutureWarning, lambda : + s[3.0]) + + # this is ok! + s[3] + + # ints + i = index(5) + s = Series(np.arange(len(i))) + self.assertRaises(FutureWarning, lambda : + s.iloc[3.0]) + + # on some arch's this doesn't provide a warning (and thus raise) + # and some it does + try: + s[3.0] + except: + pass + + # floats: these are all ok! + i = np.arange(5.) + s = Series(np.arange(len(i)),index=i) + with tm.assert_produces_warning(False): + s[3.0] + + with tm.assert_produces_warning(False): + s[3] + + with tm.assert_produces_warning(False): + s.iloc[3.0] + + with tm.assert_produces_warning(False): + s.iloc[3] + + with tm.assert_produces_warning(False): + s.loc[3.0] + + with tm.assert_produces_warning(False): + s.loc[3] + + warnings.filterwarnings(action='ignore', category=FutureWarning) + if __name__ == '__main__': import nose nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],