Skip to content

Commit a04a6f7

Browse files
authored
TST/REF: collect Index setops tests (#38019)
1 parent 3ba6cc6 commit a04a6f7

File tree

4 files changed

+246
-234
lines changed

4 files changed

+246
-234
lines changed

pandas/tests/indexes/base_class/test_setops.py

+104-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from datetime import datetime
2+
13
import numpy as np
24
import pytest
35

@@ -83,14 +85,21 @@ def test_union_sort_other_incomparable(self):
8385
result = idx.union(idx[:1], sort=False)
8486
tm.assert_index_equal(result, idx)
8587

86-
@pytest.mark.xfail(reason="Not implemented")
88+
@pytest.mark.xfail(reason="GH#25151 need to decide on True behavior")
8789
def test_union_sort_other_incomparable_true(self):
8890
# TODO decide on True behaviour
8991
# sort=True
9092
idx = Index([1, pd.Timestamp("2000")])
9193
with pytest.raises(TypeError, match=".*"):
9294
idx.union(idx[:1], sort=True)
9395

96+
@pytest.mark.xfail(reason="GH#25151 need to decide on True behavior")
97+
def test_intersection_equal_sort_true(self):
98+
# TODO decide on True behaviour
99+
idx = Index(["c", "a", "b"])
100+
sorted_ = Index(["a", "b", "c"])
101+
tm.assert_index_equal(idx.intersection(idx, sort=True), sorted_)
102+
94103
def test_intersection_base(self, sort):
95104
# (same results for py2 and py3 but sortedness not tested elsewhere)
96105
index = Index([0, "a", 1, "b", 2, "c"])
@@ -111,7 +120,7 @@ def test_intersection_different_type_base(self, klass, sort):
111120
result = first.intersection(klass(second.values), sort=sort)
112121
assert tm.equalContents(result, second)
113122

114-
def test_intersect_nosort(self):
123+
def test_intersection_nosort(self):
115124
result = Index(["c", "b", "a"]).intersection(["b", "a"])
116125
expected = Index(["b", "a"])
117126
tm.assert_index_equal(result, expected)
@@ -121,6 +130,28 @@ def test_intersection_equal_sort(self):
121130
tm.assert_index_equal(idx.intersection(idx, sort=False), idx)
122131
tm.assert_index_equal(idx.intersection(idx, sort=None), idx)
123132

133+
def test_intersection_str_dates(self, sort):
134+
dt_dates = [datetime(2012, 2, 9), datetime(2012, 2, 22)]
135+
136+
i1 = Index(dt_dates, dtype=object)
137+
i2 = Index(["aa"], dtype=object)
138+
result = i2.intersection(i1, sort=sort)
139+
140+
assert len(result) == 0
141+
142+
@pytest.mark.parametrize(
143+
"index2,expected_arr",
144+
[(Index(["B", "D"]), ["B"]), (Index(["B", "D", "A"]), ["A", "B", "A"])],
145+
)
146+
def test_intersection_non_monotonic_non_unique(self, index2, expected_arr, sort):
147+
# non-monotonic non-unique
148+
index1 = Index(["A", "B", "A", "C"])
149+
expected = Index(expected_arr, dtype="object")
150+
result = index1.intersection(index2, sort=sort)
151+
if sort is None:
152+
expected = expected.sort_values()
153+
tm.assert_index_equal(result, expected)
154+
124155
def test_difference_base(self, sort):
125156
# (same results for py2 and py3 but sortedness not tested elsewhere)
126157
index = Index([0, "a", 1, "b", 2, "c"])
@@ -142,3 +173,74 @@ def test_symmetric_difference(self):
142173
result = first.symmetric_difference(second)
143174
expected = Index([0, 1, 2, "a", "c"])
144175
tm.assert_index_equal(result, expected)
176+
177+
@pytest.mark.parametrize(
178+
"method,expected,sort",
179+
[
180+
(
181+
"intersection",
182+
np.array(
183+
[(1, "A"), (2, "A"), (1, "B"), (2, "B")],
184+
dtype=[("num", int), ("let", "a1")],
185+
),
186+
False,
187+
),
188+
(
189+
"intersection",
190+
np.array(
191+
[(1, "A"), (1, "B"), (2, "A"), (2, "B")],
192+
dtype=[("num", int), ("let", "a1")],
193+
),
194+
None,
195+
),
196+
(
197+
"union",
198+
np.array(
199+
[(1, "A"), (1, "B"), (1, "C"), (2, "A"), (2, "B"), (2, "C")],
200+
dtype=[("num", int), ("let", "a1")],
201+
),
202+
None,
203+
),
204+
],
205+
)
206+
def test_tuple_union_bug(self, method, expected, sort):
207+
index1 = Index(
208+
np.array(
209+
[(1, "A"), (2, "A"), (1, "B"), (2, "B")],
210+
dtype=[("num", int), ("let", "a1")],
211+
)
212+
)
213+
index2 = Index(
214+
np.array(
215+
[(1, "A"), (2, "A"), (1, "B"), (2, "B"), (1, "C"), (2, "C")],
216+
dtype=[("num", int), ("let", "a1")],
217+
)
218+
)
219+
220+
result = getattr(index1, method)(index2, sort=sort)
221+
assert result.ndim == 1
222+
223+
expected = Index(expected)
224+
tm.assert_index_equal(result, expected)
225+
226+
@pytest.mark.parametrize("first_list", [list("ba"), list()])
227+
@pytest.mark.parametrize("second_list", [list("ab"), list()])
228+
@pytest.mark.parametrize(
229+
"first_name, second_name, expected_name",
230+
[("A", "B", None), (None, "B", None), ("A", None, None)],
231+
)
232+
def test_union_name_preservation(
233+
self, first_list, second_list, first_name, second_name, expected_name, sort
234+
):
235+
first = Index(first_list, name=first_name)
236+
second = Index(second_list, name=second_name)
237+
union = first.union(second, sort=sort)
238+
239+
vals = set(first_list).union(second_list)
240+
241+
if sort is None and len(first_list) > 0 and len(second_list) > 0:
242+
expected = Index(sorted(vals), name=expected_name)
243+
tm.assert_index_equal(union, expected)
244+
else:
245+
expected = Index(vals, name=expected_name)
246+
tm.equalContents(union, expected)
+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
from datetime import datetime, timedelta
2+
3+
import numpy as np
4+
import pytest
5+
6+
from pandas import Float64Index, Index, Int64Index, RangeIndex, UInt64Index
7+
import pandas._testing as tm
8+
9+
10+
@pytest.fixture
11+
def index_large():
12+
# large values used in TestUInt64Index where no compat needed with Int64/Float64
13+
large = [2 ** 63, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20, 2 ** 63 + 25]
14+
return UInt64Index(large)
15+
16+
17+
class TestSetOps:
18+
@pytest.mark.parametrize("dtype", ["f8", "u8", "i8"])
19+
def test_union_non_numeric(self, dtype):
20+
# corner case, non-numeric
21+
index = Index(np.arange(5, dtype=dtype), dtype=dtype)
22+
assert index.dtype == dtype
23+
24+
other = Index([datetime.now() + timedelta(i) for i in range(4)], dtype=object)
25+
result = index.union(other)
26+
expected = Index(np.concatenate((index, other)))
27+
tm.assert_index_equal(result, expected)
28+
29+
result = other.union(index)
30+
expected = Index(np.concatenate((other, index)))
31+
tm.assert_index_equal(result, expected)
32+
33+
def test_intersection(self):
34+
index = Int64Index(range(5))
35+
36+
other = Index([1, 2, 3, 4, 5])
37+
result = index.intersection(other)
38+
expected = Index(np.sort(np.intersect1d(index.values, other.values)))
39+
tm.assert_index_equal(result, expected)
40+
41+
result = other.intersection(index)
42+
expected = Index(
43+
np.sort(np.asarray(np.intersect1d(index.values, other.values)))
44+
)
45+
tm.assert_index_equal(result, expected)
46+
47+
@pytest.mark.parametrize("dtype", ["int64", "uint64"])
48+
def test_int_float_union_dtype(self, dtype):
49+
# https://github.com/pandas-dev/pandas/issues/26778
50+
# [u]int | float -> float
51+
index = Index([0, 2, 3], dtype=dtype)
52+
other = Float64Index([0.5, 1.5])
53+
expected = Float64Index([0.0, 0.5, 1.5, 2.0, 3.0])
54+
result = index.union(other)
55+
tm.assert_index_equal(result, expected)
56+
57+
result = other.union(index)
58+
tm.assert_index_equal(result, expected)
59+
60+
def test_range_float_union_dtype(self):
61+
# https://github.com/pandas-dev/pandas/issues/26778
62+
index = RangeIndex(start=0, stop=3)
63+
other = Float64Index([0.5, 1.5])
64+
result = index.union(other)
65+
expected = Float64Index([0.0, 0.5, 1, 1.5, 2.0])
66+
tm.assert_index_equal(result, expected)
67+
68+
result = other.union(index)
69+
tm.assert_index_equal(result, expected)
70+
71+
def test_float64_index_difference(self):
72+
# https://github.com/pandas-dev/pandas/issues/35217
73+
float_index = Index([1.0, 2, 3])
74+
string_index = Index(["1", "2", "3"])
75+
76+
result = float_index.difference(string_index)
77+
tm.assert_index_equal(result, float_index)
78+
79+
result = string_index.difference(float_index)
80+
tm.assert_index_equal(result, string_index)
81+
82+
def test_intersection_uint64_outside_int64_range(self, index_large):
83+
other = Index([2 ** 63, 2 ** 63 + 5, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20])
84+
result = index_large.intersection(other)
85+
expected = Index(np.sort(np.intersect1d(index_large.values, other.values)))
86+
tm.assert_index_equal(result, expected)
87+
88+
result = other.intersection(index_large)
89+
expected = Index(
90+
np.sort(np.asarray(np.intersect1d(index_large.values, other.values)))
91+
)
92+
tm.assert_index_equal(result, expected)
93+
94+
@pytest.mark.parametrize(
95+
"index2,keeps_name",
96+
[
97+
(Index([4, 7, 6, 5, 3], name="index"), True),
98+
(Index([4, 7, 6, 5, 3], name="other"), False),
99+
],
100+
)
101+
def test_intersection_monotonic(self, index2, keeps_name, sort):
102+
index1 = Index([5, 3, 2, 4, 1], name="index")
103+
expected = Index([5, 3, 4])
104+
105+
if keeps_name:
106+
expected.name = "index"
107+
108+
result = index1.intersection(index2, sort=sort)
109+
if sort is None:
110+
expected = expected.sort_values()
111+
tm.assert_index_equal(result, expected)
112+
113+
114+
class TestSetOpsSort:
115+
@pytest.mark.parametrize("slice_", [slice(None), slice(0)])
116+
def test_union_sort_other_special(self, slice_):
117+
# https://github.com/pandas-dev/pandas/issues/24959
118+
119+
idx = Index([1, 0, 2])
120+
# default, sort=None
121+
other = idx[slice_]
122+
tm.assert_index_equal(idx.union(other), idx)
123+
tm.assert_index_equal(other.union(idx), idx)
124+
125+
# sort=False
126+
tm.assert_index_equal(idx.union(other, sort=False), idx)
127+
128+
@pytest.mark.xfail(reason="Not implemented")
129+
@pytest.mark.parametrize("slice_", [slice(None), slice(0)])
130+
def test_union_sort_special_true(self, slice_):
131+
# TODO: decide on True behaviour
132+
# sort=True
133+
idx = Index([1, 0, 2])
134+
# default, sort=None
135+
other = idx[slice_]
136+
137+
result = idx.union(other, sort=True)
138+
expected = Index([0, 1, 2])
139+
tm.assert_index_equal(result, expected)

0 commit comments

Comments
 (0)