Skip to content

Commit 26ad277

Browse files
committed
addressing comments to pull request #21514 for GH issue #18644
1 parent 1542e4f commit 26ad277

17 files changed

+1529
-1470
lines changed

pandas/tests/indexes/multi/test_base.py

Lines changed: 0 additions & 938 deletions
This file was deleted.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# -*- coding: utf-8 -*-
2+
3+
4+
import numpy as np
5+
import pandas as pd
6+
import pandas.util.testing as tm
7+
import pytest
8+
from pandas import (CategoricalIndex, DatetimeIndex, Float64Index, Index,
9+
Int64Index, IntervalIndex, MultiIndex, PeriodIndex,
10+
RangeIndex, Series, TimedeltaIndex, UInt64Index, compat,
11+
isna)
12+
from pandas._libs.tslib import iNaT
13+
from pandas.compat import PY3
14+
from pandas.core.indexes.base import InvalidIndexError
15+
from pandas.core.indexes.datetimelike import DatetimeIndexOpsMixin
16+
from pandas.compat import PY3, PYPY, lrange, lzip, range, u, long
17+
import numpy as np
18+
19+
20+
21+
def test_numeric_compat(_index):
22+
23+
idx = _index
24+
tm.assert_raises_regex(TypeError, "cannot perform __mul__",
25+
lambda: idx * 1)
26+
tm.assert_raises_regex(TypeError, "cannot perform __rmul__",
27+
lambda: 1 * idx)
28+
29+
div_err = "cannot perform __truediv__" if PY3 \
30+
else "cannot perform __div__"
31+
tm.assert_raises_regex(TypeError, div_err, lambda: idx / 1)
32+
div_err = div_err.replace(' __', ' __r')
33+
tm.assert_raises_regex(TypeError, div_err, lambda: 1 / idx)
34+
tm.assert_raises_regex(TypeError, "cannot perform __floordiv__",
35+
lambda: idx // 1)
36+
tm.assert_raises_regex(TypeError, "cannot perform __rfloordiv__",
37+
lambda: 1 // idx)
38+
39+
40+
def test_logical_compat(_index):
41+
idx = _index
42+
tm.assert_raises_regex(TypeError, 'cannot perform all',
43+
lambda: idx.all())
44+
tm.assert_raises_regex(TypeError, 'cannot perform any',
45+
lambda: idx.any())
46+
47+
48+
def test_boolean_context_compat(_index):
49+
50+
# boolean context compat
51+
idx = _index
52+
53+
def f():
54+
if idx:
55+
pass
56+
57+
tm.assert_raises_regex(ValueError, 'The truth value of a', f)
58+
59+
60+
def test_boolean_context_compat2():
61+
62+
# boolean context compat
63+
# GH7897
64+
i1 = MultiIndex.from_tuples([('A', 1), ('A', 2)])
65+
i2 = MultiIndex.from_tuples([('A', 1), ('A', 3)])
66+
common = i1.intersection(i2)
67+
68+
def f():
69+
if common:
70+
pass
71+
72+
tm.assert_raises_regex(ValueError, 'The truth value of a', f)
73+
74+
75+
def test_inplace_mutation_resets_values():
76+
levels = [['a', 'b', 'c'], [4]]
77+
levels2 = [[1, 2, 3], ['a']]
78+
labels = [[0, 1, 0, 2, 2, 0], [0, 0, 0, 0, 0, 0]]
79+
80+
mi1 = MultiIndex(levels=levels, labels=labels)
81+
mi2 = MultiIndex(levels=levels2, labels=labels)
82+
vals = mi1.values.copy()
83+
vals2 = mi2.values.copy()
84+
85+
assert mi1._tuples is not None
86+
87+
# Make sure level setting works
88+
new_vals = mi1.set_levels(levels2).values
89+
tm.assert_almost_equal(vals2, new_vals)
90+
91+
# Non-inplace doesn't kill _tuples [implementation detail]
92+
tm.assert_almost_equal(mi1._tuples, vals)
93+
94+
# ...and values is still same too
95+
tm.assert_almost_equal(mi1.values, vals)
96+
97+
# Inplace should kill _tuples
98+
mi1.set_levels(levels2, inplace=True)
99+
tm.assert_almost_equal(mi1.values, vals2)
100+
101+
# Make sure label setting works too
102+
labels2 = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
103+
exp_values = np.empty((6,), dtype=object)
104+
exp_values[:] = [(long(1), 'a')] * 6
105+
106+
# Must be 1d array of tuples
107+
assert exp_values.shape == (6,)
108+
new_values = mi2.set_labels(labels2).values
109+
110+
# Not inplace shouldn't change
111+
tm.assert_almost_equal(mi2._tuples, vals2)
112+
113+
# Should have correct values
114+
tm.assert_almost_equal(exp_values, new_values)
115+
116+
# ...and again setting inplace should kill _tuples, etc
117+
mi2.set_labels(labels2, inplace=True)
118+
tm.assert_almost_equal(mi2.values, new_values)
119+
120+
121+
def test_ndarray_compat_properties(_index, _compat_props):
122+
idx = _index
123+
assert idx.T.equals(idx)
124+
assert idx.transpose().equals(idx)
125+
126+
values = idx.values
127+
for prop in _compat_props:
128+
assert getattr(idx, prop) == getattr(values, prop)
129+
130+
# test for validity
131+
idx.nbytes
132+
idx.values.nbytes
133+
134+
135+
def test_compat(indices):
136+
assert indices.tolist() == list(indices)
137+
138+
def test_pickle_compat_construction(_holder):
139+
# this is testing for pickle compat
140+
if _holder is None:
141+
return
142+
143+
# need an object to create with
144+
pytest.raises(TypeError, _holder)

pandas/tests/indexes/multi/test_constructor.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,3 +476,34 @@ def test_from_product_iterator():
476476
with tm.assert_raises_regex(
477477
TypeError, "Input must be a list / sequence of iterables."):
478478
MultiIndex.from_product(0)
479+
480+
481+
def test_create_index_existing_name(_index):
482+
483+
# GH11193, when an existing index is passed, and a new name is not
484+
# specified, the new index should inherit the previous object name
485+
index = _index
486+
index.names = ['foo', 'bar']
487+
result = pd.Index(index)
488+
tm.assert_index_equal(
489+
result, Index(Index([('foo', 'one'), ('foo', 'two'),
490+
('bar', 'one'), ('baz', 'two'),
491+
('qux', 'one'), ('qux', 'two')],
492+
dtype='object'),
493+
names=['foo', 'bar']))
494+
495+
result = pd.Index(index, names=['A', 'B'])
496+
tm.assert_index_equal(
497+
result,
498+
Index(Index([('foo', 'one'), ('foo', 'two'), ('bar', 'one'),
499+
('baz', 'two'), ('qux', 'one'), ('qux', 'two')],
500+
dtype='object'), names=['A', 'B']))
501+
502+
def test_tuples_with_name_string():
503+
# GH 15110 and GH 14848
504+
505+
li = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
506+
with pytest.raises(ValueError):
507+
pd.Index(li, name='abc')
508+
with pytest.raises(ValueError):
509+
pd.Index(li, name='a')

pandas/tests/indexes/multi/test_contains.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import pandas as pd
44
from pandas import MultiIndex
5+
import pytest
6+
from pandas.compat import PY3, PYPY, lrange, lzip, range, u
7+
import numpy as np
8+
import pandas.util.testing as tm
59

610

711
def test_contains_top_level():
@@ -25,3 +29,101 @@ def test_contains(_index):
2529
assert ('foo', 'two') in _index
2630
assert ('bar', 'two') not in _index
2731
assert None not in _index
32+
33+
34+
@pytest.mark.skipif(not PYPY, reason="tuples cmp recursively on PyPy")
35+
def test_isin_nan_pypy():
36+
idx = MultiIndex.from_arrays([['foo', 'bar'], [1.0, np.nan]])
37+
tm.assert_numpy_array_equal(idx.isin([('bar', np.nan)]),
38+
np.array([False, True]))
39+
tm.assert_numpy_array_equal(idx.isin([('bar', float('nan'))]),
40+
np.array([False, True]))
41+
42+
43+
def test_isin():
44+
values = [('foo', 2), ('bar', 3), ('quux', 4)]
45+
46+
idx = MultiIndex.from_arrays([['qux', 'baz', 'foo', 'bar'], np.arange(
47+
4)])
48+
result = idx.isin(values)
49+
expected = np.array([False, False, True, True])
50+
tm.assert_numpy_array_equal(result, expected)
51+
52+
# empty, return dtype bool
53+
idx = MultiIndex.from_arrays([[], []])
54+
result = idx.isin(values)
55+
assert len(result) == 0
56+
assert result.dtype == np.bool_
57+
58+
59+
@pytest.mark.skipif(PYPY, reason="tuples cmp recursively on PyPy")
60+
def test_isin_nan_not_pypy():
61+
idx = MultiIndex.from_arrays([['foo', 'bar'], [1.0, np.nan]])
62+
tm.assert_numpy_array_equal(idx.isin([('bar', np.nan)]),
63+
np.array([False, False]))
64+
tm.assert_numpy_array_equal(idx.isin([('bar', float('nan'))]),
65+
np.array([False, False]))
66+
67+
68+
def test_isin_level_kwarg():
69+
idx = MultiIndex.from_arrays([['qux', 'baz', 'foo', 'bar'], np.arange(
70+
4)])
71+
72+
vals_0 = ['foo', 'bar', 'quux']
73+
vals_1 = [2, 3, 10]
74+
75+
expected = np.array([False, False, True, True])
76+
tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=0))
77+
tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level=-2))
78+
79+
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=1))
80+
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=-1))
81+
82+
pytest.raises(IndexError, idx.isin, vals_0, level=5)
83+
pytest.raises(IndexError, idx.isin, vals_0, level=-5)
84+
85+
pytest.raises(KeyError, idx.isin, vals_0, level=1.0)
86+
pytest.raises(KeyError, idx.isin, vals_1, level=-1.0)
87+
pytest.raises(KeyError, idx.isin, vals_1, level='A')
88+
89+
idx.names = ['A', 'B']
90+
tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level='A'))
91+
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level='B'))
92+
93+
pytest.raises(KeyError, idx.isin, vals_1, level='C')
94+
95+
96+
def test_hasnans_isnans(named_index):
97+
# GH 11343, added tests for hasnans / isnans
98+
for name, index in named_index.items():
99+
if isinstance(index, MultiIndex):
100+
pass
101+
else:
102+
idx = index.copy()
103+
104+
# cases in indices doesn't include NaN
105+
expected = np.array([False] * len(idx), dtype=bool)
106+
tm.assert_numpy_array_equal(idx._isnan, expected)
107+
assert not idx.hasnans
108+
109+
idx = index.copy()
110+
values = idx.values
111+
112+
if len(index) == 0:
113+
continue
114+
elif isinstance(index, DatetimeIndexOpsMixin):
115+
values[1] = iNaT
116+
elif isinstance(index, (Int64Index, UInt64Index)):
117+
continue
118+
else:
119+
values[1] = np.nan
120+
121+
if isinstance(index, PeriodIndex):
122+
idx = index.__class__(values, freq=index.freq)
123+
else:
124+
idx = index.__class__(values)
125+
126+
expected = np.array([False] * len(idx), dtype=bool)
127+
expected[1] = True
128+
tm.assert_numpy_array_equal(idx._isnan, expected)
129+
assert idx.hasnans

pandas/tests/indexes/multi/test_conversion.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,9 @@
77
import pytest
88
from pandas import DataFrame, MultiIndex, date_range
99
from pandas.compat import PY3, range
10-
1110
from pandas.util.testing import assert_almost_equal
1211

1312

14-
def test_tuples_with_name_string():
15-
# GH 15110 and GH 14848
16-
17-
li = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
18-
with pytest.raises(ValueError):
19-
pd.Index(li, name='abc')
20-
with pytest.raises(ValueError):
21-
pd.Index(li, name='a')
22-
23-
2413
def test_tolist(_index):
2514
result = _index.tolist()
2615
exp = list(_index.values)
@@ -150,3 +139,12 @@ def test_roundtrip_pickle_with_tz():
150139
], names=['one', 'two', 'three'])
151140
unpickled = tm.round_trip_pickle(index)
152141
assert index.equal_levels(unpickled)
142+
143+
144+
def test_pickle(indices):
145+
unpickled = tm.round_trip_pickle(indices)
146+
assert indices.equals(unpickled)
147+
original_name, indices.name = indices.name, 'foo'
148+
unpickled = tm.round_trip_pickle(indices)
149+
assert indices.equals(unpickled)
150+
indices.name = original_name

0 commit comments

Comments
 (0)