From 3505aeaaaf615a3ad2d71a70cfe0538ac6128549 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 10 Feb 2020 12:31:06 -0800 Subject: [PATCH 1/6] TST: parametrize tests --- pandas/tests/indexing/test_floats.py | 349 +++++++++++++-------------- 1 file changed, 174 insertions(+), 175 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 6cc18a3989266..309dad9370c30 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -5,6 +5,16 @@ import pandas._testing as tm +def gen_obj(klass, index): + if klass is Series: + obj = Series(np.arange(len(index)), index=index) + else: + obj = DataFrame( + np.random.randn(len(index), len(index)), index=index, columns=index + ) + return obj + + class TestFloatIndexers: def check(self, result, original, indexer, getitem): """ @@ -178,19 +188,18 @@ def test_scalar_with_mixed(self): # lookup in a pure stringstr # with an invalid indexer - for idxr in [lambda x: x, lambda x: x.iloc]: - - msg = ( - r"cannot do label indexing " - r"on {klass} with these indexers \[1\.0\] of " - r"type float|" - "Cannot index by location index with a non-integer key".format( - klass=Index.__name__ - ) + msg = ( + r"cannot do label indexing " + r"on {klass} with these indexers \[1\.0\] of " + r"type float|" + "Cannot index by location index with a non-integer key".format( + klass=Index.__name__ ) - with pytest.raises(TypeError, match=msg): - idxr(s2)[1.0] - + ) + with pytest.raises(TypeError, match=msg): + s2[1.0] + with pytest.raises(TypeError, match=msg): + s2.iloc[1.0] with pytest.raises(KeyError, match=r"^1\.0$"): s2.loc[1.0] @@ -200,19 +209,17 @@ def test_scalar_with_mixed(self): # mixed index so we have label # indexing - for idxr in [lambda x: x]: - - msg = ( - r"cannot do label indexing " - r"on {klass} with these indexers \[1\.0\] of " - r"type float".format(klass=Index.__name__) - ) - with pytest.raises(TypeError, match=msg): - idxr(s3)[1.0] + msg = ( + r"cannot do label indexing " + r"on {klass} with these indexers \[1\.0\] of " + r"type float".format(klass=Index.__name__) + ) + with pytest.raises(TypeError, match=msg): + s3[1.0] - result = idxr(s3)[1] - expected = 2 - assert result == expected + result = s3[1] + expected = 2 + assert result == expected msg = "Cannot index by location index with a non-integer key" with pytest.raises(TypeError, match=msg): @@ -236,6 +243,7 @@ def test_scalar_integer(self, index_func, klass): i = index_func(5) if klass is Series: + # TODO: Should we be passing index=i here? obj = Series(np.arange(len(i))) else: obj = DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i) @@ -275,58 +283,54 @@ def compare(x, y): # coerce to equal int assert 3.0 in obj - def test_scalar_float(self): + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_scalar_float(self, klass): # scalar float indexers work on a float index index = Index(np.arange(5.0)) - for s in [ - Series(np.arange(len(index)), index=index), - DataFrame( - np.random.randn(len(index), len(index)), index=index, columns=index - ), - ]: + s = gen_obj(klass, index) - # assert all operations except for iloc are ok - indexer = index[3] - for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: + # assert all operations except for iloc are ok + indexer = index[3] + for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: - # getting - result = idxr(s)[indexer] - self.check(result, s, 3, getitem) + # getting + result = idxr(s)[indexer] + self.check(result, s, 3, getitem) - # setting - s2 = s.copy() + # setting + s2 = s.copy() - result = idxr(s2)[indexer] - self.check(result, s, 3, getitem) + result = idxr(s2)[indexer] + self.check(result, s, 3, getitem) - # random integer is a KeyError - with pytest.raises(KeyError, match=r"^3\.5$"): - idxr(s)[3.5] + # random integer is a KeyError + with pytest.raises(KeyError, match=r"^3\.5$"): + idxr(s)[3.5] - # contains - assert 3.0 in s + # contains + assert 3.0 in s - # iloc succeeds with an integer - expected = s.iloc[3] - s2 = s.copy() + # iloc succeeds with an integer + expected = s.iloc[3] + s2 = s.copy() - s2.iloc[3] = expected - result = s2.iloc[3] - self.check(result, s, 3, False) + s2.iloc[3] = expected + result = s2.iloc[3] + self.check(result, s, 3, False) - # iloc raises with a float - msg = "Cannot index by location index with a non-integer key" - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] + # iloc raises with a float + msg = "Cannot index by location index with a non-integer key" + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] - msg = ( - r"cannot do positional indexing " - r"on {klass} with these indexers \[3\.0\] of " - r"type float".format(klass=Float64Index.__name__) - ) - with pytest.raises(TypeError, match=msg): - s2.iloc[3.0] = 0 + msg = ( + r"cannot do positional indexing " + r"on {klass} with these indexers \[3\.0\] of " + r"type float".format(klass=Float64Index.__name__) + ) + with pytest.raises(TypeError, match=msg): + s2.iloc[3.0] = 0 @pytest.mark.parametrize( "index_func", @@ -338,60 +342,60 @@ def test_scalar_float(self): tm.makePeriodIndex, ], ) - def test_slice_non_numeric(self, index_func): + @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_slice_non_numeric(self, index_func, l, klass): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors index = index_func(5) - for s in [ - Series(range(5), index=index), - DataFrame(np.random.randn(5, 2), index=index), - ]: - - # getitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - - msg = ( - "cannot do positional indexing " - r"on {klass} with these indexers \[(3|4)\.0\] of " - "type float".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] + s = gen_obj(klass, index) - for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: - - msg = ( - "cannot do (slice|positional) indexing " - r"on {klass} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] + # getitem + msg = ( + "cannot do positional indexing " + r"on {klass} with these indexers \[(3|4)\.0\] of " + "type float".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] - # setitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + msg = ( + "cannot do (slice|positional) indexing " + r"on {klass} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s.loc[l] + with pytest.raises(TypeError, match=msg): + s.iloc[l] + with pytest.raises(TypeError, match=msg): + s[l] - msg = ( - "cannot do positional indexing " - r"on {klass} with these indexers \[(3|4)\.0\] of " - "type float".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] = 0 + # setitem + msg = ( + "cannot do positional indexing " + r"on {klass} with these indexers \[(3|4)\.0\] of " + "type float".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] = 0 - for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: - msg = ( - "cannot do (slice|positional) indexing " - r"on {klass} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] = 0 + msg = ( + "cannot do (slice|positional) indexing " + r"on {klass} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s.loc[l] = 0 + with pytest.raises(TypeError, match=msg): + s.iloc[l] = 0 + with pytest.raises(TypeError, match=msg): + s[l] = 0 def test_slice_integer(self): @@ -501,7 +505,8 @@ def test_slice_integer(self): with pytest.raises(TypeError, match=msg): s[l] = 0 - def test_integer_positional_indexing(self): + @pytest.mark.parametrize("l", [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]) + def test_integer_positional_indexing(self, l): """ make sure that we are raising on positional indexing w.r.t. an integer index """ @@ -511,18 +516,16 @@ def test_integer_positional_indexing(self): expected = s.iloc[2:4] tm.assert_series_equal(result, expected) - for idxr in [lambda x: x, lambda x: x.iloc]: - - for l in [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]: - - klass = RangeIndex - msg = ( - "cannot do (slice|positional) indexing " - r"on {klass} with these indexers \[(2|4)\.0\] of " - "type float".format(klass=klass.__name__) - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] + klass = RangeIndex + msg = ( + "cannot do (slice|positional) indexing " + r"on {klass} with these indexers \[(2|4)\.0\] of " + "type float".format(klass=klass.__name__) + ) + with pytest.raises(TypeError, match=msg): + s[l] + with pytest.raises(TypeError, match=msg): + s.iloc[l] @pytest.mark.parametrize( "index_func", [tm.makeIntIndex, tm.makeRangeIndex], @@ -534,76 +537,72 @@ def test_slice_integer_frame_getitem(self, index_func): s = DataFrame(np.random.randn(5, 2), index=index) - def f(idxr): - - # getitem - for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - - result = idxr(s)[l] - indexer = slice(0, 2) - self.check(result, s, indexer, False) - - # positional indexing - msg = ( - "cannot do slice indexing " - r"on {klass} with these indexers \[(0|1)\.0\] of " - "type float".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - s[l] - - # getitem out-of-bounds - for l in [slice(-10, 10), slice(-10.0, 10.0)]: + # getitem + for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - result = idxr(s)[l] - self.check(result, s, slice(-10, 10), True) + result = s.loc[l] + indexer = slice(0, 2) + self.check(result, s, indexer, False) # positional indexing msg = ( "cannot do slice indexing " - r"on {klass} with these indexers \[-10\.0\] of " + r"on {klass} with these indexers \[(0|1)\.0\] of " "type float".format(klass=type(index).__name__) ) with pytest.raises(TypeError, match=msg): - s[slice(-10.0, 10.0)] + s[l] - # getitem odd floats - for l, res in [ - (slice(0.5, 1), slice(1, 2)), - (slice(0, 0.5), slice(0, 1)), - (slice(0.5, 1.5), slice(1, 2)), - ]: + # getitem out-of-bounds + for l in [slice(-10, 10), slice(-10.0, 10.0)]: - result = idxr(s)[l] - self.check(result, s, res, False) + result = s.loc[l] + self.check(result, s, slice(-10, 10), True) - # positional indexing - msg = ( - "cannot do slice indexing " - r"on {klass} with these indexers \[0\.5\] of " - "type float".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - s[l] + # positional indexing + msg = ( + "cannot do slice indexing " + r"on {klass} with these indexers \[-10\.0\] of " + "type float".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s[slice(-10.0, 10.0)] - # setitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + # getitem odd floats + for l, res in [ + (slice(0.5, 1), slice(1, 2)), + (slice(0, 0.5), slice(0, 1)), + (slice(0.5, 1.5), slice(1, 2)), + ]: - sc = s.copy() - idxr(sc)[l] = 0 - result = idxr(sc)[l].values.ravel() - assert (result == 0).all() + result = s.loc[l] + self.check(result, s, res, False) - # positional indexing - msg = ( - "cannot do slice indexing " - r"on {klass} with these indexers \[(3|4)\.0\] of " - "type float".format(klass=type(index).__name__) - ) - with pytest.raises(TypeError, match=msg): - s[l] = 0 + # positional indexing + msg = ( + "cannot do slice indexing " + r"on {klass} with these indexers \[0\.5\] of " + "type float".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s[l] + + # setitem + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + + sc = s.copy() + sc.loc[l] = 0 + result = sc.loc[l].values.ravel() + assert (result == 0).all() - f(lambda x: x.loc) + # positional indexing + msg = ( + "cannot do slice indexing " + r"on {klass} with these indexers \[(3|4)\.0\] of " + "type float".format(klass=type(index).__name__) + ) + with pytest.raises(TypeError, match=msg): + s[l] = 0 def test_slice_float(self): From d6a7c97129d2f9885b37c5a1969605ccd2068d4d Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 10 Feb 2020 12:35:08 -0800 Subject: [PATCH 2/6] parametrize float indexing tests --- pandas/tests/indexing/test_floats.py | 174 ++++++++++++++------------- 1 file changed, 91 insertions(+), 83 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 309dad9370c30..4f608244fe1d1 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -80,97 +80,108 @@ def test_scalar_error(self, index_func): tm.makePeriodIndex, ], ) - def test_scalar_non_numeric(self, index_func): + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_scalar_non_numeric(self, index_func, klass): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors i = index_func(5) + s = gen_obj(klass, i) - for s in [ - Series(np.arange(len(i)), index=i), - DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i), - ]: - - # getting - for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: + # getting + for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: - # gettitem on a DataFrame is a KeyError as it is indexing - # via labels on the columns - if getitem and isinstance(s, DataFrame): - error = KeyError - msg = r"^3(\.0)?$" - else: - error = TypeError - msg = ( - r"cannot do (label|positional) indexing " - r"on {klass} with these indexers \[3\.0\] of " - r"type float|" - "Cannot index by location index with a " - "non-integer key".format(klass=type(i).__name__) - ) - with pytest.raises(error, match=msg): - idxr(s)[3.0] - - # label based can be a TypeError or KeyError - if s.index.inferred_type in { - "categorical", - "string", - "unicode", - "mixed", - }: + # gettitem on a DataFrame is a KeyError as it is indexing + # via labels on the columns + if getitem and isinstance(s, DataFrame): error = KeyError - msg = r"^3\.0$" + msg = r"^3(\.0)?$" else: error = TypeError msg = ( r"cannot do (label|positional) indexing " r"on {klass} with these indexers \[3\.0\] of " - r"type float".format(klass=type(i).__name__) + r"type float|" + "Cannot index by location index with a " + "non-integer key".format(klass=type(i).__name__) ) with pytest.raises(error, match=msg): - s.loc[3.0] - - # contains - assert 3.0 not in s - - # setting with a float fails with iloc + idxr(s)[3.0] + + # label based can be a TypeError or KeyError + if s.index.inferred_type in { + "categorical", + "string", + "unicode", + "mixed", + }: + error = KeyError + msg = r"^3\.0$" + else: + error = TypeError msg = ( r"cannot do (label|positional) indexing " r"on {klass} with these indexers \[3\.0\] of " r"type float".format(klass=type(i).__name__) ) - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] = 0 - - # setting with an indexer - if s.index.inferred_type in ["categorical"]: - # Value or Type Error - pass - elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: - - # these should prob work - # and are inconsistent between series/dataframe ATM - # for idxr in [lambda x: x]: - # s2 = s.copy() - # - # with pytest.raises(TypeError): - # idxr(s2)[3.0] = 0 - pass + with pytest.raises(error, match=msg): + s.loc[3.0] - else: + # contains + assert 3.0 not in s + # setting with a float fails with iloc + msg = ( + r"cannot do (label|positional) indexing " + r"on {klass} with these indexers \[3\.0\] of " + r"type float".format(klass=type(i).__name__) + ) + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] = 0 + + # setting with an indexer + if s.index.inferred_type in ["categorical"]: + # Value or Type Error + pass + elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: + + # these should prob work + # and are inconsistent between series/dataframe ATM + # for idxr in [lambda x: x]: + # s2 = s.copy() + # + # with pytest.raises(TypeError): + # idxr(s2)[3.0] = 0 + pass + + else: + + s2 = s.copy() + s2.loc[3.0] = 10 + assert s2.index.is_object() + + for idxr in [lambda x: x]: s2 = s.copy() - s2.loc[3.0] = 10 + idxr(s2)[3.0] = 0 assert s2.index.is_object() - for idxr in [lambda x: x]: - s2 = s.copy() - idxr(s2)[3.0] = 0 - assert s2.index.is_object() + @pytest.mark.parametrize( + "index_func", + [ + tm.makeStringIndex, + tm.makeUnicodeIndex, + tm.makeCategoricalIndex, + tm.makeDateIndex, + tm.makeTimedeltaIndex, + tm.makePeriodIndex, + ], + ) + def test_scalar_non_numeric_series_fallback(self, index_func): # fallsback to position selection, series only + i = index_func(5) s = Series(np.arange(len(i)), index=i) s[3] msg = ( @@ -604,31 +615,28 @@ def test_slice_integer_frame_getitem(self, index_func): with pytest.raises(TypeError, match=msg): s[l] = 0 - def test_slice_float(self): + @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_slice_float(self, l, klass): # same as above, but for floats index = Index(np.arange(5.0)) + 0.1 - for s in [ - Series(range(5), index=index), - DataFrame(np.random.randn(5, 2), index=index), - ]: - - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + s = gen_obj(klass, index) - expected = s.iloc[3:4] - for idxr in [lambda x: x.loc, lambda x: x]: + expected = s.iloc[3:4] + for idxr in [lambda x: x.loc, lambda x: x]: - # getitem - result = idxr(s)[l] - if isinstance(s, Series): - tm.assert_series_equal(result, expected) - else: - tm.assert_frame_equal(result, expected) - # setitem - s2 = s.copy() - idxr(s2)[l] = 0 - result = idxr(s2)[l].values.ravel() - assert (result == 0).all() + # getitem + result = idxr(s)[l] + if isinstance(s, Series): + tm.assert_series_equal(result, expected) + else: + tm.assert_frame_equal(result, expected) + # setitem + s2 = s.copy() + idxr(s2)[l] = 0 + result = idxr(s2)[l].values.ravel() + assert (result == 0).all() def test_floating_index_doc_example(self): From a063b3af16bad6f24d098b6243559842f8665c5f Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 10 Feb 2020 12:38:25 -0800 Subject: [PATCH 3/6] de-loop tests --- pandas/tests/indexing/test_floats.py | 69 +++++++++++++--------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 4f608244fe1d1..3f4373e27f47d 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -162,10 +162,9 @@ def test_scalar_non_numeric(self, index_func, klass): s2.loc[3.0] = 10 assert s2.index.is_object() - for idxr in [lambda x: x]: - s2 = s.copy() - idxr(s2)[3.0] = 0 - assert s2.index.is_object() + s2 = s.copy() + s2[3.0] = 0 + assert s2.index.is_object() @pytest.mark.parametrize( "index_func", @@ -426,18 +425,16 @@ def test_slice_integer(self): # getitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - for idxr in [lambda x: x.loc]: + result = s.loc[l] - result = idxr(s)[l] - - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(3, 5) - self.check(result, s, indexer, False) + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(3, 5) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -451,17 +448,16 @@ def test_slice_integer(self): # getitem out-of-bounds for l in [slice(-6, 6), slice(-6.0, 6.0)]: - for idxr in [lambda x: x.loc]: - result = idxr(s)[l] + result = s.loc[l] - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(-6, 6) - self.check(result, s, indexer, False) + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(-6, 6) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -479,15 +475,13 @@ def test_slice_integer(self): (slice(2.5, 3.5), slice(3, 4)), ]: - for idxr in [lambda x: x.loc]: - - result = idxr(s)[l] - if oob: - res = slice(0, 0) - else: - res = res1 + result = s.loc[l] + if oob: + res = slice(0, 0) + else: + res = res1 - self.check(result, s, res, False) + self.check(result, s, res, False) # positional indexing msg = ( @@ -501,11 +495,10 @@ def test_slice_integer(self): # setitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - for idxr in [lambda x: x.loc]: - sc = s.copy() - idxr(sc)[l] = 0 - result = idxr(sc)[l].values.ravel() - assert (result == 0).all() + sc = s.copy() + sc.loc[l] = 0 + result = sc.loc[l].values.ravel() + assert (result == 0).all() # positional indexing msg = ( From dc2de55f81da5546b16192dfb774acc58bc0cb60 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 10 Feb 2020 12:44:32 -0800 Subject: [PATCH 4/6] simplify assert --- pandas/tests/indexing/test_floats.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 3f4373e27f47d..762f52e7b3adf 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -621,10 +621,9 @@ def test_slice_float(self, l, klass): # getitem result = idxr(s)[l] - if isinstance(s, Series): - tm.assert_series_equal(result, expected) - else: - tm.assert_frame_equal(result, expected) + assert isinstance(result, type(s)) + tm.assert_equal(result, expected) + # setitem s2 = s.copy() idxr(s2)[l] = 0 From 33f8f999d92936f097cade2147870c0a8655c00d Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 13 Feb 2020 18:37:28 -0800 Subject: [PATCH 5/6] revert bc rebase was messy --- pandas/tests/indexing/test_floats.py | 585 ++++++++++++++------------- 1 file changed, 293 insertions(+), 292 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 04a8f90faea54..80a4d81b20a13 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -5,16 +5,6 @@ import pandas._testing as tm -def gen_obj(klass, index): - if klass is Series: - obj = Series(np.arange(len(index)), index=index) - else: - obj = DataFrame( - np.random.randn(len(index), len(index)), index=index, columns=index - ) - return obj - - class TestFloatIndexers: def check(self, result, original, indexer, getitem): """ @@ -80,107 +70,97 @@ def test_scalar_error(self, index_func): tm.makePeriodIndex, ], ) - @pytest.mark.parametrize("klass", [Series, DataFrame]) - def test_scalar_non_numeric(self, index_func, klass): + def test_scalar_non_numeric(self, index_func): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors i = index_func(5) - s = gen_obj(klass, i) - # getting - for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: + for s in [ + Series(np.arange(len(i)), index=i), + DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i), + ]: + + # getting + for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: - # gettitem on a DataFrame is a KeyError as it is indexing - # via labels on the columns - if getitem and isinstance(s, DataFrame): + # gettitem on a DataFrame is a KeyError as it is indexing + # via labels on the columns + if getitem and isinstance(s, DataFrame): + error = KeyError + msg = r"^3(\.0)?$" + else: + error = TypeError + msg = ( + r"cannot do (label|positional) indexing " + fr"on {type(i).__name__} with these indexers \[3\.0\] of " + r"type float|" + "Cannot index by location index with a " + "non-integer key" + ) + with pytest.raises(error, match=msg): + idxr(s)[3.0] + + # label based can be a TypeError or KeyError + if s.index.inferred_type in { + "categorical", + "string", + "unicode", + "mixed", + }: error = KeyError - msg = r"^3(\.0)?$" + msg = r"^3\.0$" else: error = TypeError msg = ( r"cannot do (label|positional) indexing " fr"on {type(i).__name__} with these indexers \[3\.0\] of " - r"type float|" - "Cannot index by location index with a " - "non-integer key" + "type float" ) with pytest.raises(error, match=msg): - idxr(s)[3.0] - - # label based can be a TypeError or KeyError - if s.index.inferred_type in { - "categorical", - "string", - "unicode", - "mixed", - }: - error = KeyError - msg = r"^3\.0$" - else: - error = TypeError + s.loc[3.0] + + # contains + assert 3.0 not in s + + # setting with a float fails with iloc msg = ( r"cannot do (label|positional) indexing " fr"on {type(i).__name__} with these indexers \[3\.0\] of " "type float" ) - with pytest.raises(error, match=msg): - s.loc[3.0] - - # contains - assert 3.0 not in s - - # setting with a float fails with iloc - msg = ( - r"cannot do (label|positional) indexing " - fr"on {type(i).__name__} with these indexers \[3\.0\] of " - r"type float" - ) - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] = 0 - - # setting with an indexer - if s.index.inferred_type in ["categorical"]: - # Value or Type Error - pass - elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: - - # these should prob work - # and are inconsistent between series/dataframe ATM - # for idxr in [lambda x: x]: - # s2 = s.copy() - # - # with pytest.raises(TypeError): - # idxr(s2)[3.0] = 0 - pass - - else: + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] = 0 + + # setting with an indexer + if s.index.inferred_type in ["categorical"]: + # Value or Type Error + pass + elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: + + # these should prob work + # and are inconsistent between series/dataframe ATM + # for idxr in [lambda x: x]: + # s2 = s.copy() + # + # with pytest.raises(TypeError): + # idxr(s2)[3.0] = 0 + pass - s2 = s.copy() - s2.loc[3.0] = 10 - assert s2.index.is_object() + else: - s2 = s.copy() - s2[3.0] = 0 - assert s2.index.is_object() + s2 = s.copy() + s2.loc[3.0] = 10 + assert s2.index.is_object() - @pytest.mark.parametrize( - "index_func", - [ - tm.makeStringIndex, - tm.makeUnicodeIndex, - tm.makeCategoricalIndex, - tm.makeDateIndex, - tm.makeTimedeltaIndex, - tm.makePeriodIndex, - ], - ) - def test_scalar_non_numeric_series_fallback(self, index_func): + for idxr in [lambda x: x]: + s2 = s.copy() + idxr(s2)[3.0] = 0 + assert s2.index.is_object() # fallsback to position selection, series only - i = index_func(5) s = Series(np.arange(len(i)), index=i) s[3] msg = ( @@ -198,16 +178,17 @@ def test_scalar_with_mixed(self): # lookup in a pure stringstr # with an invalid indexer - msg = ( - r"cannot do label indexing " - r"on Index with these indexers \[1\.0\] of " - r"type float|" - "Cannot index by location index with a non-integer key" - ) - with pytest.raises(TypeError, match=msg): - s2[1.0] - with pytest.raises(TypeError, match=msg): - s2.iloc[1.0] + for idxr in [lambda x: x, lambda x: x.iloc]: + + msg = ( + "cannot do label indexing " + fr"on {Index.__name__} with these indexers \[1\.0\] of " + r"type float|" + "Cannot index by location index with a non-integer key" + ) + with pytest.raises(TypeError, match=msg): + idxr(s2)[1.0] + with pytest.raises(KeyError, match=r"^1\.0$"): s2.loc[1.0] @@ -217,17 +198,19 @@ def test_scalar_with_mixed(self): # mixed index so we have label # indexing - msg = ( - r"cannot do label indexing " - r"on Index with these indexers \[1\.0\] of " - r"type float" - ) - with pytest.raises(TypeError, match=msg): - s3[1.0] + for idxr in [lambda x: x]: - result = s3[1] - expected = 2 - assert result == expected + msg = ( + "cannot do label indexing " + fr"on {Index.__name__} with these indexers \[1\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + idxr(s3)[1.0] + + result = idxr(s3)[1] + expected = 2 + assert result == expected msg = "Cannot index by location index with a non-integer key" with pytest.raises(TypeError, match=msg): @@ -251,7 +234,6 @@ def test_scalar_integer(self, index_func, klass): i = index_func(5) if klass is Series: - # TODO: Should we be passing index=i here? obj = Series(np.arange(len(i))) else: obj = DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i) @@ -291,54 +273,58 @@ def compare(x, y): # coerce to equal int assert 3.0 in obj - @pytest.mark.parametrize("klass", [Series, DataFrame]) - def test_scalar_float(self, klass): + def test_scalar_float(self): # scalar float indexers work on a float index index = Index(np.arange(5.0)) - s = gen_obj(klass, index) + for s in [ + Series(np.arange(len(index)), index=index), + DataFrame( + np.random.randn(len(index), len(index)), index=index, columns=index + ), + ]: - # assert all operations except for iloc are ok - indexer = index[3] - for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: + # assert all operations except for iloc are ok + indexer = index[3] + for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: - # getting - result = idxr(s)[indexer] - self.check(result, s, 3, getitem) + # getting + result = idxr(s)[indexer] + self.check(result, s, 3, getitem) - # setting - s2 = s.copy() + # setting + s2 = s.copy() - result = idxr(s2)[indexer] - self.check(result, s, 3, getitem) + result = idxr(s2)[indexer] + self.check(result, s, 3, getitem) - # random integer is a KeyError - with pytest.raises(KeyError, match=r"^3\.5$"): - idxr(s)[3.5] + # random integer is a KeyError + with pytest.raises(KeyError, match=r"^3\.5$"): + idxr(s)[3.5] - # contains - assert 3.0 in s + # contains + assert 3.0 in s - # iloc succeeds with an integer - expected = s.iloc[3] - s2 = s.copy() + # iloc succeeds with an integer + expected = s.iloc[3] + s2 = s.copy() - s2.iloc[3] = expected - result = s2.iloc[3] - self.check(result, s, 3, False) + s2.iloc[3] = expected + result = s2.iloc[3] + self.check(result, s, 3, False) - # iloc raises with a float - msg = "Cannot index by location index with a non-integer key" - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] + # iloc raises with a float + msg = "Cannot index by location index with a non-integer key" + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] - msg = ( - r"cannot do positional indexing " - r"on Float64Index with these indexers \[3\.0\] of " - r"type float" - ) - with pytest.raises(TypeError, match=msg): - s2.iloc[3.0] = 0 + msg = ( + "cannot do positional indexing " + fr"on {Float64Index.__name__} with these indexers \[3\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s2.iloc[3.0] = 0 @pytest.mark.parametrize( "index_func", @@ -350,60 +336,60 @@ def test_scalar_float(self, klass): tm.makePeriodIndex, ], ) - @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) - @pytest.mark.parametrize("klass", [Series, DataFrame]) - def test_slice_non_numeric(self, index_func, l, klass): + def test_slice_non_numeric(self, index_func): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors index = index_func(5) - s = gen_obj(klass, index) + for s in [ + Series(range(5), index=index), + DataFrame(np.random.randn(5, 2), index=index), + ]: - # getitem - msg = ( - "cannot do positional indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] + # getitem + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - msg = ( - "cannot do (slice|positional) indexing " - fr"on {type(index).__name__} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)" - ) - with pytest.raises(TypeError, match=msg): - s.loc[l] - with pytest.raises(TypeError, match=msg): - s.iloc[l] - with pytest.raises(TypeError, match=msg): - s[l] + msg = ( + "cannot do positional indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] - # setitem - msg = ( - "cannot do positional indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] = 0 + for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: - msg = ( - "cannot do (slice|positional) indexing " - fr"on {type(index).__name__} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)" - ) - with pytest.raises(TypeError, match=msg): - s.loc[l] = 0 - with pytest.raises(TypeError, match=msg): - s.iloc[l] = 0 - with pytest.raises(TypeError, match=msg): - s[l] = 0 + msg = ( + "cannot do (slice|positional) indexing " + fr"on {type(index).__name__} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)" + ) + with pytest.raises(TypeError, match=msg): + idxr(s)[l] + + # setitem + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + + msg = ( + "cannot do positional indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] = 0 + + for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: + msg = ( + "cannot do (slice|positional) indexing " + fr"on {type(index).__name__} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)" + ) + with pytest.raises(TypeError, match=msg): + idxr(s)[l] = 0 def test_slice_integer(self): @@ -423,16 +409,18 @@ def test_slice_integer(self): # getitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - result = s.loc[l] + for idxr in [lambda x: x.loc]: - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(3, 5) - self.check(result, s, indexer, False) + result = idxr(s)[l] + + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(3, 5) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -446,16 +434,17 @@ def test_slice_integer(self): # getitem out-of-bounds for l in [slice(-6, 6), slice(-6.0, 6.0)]: - result = s.loc[l] + for idxr in [lambda x: x.loc]: + result = idxr(s)[l] - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(-6, 6) - self.check(result, s, indexer, False) + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(-6, 6) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -473,13 +462,15 @@ def test_slice_integer(self): (slice(2.5, 3.5), slice(3, 4)), ]: - result = s.loc[l] - if oob: - res = slice(0, 0) - else: - res = res1 + for idxr in [lambda x: x.loc]: - self.check(result, s, res, False) + result = idxr(s)[l] + if oob: + res = slice(0, 0) + else: + res = res1 + + self.check(result, s, res, False) # positional indexing msg = ( @@ -493,10 +484,11 @@ def test_slice_integer(self): # setitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - sc = s.copy() - sc.loc[l] = 0 - result = sc.loc[l].values.ravel() - assert (result == 0).all() + for idxr in [lambda x: x.loc]: + sc = s.copy() + idxr(sc)[l] = 0 + result = idxr(sc)[l].values.ravel() + assert (result == 0).all() # positional indexing msg = ( @@ -507,8 +499,7 @@ def test_slice_integer(self): with pytest.raises(TypeError, match=msg): s[l] = 0 - @pytest.mark.parametrize("l", [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]) - def test_integer_positional_indexing(self, l): + def test_integer_positional_indexing(self): """ make sure that we are raising on positional indexing w.r.t. an integer index """ @@ -518,16 +509,18 @@ def test_integer_positional_indexing(self, l): expected = s.iloc[2:4] tm.assert_series_equal(result, expected) - klass = RangeIndex - msg = ( - "cannot do (slice|positional) indexing " - fr"on {klass.__name__} with these indexers \[(2|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] - with pytest.raises(TypeError, match=msg): - s.iloc[l] + for idxr in [lambda x: x, lambda x: x.iloc]: + + for l in [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]: + + klass = RangeIndex + msg = ( + "cannot do (slice|positional) indexing " + fr"on {klass.__name__} with these indexers \[(2|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + idxr(s)[l] @pytest.mark.parametrize( "index_func", [tm.makeIntIndex, tm.makeRangeIndex], @@ -539,94 +532,102 @@ def test_slice_integer_frame_getitem(self, index_func): s = DataFrame(np.random.randn(5, 2), index=index) - # getitem - for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - - result = s.loc[l] - indexer = slice(0, 2) - self.check(result, s, indexer, False) + def f(idxr): - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[(0|1)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] - - # getitem out-of-bounds - for l in [slice(-10, 10), slice(-10.0, 10.0)]: + # getitem + for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - result = s.loc[l] - self.check(result, s, slice(-10, 10), True) + result = idxr(s)[l] + indexer = slice(0, 2) + self.check(result, s, indexer, False) - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[-10\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[slice(-10.0, 10.0)] + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[(0|1)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] - # getitem odd floats - for l, res in [ - (slice(0.5, 1), slice(1, 2)), - (slice(0, 0.5), slice(0, 1)), - (slice(0.5, 1.5), slice(1, 2)), - ]: + # getitem out-of-bounds + for l in [slice(-10, 10), slice(-10.0, 10.0)]: - result = s.loc[l] - self.check(result, s, res, False) + result = idxr(s)[l] + self.check(result, s, slice(-10, 10), True) # positional indexing msg = ( "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[0\.5\] of " + fr"on {type(index).__name__} with these indexers \[-10\.0\] of " "type float" ) with pytest.raises(TypeError, match=msg): - s[l] + s[slice(-10.0, 10.0)] - # setitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + # getitem odd floats + for l, res in [ + (slice(0.5, 1), slice(1, 2)), + (slice(0, 0.5), slice(0, 1)), + (slice(0.5, 1.5), slice(1, 2)), + ]: - sc = s.copy() - sc.loc[l] = 0 - result = sc.loc[l].values.ravel() - assert (result == 0).all() + result = idxr(s)[l] + self.check(result, s, res, False) - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] = 0 + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[0\.5\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] - @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) - @pytest.mark.parametrize("klass", [Series, DataFrame]) - def test_slice_float(self, l, klass): + # setitem + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + + sc = s.copy() + idxr(sc)[l] = 0 + result = idxr(sc)[l].values.ravel() + assert (result == 0).all() + + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] = 0 + + f(lambda x: x.loc) + + def test_slice_float(self): # same as above, but for floats index = Index(np.arange(5.0)) + 0.1 - s = gen_obj(klass, index) - - expected = s.iloc[3:4] - for idxr in [lambda x: x.loc, lambda x: x]: + for s in [ + Series(range(5), index=index), + DataFrame(np.random.randn(5, 2), index=index), + ]: - # getitem - result = idxr(s)[l] - assert isinstance(result, type(s)) - tm.assert_equal(result, expected) + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - # setitem - s2 = s.copy() - idxr(s2)[l] = 0 - result = idxr(s2)[l].values.ravel() - assert (result == 0).all() + expected = s.iloc[3:4] + for idxr in [lambda x: x.loc, lambda x: x]: + + # getitem + result = idxr(s)[l] + if isinstance(s, Series): + tm.assert_series_equal(result, expected) + else: + tm.assert_frame_equal(result, expected) + # setitem + s2 = s.copy() + idxr(s2)[l] = 0 + result = idxr(s2)[l].values.ravel() + assert (result == 0).all() def test_floating_index_doc_example(self): From 751d8dd04f9974beb36c1398e88d936253968c3f Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 13 Feb 2020 18:54:47 -0800 Subject: [PATCH 6/6] redo --- pandas/tests/indexing/test_floats.py | 577 +++++++++++++-------------- 1 file changed, 286 insertions(+), 291 deletions(-) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 80a4d81b20a13..7c4fe286f4416 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -5,6 +5,16 @@ import pandas._testing as tm +def gen_obj(klass, index): + if klass is Series: + obj = Series(np.arange(len(index)), index=index) + else: + obj = DataFrame( + np.random.randn(len(index), len(index)), index=index, columns=index + ) + return obj + + class TestFloatIndexers: def check(self, result, original, indexer, getitem): """ @@ -70,97 +80,107 @@ def test_scalar_error(self, index_func): tm.makePeriodIndex, ], ) - def test_scalar_non_numeric(self, index_func): + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_scalar_non_numeric(self, index_func, klass): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors i = index_func(5) + s = gen_obj(klass, i) - for s in [ - Series(np.arange(len(i)), index=i), - DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i), - ]: - - # getting - for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: + # getting + for idxr, getitem in [(lambda x: x.iloc, False), (lambda x: x, True)]: - # gettitem on a DataFrame is a KeyError as it is indexing - # via labels on the columns - if getitem and isinstance(s, DataFrame): - error = KeyError - msg = r"^3(\.0)?$" - else: - error = TypeError - msg = ( - r"cannot do (label|positional) indexing " - fr"on {type(i).__name__} with these indexers \[3\.0\] of " - r"type float|" - "Cannot index by location index with a " - "non-integer key" - ) - with pytest.raises(error, match=msg): - idxr(s)[3.0] - - # label based can be a TypeError or KeyError - if s.index.inferred_type in { - "categorical", - "string", - "unicode", - "mixed", - }: + # gettitem on a DataFrame is a KeyError as it is indexing + # via labels on the columns + if getitem and isinstance(s, DataFrame): error = KeyError - msg = r"^3\.0$" + msg = r"^3(\.0)?$" else: error = TypeError msg = ( r"cannot do (label|positional) indexing " fr"on {type(i).__name__} with these indexers \[3\.0\] of " - "type float" + r"type float|" + "Cannot index by location index with a " + "non-integer key" ) with pytest.raises(error, match=msg): - s.loc[3.0] - - # contains - assert 3.0 not in s - - # setting with a float fails with iloc + idxr(s)[3.0] + + # label based can be a TypeError or KeyError + if s.index.inferred_type in { + "categorical", + "string", + "unicode", + "mixed", + }: + error = KeyError + msg = r"^3\.0$" + else: + error = TypeError msg = ( r"cannot do (label|positional) indexing " fr"on {type(i).__name__} with these indexers \[3\.0\] of " "type float" ) - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] = 0 - - # setting with an indexer - if s.index.inferred_type in ["categorical"]: - # Value or Type Error - pass - elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: - - # these should prob work - # and are inconsistent between series/dataframe ATM - # for idxr in [lambda x: x]: - # s2 = s.copy() - # - # with pytest.raises(TypeError): - # idxr(s2)[3.0] = 0 - pass + with pytest.raises(error, match=msg): + s.loc[3.0] - else: + # contains + assert 3.0 not in s + + # setting with a float fails with iloc + msg = ( + r"cannot do (label|positional) indexing " + fr"on {type(i).__name__} with these indexers \[3\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] = 0 + + # setting with an indexer + if s.index.inferred_type in ["categorical"]: + # Value or Type Error + pass + elif s.index.inferred_type in ["datetime64", "timedelta64", "period"]: + + # these should prob work + # and are inconsistent between series/dataframe ATM + # for idxr in [lambda x: x]: + # s2 = s.copy() + # + # with pytest.raises(TypeError): + # idxr(s2)[3.0] = 0 + pass + else: + + s2 = s.copy() + s2.loc[3.0] = 10 + assert s2.index.is_object() + + for idxr in [lambda x: x]: s2 = s.copy() - s2.loc[3.0] = 10 + idxr(s2)[3.0] = 0 assert s2.index.is_object() - for idxr in [lambda x: x]: - s2 = s.copy() - idxr(s2)[3.0] = 0 - assert s2.index.is_object() - + @pytest.mark.parametrize( + "index_func", + [ + tm.makeStringIndex, + tm.makeUnicodeIndex, + tm.makeCategoricalIndex, + tm.makeDateIndex, + tm.makeTimedeltaIndex, + tm.makePeriodIndex, + ], + ) + def test_scalar_non_numeric_series_fallback(self, index_func): # fallsback to position selection, series only + i = index_func(5) s = Series(np.arange(len(i)), index=i) s[3] msg = ( @@ -178,16 +198,16 @@ def test_scalar_with_mixed(self): # lookup in a pure stringstr # with an invalid indexer - for idxr in [lambda x: x, lambda x: x.iloc]: - - msg = ( - "cannot do label indexing " - fr"on {Index.__name__} with these indexers \[1\.0\] of " - r"type float|" - "Cannot index by location index with a non-integer key" - ) - with pytest.raises(TypeError, match=msg): - idxr(s2)[1.0] + msg = ( + "cannot do label indexing " + fr"on {Index.__name__} with these indexers \[1\.0\] of " + r"type float|" + "Cannot index by location index with a non-integer key" + ) + with pytest.raises(TypeError, match=msg): + s2[1.0] + with pytest.raises(TypeError, match=msg): + s2.iloc[1.0] with pytest.raises(KeyError, match=r"^1\.0$"): s2.loc[1.0] @@ -198,19 +218,17 @@ def test_scalar_with_mixed(self): # mixed index so we have label # indexing - for idxr in [lambda x: x]: - - msg = ( - "cannot do label indexing " - fr"on {Index.__name__} with these indexers \[1\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - idxr(s3)[1.0] + msg = ( + "cannot do label indexing " + fr"on {Index.__name__} with these indexers \[1\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s3[1.0] - result = idxr(s3)[1] - expected = 2 - assert result == expected + result = s3[1] + expected = 2 + assert result == expected msg = "Cannot index by location index with a non-integer key" with pytest.raises(TypeError, match=msg): @@ -234,6 +252,7 @@ def test_scalar_integer(self, index_func, klass): i = index_func(5) if klass is Series: + # TODO: Should we be passing index=i here? obj = Series(np.arange(len(i))) else: obj = DataFrame(np.random.randn(len(i), len(i)), index=i, columns=i) @@ -273,58 +292,54 @@ def compare(x, y): # coerce to equal int assert 3.0 in obj - def test_scalar_float(self): + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_scalar_float(self, klass): # scalar float indexers work on a float index index = Index(np.arange(5.0)) - for s in [ - Series(np.arange(len(index)), index=index), - DataFrame( - np.random.randn(len(index), len(index)), index=index, columns=index - ), - ]: + s = gen_obj(klass, index) - # assert all operations except for iloc are ok - indexer = index[3] - for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: + # assert all operations except for iloc are ok + indexer = index[3] + for idxr, getitem in [(lambda x: x.loc, False), (lambda x: x, True)]: - # getting - result = idxr(s)[indexer] - self.check(result, s, 3, getitem) + # getting + result = idxr(s)[indexer] + self.check(result, s, 3, getitem) - # setting - s2 = s.copy() + # setting + s2 = s.copy() - result = idxr(s2)[indexer] - self.check(result, s, 3, getitem) + result = idxr(s2)[indexer] + self.check(result, s, 3, getitem) - # random integer is a KeyError - with pytest.raises(KeyError, match=r"^3\.5$"): - idxr(s)[3.5] + # random integer is a KeyError + with pytest.raises(KeyError, match=r"^3\.5$"): + idxr(s)[3.5] - # contains - assert 3.0 in s + # contains + assert 3.0 in s - # iloc succeeds with an integer - expected = s.iloc[3] - s2 = s.copy() + # iloc succeeds with an integer + expected = s.iloc[3] + s2 = s.copy() - s2.iloc[3] = expected - result = s2.iloc[3] - self.check(result, s, 3, False) + s2.iloc[3] = expected + result = s2.iloc[3] + self.check(result, s, 3, False) - # iloc raises with a float - msg = "Cannot index by location index with a non-integer key" - with pytest.raises(TypeError, match=msg): - s.iloc[3.0] + # iloc raises with a float + msg = "Cannot index by location index with a non-integer key" + with pytest.raises(TypeError, match=msg): + s.iloc[3.0] - msg = ( - "cannot do positional indexing " - fr"on {Float64Index.__name__} with these indexers \[3\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s2.iloc[3.0] = 0 + msg = ( + "cannot do positional indexing " + fr"on {Float64Index.__name__} with these indexers \[3\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s2.iloc[3.0] = 0 @pytest.mark.parametrize( "index_func", @@ -336,60 +351,54 @@ def test_scalar_float(self): tm.makePeriodIndex, ], ) - def test_slice_non_numeric(self, index_func): + @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_slice_non_numeric(self, index_func, l, klass): # GH 4892 # float_indexers should raise exceptions # on appropriate Index types & accessors index = index_func(5) - for s in [ - Series(range(5), index=index), - DataFrame(np.random.randn(5, 2), index=index), - ]: - - # getitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - - msg = ( - "cannot do positional indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] + s = gen_obj(klass, index) - for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: + # getitem + msg = ( + "cannot do positional indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] - msg = ( - "cannot do (slice|positional) indexing " - fr"on {type(index).__name__} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)" - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] + msg = ( + "cannot do (slice|positional) indexing " + fr"on {type(index).__name__} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)" + ) + for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: + with pytest.raises(TypeError, match=msg): + idxr(s)[l] - # setitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + # setitem + msg = ( + "cannot do positional indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s.iloc[l] = 0 - msg = ( - "cannot do positional indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s.iloc[l] = 0 - - for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: - msg = ( - "cannot do (slice|positional) indexing " - fr"on {type(index).__name__} with these indexers " - r"\[(3|4)(\.0)?\] " - r"of type (float|int)" - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] = 0 + msg = ( + "cannot do (slice|positional) indexing " + fr"on {type(index).__name__} with these indexers " + r"\[(3|4)(\.0)?\] " + r"of type (float|int)" + ) + for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: + with pytest.raises(TypeError, match=msg): + idxr(s)[l] = 0 def test_slice_integer(self): @@ -409,18 +418,16 @@ def test_slice_integer(self): # getitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - for idxr in [lambda x: x.loc]: - - result = idxr(s)[l] + result = s.loc[l] - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(3, 5) - self.check(result, s, indexer, False) + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(3, 5) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -434,17 +441,16 @@ def test_slice_integer(self): # getitem out-of-bounds for l in [slice(-6, 6), slice(-6.0, 6.0)]: - for idxr in [lambda x: x.loc]: - result = idxr(s)[l] + result = s.loc[l] - # these are all label indexing - # except getitem which is positional - # empty - if oob: - indexer = slice(0, 0) - else: - indexer = slice(-6, 6) - self.check(result, s, indexer, False) + # these are all label indexing + # except getitem which is positional + # empty + if oob: + indexer = slice(0, 0) + else: + indexer = slice(-6, 6) + self.check(result, s, indexer, False) # positional indexing msg = ( @@ -462,15 +468,13 @@ def test_slice_integer(self): (slice(2.5, 3.5), slice(3, 4)), ]: - for idxr in [lambda x: x.loc]: - - result = idxr(s)[l] - if oob: - res = slice(0, 0) - else: - res = res1 + result = s.loc[l] + if oob: + res = slice(0, 0) + else: + res = res1 - self.check(result, s, res, False) + self.check(result, s, res, False) # positional indexing msg = ( @@ -484,11 +488,10 @@ def test_slice_integer(self): # setitem for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: - for idxr in [lambda x: x.loc]: - sc = s.copy() - idxr(sc)[l] = 0 - result = idxr(sc)[l].values.ravel() - assert (result == 0).all() + sc = s.copy() + sc.loc[l] = 0 + result = sc.loc[l].values.ravel() + assert (result == 0).all() # positional indexing msg = ( @@ -499,7 +502,8 @@ def test_slice_integer(self): with pytest.raises(TypeError, match=msg): s[l] = 0 - def test_integer_positional_indexing(self): + @pytest.mark.parametrize("l", [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]) + def test_integer_positional_indexing(self, l): """ make sure that we are raising on positional indexing w.r.t. an integer index """ @@ -509,18 +513,16 @@ def test_integer_positional_indexing(self): expected = s.iloc[2:4] tm.assert_series_equal(result, expected) - for idxr in [lambda x: x, lambda x: x.iloc]: - - for l in [slice(2, 4.0), slice(2.0, 4), slice(2.0, 4.0)]: - - klass = RangeIndex - msg = ( - "cannot do (slice|positional) indexing " - fr"on {klass.__name__} with these indexers \[(2|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - idxr(s)[l] + klass = RangeIndex + msg = ( + "cannot do (slice|positional) indexing " + fr"on {klass.__name__} with these indexers \[(2|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] + with pytest.raises(TypeError, match=msg): + s.iloc[l] @pytest.mark.parametrize( "index_func", [tm.makeIntIndex, tm.makeRangeIndex], @@ -532,102 +534,95 @@ def test_slice_integer_frame_getitem(self, index_func): s = DataFrame(np.random.randn(5, 2), index=index) - def f(idxr): - - # getitem - for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - - result = idxr(s)[l] - indexer = slice(0, 2) - self.check(result, s, indexer, False) - - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[(0|1)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] - - # getitem out-of-bounds - for l in [slice(-10, 10), slice(-10.0, 10.0)]: + # getitem + for l in [slice(0.0, 1), slice(0, 1.0), slice(0.0, 1.0)]: - result = idxr(s)[l] - self.check(result, s, slice(-10, 10), True) + result = s.loc[l] + indexer = slice(0, 2) + self.check(result, s, indexer, False) # positional indexing msg = ( "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[-10\.0\] of " + fr"on {type(index).__name__} with these indexers \[(0|1)\.0\] of " "type float" ) with pytest.raises(TypeError, match=msg): - s[slice(-10.0, 10.0)] + s[l] - # getitem odd floats - for l, res in [ - (slice(0.5, 1), slice(1, 2)), - (slice(0, 0.5), slice(0, 1)), - (slice(0.5, 1.5), slice(1, 2)), - ]: + # getitem out-of-bounds + for l in [slice(-10, 10), slice(-10.0, 10.0)]: - result = idxr(s)[l] - self.check(result, s, res, False) + result = s.loc[l] + self.check(result, s, slice(-10, 10), True) - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[0\.5\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[-10\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[slice(-10.0, 10.0)] - # setitem - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + # getitem odd floats + for l, res in [ + (slice(0.5, 1), slice(1, 2)), + (slice(0, 0.5), slice(0, 1)), + (slice(0.5, 1.5), slice(1, 2)), + ]: - sc = s.copy() - idxr(sc)[l] = 0 - result = idxr(sc)[l].values.ravel() - assert (result == 0).all() + result = s.loc[l] + self.check(result, s, res, False) - # positional indexing - msg = ( - "cannot do slice indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): - s[l] = 0 + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[0\.5\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] - f(lambda x: x.loc) + # setitem + for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + + sc = s.copy() + sc.loc[l] = 0 + result = sc.loc[l].values.ravel() + assert (result == 0).all() + + # positional indexing + msg = ( + "cannot do slice indexing " + fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " + "type float" + ) + with pytest.raises(TypeError, match=msg): + s[l] = 0 - def test_slice_float(self): + @pytest.mark.parametrize("l", [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]) + @pytest.mark.parametrize("klass", [Series, DataFrame]) + def test_slice_float(self, l, klass): # same as above, but for floats index = Index(np.arange(5.0)) + 0.1 - for s in [ - Series(range(5), index=index), - DataFrame(np.random.randn(5, 2), index=index), - ]: + s = gen_obj(klass, index) - for l in [slice(3.0, 4), slice(3, 4.0), slice(3.0, 4.0)]: + expected = s.iloc[3:4] + for idxr in [lambda x: x.loc, lambda x: x]: - expected = s.iloc[3:4] - for idxr in [lambda x: x.loc, lambda x: x]: - - # getitem - result = idxr(s)[l] - if isinstance(s, Series): - tm.assert_series_equal(result, expected) - else: - tm.assert_frame_equal(result, expected) - # setitem - s2 = s.copy() - idxr(s2)[l] = 0 - result = idxr(s2)[l].values.ravel() - assert (result == 0).all() + # getitem + result = idxr(s)[l] + if isinstance(s, Series): + tm.assert_series_equal(result, expected) + else: + tm.assert_frame_equal(result, expected) + # setitem + s2 = s.copy() + idxr(s2)[l] = 0 + result = idxr(s2)[l].values.ravel() + assert (result == 0).all() def test_floating_index_doc_example(self):