From 6a24ca6af6e97c2a13cb8d8e92e6aa0f04bc851a Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 11:49:24 -0700 Subject: [PATCH 1/6] REF RangeIndex indexing tests --- pandas/tests/indexes/ranges/test_indexing.py | 79 ++++++++++++++++++++ pandas/tests/indexes/ranges/test_range.py | 69 ----------------- 2 files changed, 79 insertions(+), 69 deletions(-) create mode 100644 pandas/tests/indexes/ranges/test_indexing.py diff --git a/pandas/tests/indexes/ranges/test_indexing.py b/pandas/tests/indexes/ranges/test_indexing.py new file mode 100644 index 0000000000000..238c33c3db6d7 --- /dev/null +++ b/pandas/tests/indexes/ranges/test_indexing.py @@ -0,0 +1,79 @@ +import numpy as np +import pytest + +import pandas as pd +from pandas import RangeIndex +import pandas._testing as tm + + +class TestGetIndexer: + def test_get_indexer(self): + index = RangeIndex(start=0, stop=20, step=2) + target = RangeIndex(10) + indexer = index.get_indexer(target) + expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp) + tm.assert_numpy_array_equal(indexer, expected) + + def test_get_indexer_pad(self): + index = RangeIndex(start=0, stop=20, step=2) + target = RangeIndex(10) + indexer = index.get_indexer(target, method="pad") + expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp) + tm.assert_numpy_array_equal(indexer, expected) + + def test_get_indexer_backfill(self): + index = RangeIndex(start=0, stop=20, step=2) + target = RangeIndex(10) + indexer = index.get_indexer(target, method="backfill") + expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp) + tm.assert_numpy_array_equal(indexer, expected) + + def test_get_indexer_limit(self): + # GH#28631 + idx = RangeIndex(4) + target = RangeIndex(6) + result = idx.get_indexer(target, method="pad", limit=1) + expected = np.array([0, 1, 2, 3, 3, -1], dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) + + @pytest.mark.parametrize("stop", [0, -1, -2]) + def test_get_indexer_decreasing(self, stop): + # GH#28678 + index = RangeIndex(7, stop, -3) + result = index.get_indexer(range(9)) + expected = np.array([-1, 2, -1, -1, 1, -1, -1, 0, -1], dtype=np.intp) + tm.assert_numpy_array_equal(result, expected) + + +class TestTake: + def test_take_preserve_name(self): + index = RangeIndex(1, 5, name="foo") + taken = index.take([3, 0, 1]) + assert index.name == taken.name + + def test_take_fill_value(self): + # GH#12631 + idx = pd.RangeIndex(1, 4, name="xxx") + result = idx.take(np.array([1, 0, -1])) + expected = pd.Int64Index([2, 1, 3], name="xxx") + tm.assert_index_equal(result, expected) + + # fill_value + msg = "Unable to fill values because RangeIndex cannot contain NA" + with pytest.raises(ValueError, match=msg): + idx.take(np.array([1, 0, -1]), fill_value=True) + + # allow_fill=False + result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True) + expected = pd.Int64Index([2, 1, 3], name="xxx") + tm.assert_index_equal(result, expected) + + msg = "Unable to fill values because RangeIndex cannot contain NA" + with pytest.raises(ValueError, match=msg): + idx.take(np.array([1, 0, -2]), fill_value=True) + with pytest.raises(ValueError, match=msg): + idx.take(np.array([1, 0, -5]), fill_value=True) + + msg = "index -5 is out of bounds for (axis 0 with )?size 3" + with pytest.raises(IndexError, match=msg): + idx.take(np.array([1, -5])) diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py index df5b3daa32e9f..05422e7b4419f 100644 --- a/pandas/tests/indexes/ranges/test_range.py +++ b/pandas/tests/indexes/ranges/test_range.py @@ -257,43 +257,6 @@ def test_identical(self): assert not index.copy(dtype=object).identical(index.copy(dtype="int64")) - def test_get_indexer(self): - index = self.create_index() - target = RangeIndex(10) - indexer = index.get_indexer(target) - expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp) - tm.assert_numpy_array_equal(indexer, expected) - - def test_get_indexer_pad(self): - index = self.create_index() - target = RangeIndex(10) - indexer = index.get_indexer(target, method="pad") - expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp) - tm.assert_numpy_array_equal(indexer, expected) - - def test_get_indexer_backfill(self): - index = self.create_index() - target = RangeIndex(10) - indexer = index.get_indexer(target, method="backfill") - expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp) - tm.assert_numpy_array_equal(indexer, expected) - - def test_get_indexer_limit(self): - # GH 28631 - idx = RangeIndex(4) - target = RangeIndex(6) - result = idx.get_indexer(target, method="pad", limit=1) - expected = np.array([0, 1, 2, 3, 3, -1], dtype=np.intp) - tm.assert_numpy_array_equal(result, expected) - - @pytest.mark.parametrize("stop", [0, -1, -2]) - def test_get_indexer_decreasing(self, stop): - # GH 28678 - index = RangeIndex(7, stop, -3) - result = index.get_indexer(range(9)) - expected = np.array([-1, 2, -1, -1, 1, -1, -1, 0, -1], dtype=np.intp) - tm.assert_numpy_array_equal(result, expected) - def test_nbytes(self): # memory savings vs int index @@ -327,38 +290,6 @@ def test_prevent_casting(self): result = index.astype("O") assert result.dtype == np.object_ - def test_take_preserve_name(self): - index = RangeIndex(1, 5, name="foo") - taken = index.take([3, 0, 1]) - assert index.name == taken.name - - def test_take_fill_value(self): - # GH 12631 - idx = pd.RangeIndex(1, 4, name="xxx") - result = idx.take(np.array([1, 0, -1])) - expected = pd.Int64Index([2, 1, 3], name="xxx") - tm.assert_index_equal(result, expected) - - # fill_value - msg = "Unable to fill values because RangeIndex cannot contain NA" - with pytest.raises(ValueError, match=msg): - idx.take(np.array([1, 0, -1]), fill_value=True) - - # allow_fill=False - result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True) - expected = pd.Int64Index([2, 1, 3], name="xxx") - tm.assert_index_equal(result, expected) - - msg = "Unable to fill values because RangeIndex cannot contain NA" - with pytest.raises(ValueError, match=msg): - idx.take(np.array([1, 0, -2]), fill_value=True) - with pytest.raises(ValueError, match=msg): - idx.take(np.array([1, 0, -5]), fill_value=True) - - msg = "index -5 is out of bounds for (axis 0 with )?size 3" - with pytest.raises(IndexError, match=msg): - idx.take(np.array([1, -5])) - def test_repr_roundtrip(self): index = self.create_index() tm.assert_index_equal(eval(repr(index)), index) From a493640d9ba3e0cfa72ff49c157d83220b884745 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 11:53:59 -0700 Subject: [PATCH 2/6] REF: MultiIndex arithmetic/indexing tests --- pandas/tests/indexes/multi/test_analytics.py | 34 ------------- pandas/tests/indexes/multi/test_arithmetic.py | 43 ++++++++++++++++ pandas/tests/indexes/multi/test_compat.py | 22 --------- pandas/tests/indexes/multi/test_contains.py | 35 ------------- pandas/tests/indexes/multi/test_indexing.py | 49 +++++++++++++++++++ 5 files changed, 92 insertions(+), 91 deletions(-) create mode 100644 pandas/tests/indexes/multi/test_arithmetic.py diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py index a9e02934f27ab..a4f8847ce7b51 100644 --- a/pandas/tests/indexes/multi/test_analytics.py +++ b/pandas/tests/indexes/multi/test_analytics.py @@ -57,23 +57,6 @@ def test_truncate(): index.truncate(3, 1) -def test_where(): - i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) - - msg = r"\.where is not supported for MultiIndex operations" - with pytest.raises(NotImplementedError, match=msg): - i.where(True) - - -@pytest.mark.parametrize("klass", [list, tuple, np.array, pd.Series]) -def test_where_array_like(klass): - i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) - cond = [False, True] - msg = r"\.where is not supported for MultiIndex operations" - with pytest.raises(NotImplementedError, match=msg): - i.where(klass(cond)) - - # TODO: reshape @@ -159,23 +142,6 @@ def test_iter(idx): assert result == expected -def test_sub(idx): - - first = idx - - # - now raises (previously was set op difference) - msg = "cannot perform __sub__ with this index type: MultiIndex" - with pytest.raises(TypeError, match=msg): - first - idx[-3:] - with pytest.raises(TypeError, match=msg): - idx[-3:] - first - with pytest.raises(TypeError, match=msg): - idx[-3:] - first.tolist() - msg = "cannot perform __rsub__ with this index type: MultiIndex" - with pytest.raises(TypeError, match=msg): - first.tolist() - idx[-3:] - - def test_map(idx): # callable index = idx diff --git a/pandas/tests/indexes/multi/test_arithmetic.py b/pandas/tests/indexes/multi/test_arithmetic.py new file mode 100644 index 0000000000000..4c4ef4adfa6ec --- /dev/null +++ b/pandas/tests/indexes/multi/test_arithmetic.py @@ -0,0 +1,43 @@ +""" +Tests for arithmetic being disabled on MultiIndex. +""" +import pytest + + +def test_sub(idx): + + first = idx + + # - now raises (previously was set op difference) + msg = "cannot perform __sub__ with this index type: MultiIndex" + with pytest.raises(TypeError, match=msg): + first - idx[-3:] + with pytest.raises(TypeError, match=msg): + idx[-3:] - first + with pytest.raises(TypeError, match=msg): + idx[-3:] - first.tolist() + msg = "cannot perform __rsub__ with this index type: MultiIndex" + with pytest.raises(TypeError, match=msg): + first.tolist() - idx[-3:] + + +def test_numeric_compat(idx): + with pytest.raises(TypeError, match="cannot perform __mul__"): + idx * 1 + + with pytest.raises(TypeError, match="cannot perform __rmul__"): + 1 * idx + + div_err = "cannot perform __truediv__" + with pytest.raises(TypeError, match=div_err): + idx / 1 + + div_err = div_err.replace(" __", " __r") + with pytest.raises(TypeError, match=div_err): + 1 / idx + + with pytest.raises(TypeError, match="cannot perform __floordiv__"): + idx // 1 + + with pytest.raises(TypeError, match="cannot perform __rfloordiv__"): + 1 // idx diff --git a/pandas/tests/indexes/multi/test_compat.py b/pandas/tests/indexes/multi/test_compat.py index 9273de9c20412..cd2671206505f 100644 --- a/pandas/tests/indexes/multi/test_compat.py +++ b/pandas/tests/indexes/multi/test_compat.py @@ -5,28 +5,6 @@ import pandas._testing as tm -def test_numeric_compat(idx): - with pytest.raises(TypeError, match="cannot perform __mul__"): - idx * 1 - - with pytest.raises(TypeError, match="cannot perform __rmul__"): - 1 * idx - - div_err = "cannot perform __truediv__" - with pytest.raises(TypeError, match=div_err): - idx / 1 - - div_err = div_err.replace(" __", " __r") - with pytest.raises(TypeError, match=div_err): - 1 / idx - - with pytest.raises(TypeError, match="cannot perform __floordiv__"): - idx // 1 - - with pytest.raises(TypeError, match="cannot perform __rfloordiv__"): - 1 // idx - - @pytest.mark.parametrize("method", ["all", "any"]) def test_logical_compat(idx, method): msg = f"cannot perform {method}" diff --git a/pandas/tests/indexes/multi/test_contains.py b/pandas/tests/indexes/multi/test_contains.py index 49aa63210cd5e..122263e6ec198 100644 --- a/pandas/tests/indexes/multi/test_contains.py +++ b/pandas/tests/indexes/multi/test_contains.py @@ -3,35 +3,10 @@ from pandas.compat import PYPY -import pandas as pd from pandas import MultiIndex import pandas._testing as tm -def test_contains_top_level(): - midx = MultiIndex.from_product([["A", "B"], [1, 2]]) - assert "A" in midx - assert "A" not in midx._engine - - -def test_contains_with_nat(): - # MI with a NaT - mi = MultiIndex( - levels=[["C"], pd.date_range("2012-01-01", periods=5)], - codes=[[0, 0, 0, 0, 0, 0], [-1, 0, 1, 2, 3, 4]], - names=[None, "B"], - ) - assert ("C", pd.Timestamp("2012-01-01")) in mi - for val in mi.values: - assert val in mi - - -def test_contains(idx): - assert ("foo", "two") in idx - assert ("bar", "two") not in idx - assert None not in idx - - @pytest.mark.skipif(not PYPY, reason="tuples cmp recursively on PyPy") def test_isin_nan_pypy(): idx = MultiIndex.from_arrays([["foo", "bar"], [1.0, np.nan]]) @@ -100,16 +75,6 @@ def test_isin_level_kwarg(): idx.isin(vals_1, level="C") -def test_contains_with_missing_value(): - # issue 19132 - idx = MultiIndex.from_arrays([[1, np.nan, 2]]) - assert np.nan in idx - - idx = MultiIndex.from_arrays([[1, 2], [np.nan, 3]]) - assert np.nan not in idx - assert (1, np.nan) in idx - - @pytest.mark.parametrize( "labels,expected,level", [ diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py index b7d7b3b459aff..9ec37ae366f4f 100644 --- a/pandas/tests/indexes/multi/test_indexing.py +++ b/pandas/tests/indexes/multi/test_indexing.py @@ -240,6 +240,55 @@ def test_get_indexer_with_missing_value(self, index_arr, labels, expected): tm.assert_numpy_array_equal(result, expected) +class TestWhere: + def test_where(self): + i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) + + msg = r"\.where is not supported for MultiIndex operations" + with pytest.raises(NotImplementedError, match=msg): + i.where(True) + + @pytest.mark.parametrize("klass", [list, tuple, np.array, pd.Series]) + def test_where_array_like(self, klass): + i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) + cond = [False, True] + msg = r"\.where is not supported for MultiIndex operations" + with pytest.raises(NotImplementedError, match=msg): + i.where(klass(cond)) + + +class TestContains: + def test_contains_top_level(self): + midx = MultiIndex.from_product([["A", "B"], [1, 2]]) + assert "A" in midx + assert "A" not in midx._engine + + def test_contains_with_nat(self): + # MI with a NaT + mi = MultiIndex( + levels=[["C"], pd.date_range("2012-01-01", periods=5)], + codes=[[0, 0, 0, 0, 0, 0], [-1, 0, 1, 2, 3, 4]], + names=[None, "B"], + ) + assert ("C", pd.Timestamp("2012-01-01")) in mi + for val in mi.values: + assert val in mi + + def test_contains(self, idx): + assert ("foo", "two") in idx + assert ("bar", "two") not in idx + assert None not in idx + + def test_contains_with_missing_value(self): + # GH#19132 + idx = MultiIndex.from_arrays([[1, np.nan, 2]]) + assert np.nan in idx + + idx = MultiIndex.from_arrays([[1, 2], [np.nan, 3]]) + assert np.nan not in idx + assert (1, np.nan) in idx + + def test_getitem(idx): # scalar assert idx[2] == ("bar", "one") From 650916a77f806ae997d5ed23fd8f4e868b14ffc3 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 11:54:18 -0700 Subject: [PATCH 3/6] rename test_contains->test_isin --- pandas/tests/indexes/multi/{test_contains.py => test_isin.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pandas/tests/indexes/multi/{test_contains.py => test_isin.py} (100%) diff --git a/pandas/tests/indexes/multi/test_contains.py b/pandas/tests/indexes/multi/test_isin.py similarity index 100% rename from pandas/tests/indexes/multi/test_contains.py rename to pandas/tests/indexes/multi/test_isin.py From 5aa23f4aeca97d8de6f99ed77b5378f2a16e89a6 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 12:02:17 -0700 Subject: [PATCH 4/6] revert --- pandas/tests/indexes/multi/test_analytics.py | 34 +++++ pandas/tests/indexes/multi/test_compat.py | 22 ++++ pandas/tests/indexes/multi/test_contains.py | 124 +++++++++++++++++++ pandas/tests/indexes/multi/test_indexing.py | 49 -------- 4 files changed, 180 insertions(+), 49 deletions(-) create mode 100644 pandas/tests/indexes/multi/test_contains.py diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py index a4f8847ce7b51..a9e02934f27ab 100644 --- a/pandas/tests/indexes/multi/test_analytics.py +++ b/pandas/tests/indexes/multi/test_analytics.py @@ -57,6 +57,23 @@ def test_truncate(): index.truncate(3, 1) +def test_where(): + i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) + + msg = r"\.where is not supported for MultiIndex operations" + with pytest.raises(NotImplementedError, match=msg): + i.where(True) + + +@pytest.mark.parametrize("klass", [list, tuple, np.array, pd.Series]) +def test_where_array_like(klass): + i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) + cond = [False, True] + msg = r"\.where is not supported for MultiIndex operations" + with pytest.raises(NotImplementedError, match=msg): + i.where(klass(cond)) + + # TODO: reshape @@ -142,6 +159,23 @@ def test_iter(idx): assert result == expected +def test_sub(idx): + + first = idx + + # - now raises (previously was set op difference) + msg = "cannot perform __sub__ with this index type: MultiIndex" + with pytest.raises(TypeError, match=msg): + first - idx[-3:] + with pytest.raises(TypeError, match=msg): + idx[-3:] - first + with pytest.raises(TypeError, match=msg): + idx[-3:] - first.tolist() + msg = "cannot perform __rsub__ with this index type: MultiIndex" + with pytest.raises(TypeError, match=msg): + first.tolist() - idx[-3:] + + def test_map(idx): # callable index = idx diff --git a/pandas/tests/indexes/multi/test_compat.py b/pandas/tests/indexes/multi/test_compat.py index cd2671206505f..9273de9c20412 100644 --- a/pandas/tests/indexes/multi/test_compat.py +++ b/pandas/tests/indexes/multi/test_compat.py @@ -5,6 +5,28 @@ import pandas._testing as tm +def test_numeric_compat(idx): + with pytest.raises(TypeError, match="cannot perform __mul__"): + idx * 1 + + with pytest.raises(TypeError, match="cannot perform __rmul__"): + 1 * idx + + div_err = "cannot perform __truediv__" + with pytest.raises(TypeError, match=div_err): + idx / 1 + + div_err = div_err.replace(" __", " __r") + with pytest.raises(TypeError, match=div_err): + 1 / idx + + with pytest.raises(TypeError, match="cannot perform __floordiv__"): + idx // 1 + + with pytest.raises(TypeError, match="cannot perform __rfloordiv__"): + 1 // idx + + @pytest.mark.parametrize("method", ["all", "any"]) def test_logical_compat(idx, method): msg = f"cannot perform {method}" diff --git a/pandas/tests/indexes/multi/test_contains.py b/pandas/tests/indexes/multi/test_contains.py new file mode 100644 index 0000000000000..49aa63210cd5e --- /dev/null +++ b/pandas/tests/indexes/multi/test_contains.py @@ -0,0 +1,124 @@ +import numpy as np +import pytest + +from pandas.compat import PYPY + +import pandas as pd +from pandas import MultiIndex +import pandas._testing as tm + + +def test_contains_top_level(): + midx = MultiIndex.from_product([["A", "B"], [1, 2]]) + assert "A" in midx + assert "A" not in midx._engine + + +def test_contains_with_nat(): + # MI with a NaT + mi = MultiIndex( + levels=[["C"], pd.date_range("2012-01-01", periods=5)], + codes=[[0, 0, 0, 0, 0, 0], [-1, 0, 1, 2, 3, 4]], + names=[None, "B"], + ) + assert ("C", pd.Timestamp("2012-01-01")) in mi + for val in mi.values: + assert val in mi + + +def test_contains(idx): + assert ("foo", "two") in idx + assert ("bar", "two") not in idx + assert None not in idx + + +@pytest.mark.skipif(not PYPY, reason="tuples cmp recursively on PyPy") +def test_isin_nan_pypy(): + idx = MultiIndex.from_arrays([["foo", "bar"], [1.0, np.nan]]) + tm.assert_numpy_array_equal(idx.isin([("bar", np.nan)]), np.array([False, True])) + tm.assert_numpy_array_equal( + idx.isin([("bar", float("nan"))]), np.array([False, True]) + ) + + +def test_isin(): + values = [("foo", 2), ("bar", 3), ("quux", 4)] + + idx = MultiIndex.from_arrays([["qux", "baz", "foo", "bar"], np.arange(4)]) + result = idx.isin(values) + expected = np.array([False, False, True, True]) + tm.assert_numpy_array_equal(result, expected) + + # empty, return dtype bool + idx = MultiIndex.from_arrays([[], []]) + result = idx.isin(values) + assert len(result) == 0 + assert result.dtype == np.bool_ + + +@pytest.mark.skipif(PYPY, reason="tuples cmp recursively on PyPy") +def test_isin_nan_not_pypy(): + idx = MultiIndex.from_arrays([["foo", "bar"], [1.0, np.nan]]) + tm.assert_numpy_array_equal(idx.isin([("bar", np.nan)]), np.array([False, False])) + tm.assert_numpy_array_equal( + idx.isin([("bar", float("nan"))]), np.array([False, False]) + ) + + +def test_isin_level_kwarg(): + idx = MultiIndex.from_arrays([["qux", "baz", "foo", "bar"], np.arange(4)]) + + vals_0 = ["foo", "bar", "quux"] + vals_1 = [2, 3, 10] + + expected = np.array([False, False, True, True]) + tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=0)) + tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=-2)) + + tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=1)) + tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=-1)) + + msg = "Too many levels: Index has only 2 levels, not 6" + with pytest.raises(IndexError, match=msg): + idx.isin(vals_0, level=5) + msg = "Too many levels: Index has only 2 levels, -5 is not a valid level number" + with pytest.raises(IndexError, match=msg): + idx.isin(vals_0, level=-5) + + with pytest.raises(KeyError, match=r"'Level 1\.0 not found'"): + idx.isin(vals_0, level=1.0) + with pytest.raises(KeyError, match=r"'Level -1\.0 not found'"): + idx.isin(vals_1, level=-1.0) + with pytest.raises(KeyError, match="'Level A not found'"): + idx.isin(vals_1, level="A") + + idx.names = ["A", "B"] + tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level="A")) + tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level="B")) + + with pytest.raises(KeyError, match="'Level C not found'"): + idx.isin(vals_1, level="C") + + +def test_contains_with_missing_value(): + # issue 19132 + idx = MultiIndex.from_arrays([[1, np.nan, 2]]) + assert np.nan in idx + + idx = MultiIndex.from_arrays([[1, 2], [np.nan, 3]]) + assert np.nan not in idx + assert (1, np.nan) in idx + + +@pytest.mark.parametrize( + "labels,expected,level", + [ + ([("b", np.nan)], np.array([False, False, True]), None,), + ([np.nan, "a"], np.array([True, True, False]), 0), + (["d", np.nan], np.array([False, True, True]), 1), + ], +) +def test_isin_multi_index_with_missing_value(labels, expected, level): + # GH 19132 + midx = MultiIndex.from_arrays([[np.nan, "a", "b"], ["c", "d", np.nan]]) + tm.assert_numpy_array_equal(midx.isin(labels, level=level), expected) diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py index 9ec37ae366f4f..b7d7b3b459aff 100644 --- a/pandas/tests/indexes/multi/test_indexing.py +++ b/pandas/tests/indexes/multi/test_indexing.py @@ -240,55 +240,6 @@ def test_get_indexer_with_missing_value(self, index_arr, labels, expected): tm.assert_numpy_array_equal(result, expected) -class TestWhere: - def test_where(self): - i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) - - msg = r"\.where is not supported for MultiIndex operations" - with pytest.raises(NotImplementedError, match=msg): - i.where(True) - - @pytest.mark.parametrize("klass", [list, tuple, np.array, pd.Series]) - def test_where_array_like(self, klass): - i = MultiIndex.from_tuples([("A", 1), ("A", 2)]) - cond = [False, True] - msg = r"\.where is not supported for MultiIndex operations" - with pytest.raises(NotImplementedError, match=msg): - i.where(klass(cond)) - - -class TestContains: - def test_contains_top_level(self): - midx = MultiIndex.from_product([["A", "B"], [1, 2]]) - assert "A" in midx - assert "A" not in midx._engine - - def test_contains_with_nat(self): - # MI with a NaT - mi = MultiIndex( - levels=[["C"], pd.date_range("2012-01-01", periods=5)], - codes=[[0, 0, 0, 0, 0, 0], [-1, 0, 1, 2, 3, 4]], - names=[None, "B"], - ) - assert ("C", pd.Timestamp("2012-01-01")) in mi - for val in mi.values: - assert val in mi - - def test_contains(self, idx): - assert ("foo", "two") in idx - assert ("bar", "two") not in idx - assert None not in idx - - def test_contains_with_missing_value(self): - # GH#19132 - idx = MultiIndex.from_arrays([[1, np.nan, 2]]) - assert np.nan in idx - - idx = MultiIndex.from_arrays([[1, 2], [np.nan, 3]]) - assert np.nan not in idx - assert (1, np.nan) in idx - - def test_getitem(idx): # scalar assert idx[2] == ("bar", "one") From c4f3419bfa3563f15332b9c00221c311f2739bb2 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 12:03:09 -0700 Subject: [PATCH 5/6] revert --- pandas/tests/indexes/multi/test_arithmetic.py | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 pandas/tests/indexes/multi/test_arithmetic.py diff --git a/pandas/tests/indexes/multi/test_arithmetic.py b/pandas/tests/indexes/multi/test_arithmetic.py deleted file mode 100644 index 4c4ef4adfa6ec..0000000000000 --- a/pandas/tests/indexes/multi/test_arithmetic.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Tests for arithmetic being disabled on MultiIndex. -""" -import pytest - - -def test_sub(idx): - - first = idx - - # - now raises (previously was set op difference) - msg = "cannot perform __sub__ with this index type: MultiIndex" - with pytest.raises(TypeError, match=msg): - first - idx[-3:] - with pytest.raises(TypeError, match=msg): - idx[-3:] - first - with pytest.raises(TypeError, match=msg): - idx[-3:] - first.tolist() - msg = "cannot perform __rsub__ with this index type: MultiIndex" - with pytest.raises(TypeError, match=msg): - first.tolist() - idx[-3:] - - -def test_numeric_compat(idx): - with pytest.raises(TypeError, match="cannot perform __mul__"): - idx * 1 - - with pytest.raises(TypeError, match="cannot perform __rmul__"): - 1 * idx - - div_err = "cannot perform __truediv__" - with pytest.raises(TypeError, match=div_err): - idx / 1 - - div_err = div_err.replace(" __", " __r") - with pytest.raises(TypeError, match=div_err): - 1 / idx - - with pytest.raises(TypeError, match="cannot perform __floordiv__"): - idx // 1 - - with pytest.raises(TypeError, match="cannot perform __rfloordiv__"): - 1 // idx From 5f88ce4a82cccccbaa9fe8bedc80962941e53e7d Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 26 Mar 2020 12:03:31 -0700 Subject: [PATCH 6/6] revert --- pandas/tests/indexes/multi/test_isin.py | 89 ------------------------- 1 file changed, 89 deletions(-) delete mode 100644 pandas/tests/indexes/multi/test_isin.py diff --git a/pandas/tests/indexes/multi/test_isin.py b/pandas/tests/indexes/multi/test_isin.py deleted file mode 100644 index 122263e6ec198..0000000000000 --- a/pandas/tests/indexes/multi/test_isin.py +++ /dev/null @@ -1,89 +0,0 @@ -import numpy as np -import pytest - -from pandas.compat import PYPY - -from pandas import MultiIndex -import pandas._testing as tm - - -@pytest.mark.skipif(not PYPY, reason="tuples cmp recursively on PyPy") -def test_isin_nan_pypy(): - idx = MultiIndex.from_arrays([["foo", "bar"], [1.0, np.nan]]) - tm.assert_numpy_array_equal(idx.isin([("bar", np.nan)]), np.array([False, True])) - tm.assert_numpy_array_equal( - idx.isin([("bar", float("nan"))]), np.array([False, True]) - ) - - -def test_isin(): - values = [("foo", 2), ("bar", 3), ("quux", 4)] - - idx = MultiIndex.from_arrays([["qux", "baz", "foo", "bar"], np.arange(4)]) - result = idx.isin(values) - expected = np.array([False, False, True, True]) - tm.assert_numpy_array_equal(result, expected) - - # empty, return dtype bool - idx = MultiIndex.from_arrays([[], []]) - result = idx.isin(values) - assert len(result) == 0 - assert result.dtype == np.bool_ - - -@pytest.mark.skipif(PYPY, reason="tuples cmp recursively on PyPy") -def test_isin_nan_not_pypy(): - idx = MultiIndex.from_arrays([["foo", "bar"], [1.0, np.nan]]) - tm.assert_numpy_array_equal(idx.isin([("bar", np.nan)]), np.array([False, False])) - tm.assert_numpy_array_equal( - idx.isin([("bar", float("nan"))]), np.array([False, False]) - ) - - -def test_isin_level_kwarg(): - idx = MultiIndex.from_arrays([["qux", "baz", "foo", "bar"], np.arange(4)]) - - vals_0 = ["foo", "bar", "quux"] - vals_1 = [2, 3, 10] - - expected = np.array([False, False, True, True]) - tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=0)) - tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=-2)) - - tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=1)) - tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=-1)) - - msg = "Too many levels: Index has only 2 levels, not 6" - with pytest.raises(IndexError, match=msg): - idx.isin(vals_0, level=5) - msg = "Too many levels: Index has only 2 levels, -5 is not a valid level number" - with pytest.raises(IndexError, match=msg): - idx.isin(vals_0, level=-5) - - with pytest.raises(KeyError, match=r"'Level 1\.0 not found'"): - idx.isin(vals_0, level=1.0) - with pytest.raises(KeyError, match=r"'Level -1\.0 not found'"): - idx.isin(vals_1, level=-1.0) - with pytest.raises(KeyError, match="'Level A not found'"): - idx.isin(vals_1, level="A") - - idx.names = ["A", "B"] - tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level="A")) - tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level="B")) - - with pytest.raises(KeyError, match="'Level C not found'"): - idx.isin(vals_1, level="C") - - -@pytest.mark.parametrize( - "labels,expected,level", - [ - ([("b", np.nan)], np.array([False, False, True]), None,), - ([np.nan, "a"], np.array([True, True, False]), 0), - (["d", np.nan], np.array([False, True, True]), 1), - ], -) -def test_isin_multi_index_with_missing_value(labels, expected, level): - # GH 19132 - midx = MultiIndex.from_arrays([[np.nan, "a", "b"], ["c", "d", np.nan]]) - tm.assert_numpy_array_equal(midx.isin(labels, level=level), expected)