Skip to content

Commit e3c95db

Browse files
authored
TST/REF: collect index tests (#39485)
1 parent 684b58f commit e3c95db

File tree

9 files changed

+499
-467
lines changed

9 files changed

+499
-467
lines changed

pandas/tests/indexes/common.py

-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import pytest
66

77
from pandas._libs import iNaT
8-
from pandas.errors import InvalidIndexError
98

109
from pandas.core.dtypes.common import is_datetime64tz_dtype
1110
from pandas.core.dtypes.dtypes import CategoricalDtype
@@ -202,25 +201,6 @@ def test_reindex_base(self):
202201
with pytest.raises(ValueError, match="Invalid fill method"):
203202
idx.get_indexer(idx, method="invalid")
204203

205-
def test_get_indexer_consistency(self, index):
206-
# See GH 16819
207-
if isinstance(index, IntervalIndex):
208-
# requires index.is_non_overlapping
209-
return
210-
211-
if index.is_unique:
212-
indexer = index.get_indexer(index[0:2])
213-
assert isinstance(indexer, np.ndarray)
214-
assert indexer.dtype == np.intp
215-
else:
216-
e = "Reindexing only valid with uniquely valued Index objects"
217-
with pytest.raises(InvalidIndexError, match=e):
218-
index.get_indexer(index[0:2])
219-
220-
indexer, _ = index.get_indexer_non_unique(index[0:2])
221-
assert isinstance(indexer, np.ndarray)
222-
assert indexer.dtype == np.intp
223-
224204
def test_ndarray_compat_properties(self):
225205
idx = self.create_index()
226206
assert idx.T.equals(idx)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import numpy as np
2+
import pytest
3+
4+
import pandas as pd
5+
from pandas import DatetimeIndex, Index
6+
import pandas._testing as tm
7+
8+
dtlike_dtypes = [
9+
np.dtype("timedelta64[ns]"),
10+
np.dtype("datetime64[ns]"),
11+
pd.DatetimeTZDtype("ns", "Asia/Tokyo"),
12+
pd.PeriodDtype("ns"),
13+
]
14+
15+
16+
@pytest.mark.parametrize("ldtype", dtlike_dtypes)
17+
@pytest.mark.parametrize("rdtype", dtlike_dtypes)
18+
def test_get_indexer_non_unique_wrong_dtype(ldtype, rdtype):
19+
20+
vals = np.tile(3600 * 10 ** 9 * np.arange(3), 2)
21+
22+
def construct(dtype):
23+
if dtype is dtlike_dtypes[-1]:
24+
# PeriodArray will try to cast ints to strings
25+
return DatetimeIndex(vals).astype(dtype)
26+
return Index(vals, dtype=dtype)
27+
28+
left = construct(ldtype)
29+
right = construct(rdtype)
30+
31+
result = left.get_indexer_non_unique(right)
32+
33+
if ldtype is rdtype:
34+
ex1 = np.array([0, 3, 1, 4, 2, 5] * 2, dtype=np.intp)
35+
ex2 = np.array([], dtype=np.intp)
36+
tm.assert_numpy_array_equal(result[0], ex1)
37+
tm.assert_numpy_array_equal(result[1], ex2)
38+
39+
else:
40+
no_matches = np.array([-1] * 6, dtype=np.intp)
41+
missing = np.arange(6, dtype=np.intp)
42+
tm.assert_numpy_array_equal(result[0], no_matches)
43+
tm.assert_numpy_array_equal(result[1], missing)

pandas/tests/indexes/numeric/test_indexing.py

+230-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import numpy as np
22
import pytest
33

4-
from pandas import Float64Index, Index, Int64Index, Series, UInt64Index
4+
from pandas import Float64Index, Index, Int64Index, RangeIndex, Series, UInt64Index
55
import pandas._testing as tm
66

77

@@ -13,6 +13,54 @@ def index_large():
1313

1414

1515
class TestGetLoc:
16+
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
17+
def test_get_loc(self, method):
18+
index = Index([0, 1, 2])
19+
assert index.get_loc(1, method=method) == 1
20+
21+
if method:
22+
assert index.get_loc(1, method=method, tolerance=0) == 1
23+
24+
@pytest.mark.parametrize("method", [None, "pad", "backfill", "nearest"])
25+
def test_get_loc_raises_bad_label(self, method):
26+
index = Index([0, 1, 2])
27+
if method:
28+
msg = "not supported between"
29+
else:
30+
msg = "invalid key"
31+
32+
with pytest.raises(TypeError, match=msg):
33+
index.get_loc([1, 2], method=method)
34+
35+
@pytest.mark.parametrize(
36+
"method,loc", [("pad", 1), ("backfill", 2), ("nearest", 1)]
37+
)
38+
def test_get_loc_tolerance(self, method, loc):
39+
index = Index([0, 1, 2])
40+
assert index.get_loc(1.1, method) == loc
41+
assert index.get_loc(1.1, method, tolerance=1) == loc
42+
43+
@pytest.mark.parametrize("method", ["pad", "backfill", "nearest"])
44+
def test_get_loc_outside_tolerance_raises(self, method):
45+
index = Index([0, 1, 2])
46+
with pytest.raises(KeyError, match="1.1"):
47+
index.get_loc(1.1, method, tolerance=0.05)
48+
49+
def test_get_loc_bad_tolerance_raises(self):
50+
index = Index([0, 1, 2])
51+
with pytest.raises(ValueError, match="must be numeric"):
52+
index.get_loc(1.1, "nearest", tolerance="invalid")
53+
54+
def test_get_loc_tolerance_no_method_raises(self):
55+
index = Index([0, 1, 2])
56+
with pytest.raises(ValueError, match="tolerance .* valid if"):
57+
index.get_loc(1.1, tolerance=1)
58+
59+
def test_get_loc_raises_missized_tolerance(self):
60+
index = Index([0, 1, 2])
61+
with pytest.raises(ValueError, match="tolerance size must match"):
62+
index.get_loc(1.1, "nearest", tolerance=[1, 1])
63+
1664
def test_get_loc_float64(self):
1765
idx = Float64Index([0.0, 1.0, 2.0])
1866
for method in [None, "pad", "backfill", "nearest"]:
@@ -82,6 +130,131 @@ def test_get_loc_missing_nan(self):
82130

83131

84132
class TestGetIndexer:
133+
def test_get_indexer(self):
134+
index1 = Index([1, 2, 3, 4, 5])
135+
index2 = Index([2, 4, 6])
136+
137+
r1 = index1.get_indexer(index2)
138+
e1 = np.array([1, 3, -1], dtype=np.intp)
139+
tm.assert_almost_equal(r1, e1)
140+
141+
@pytest.mark.parametrize("reverse", [True, False])
142+
@pytest.mark.parametrize(
143+
"expected,method",
144+
[
145+
(np.array([-1, 0, 0, 1, 1], dtype=np.intp), "pad"),
146+
(np.array([-1, 0, 0, 1, 1], dtype=np.intp), "ffill"),
147+
(np.array([0, 0, 1, 1, 2], dtype=np.intp), "backfill"),
148+
(np.array([0, 0, 1, 1, 2], dtype=np.intp), "bfill"),
149+
],
150+
)
151+
def test_get_indexer_methods(self, reverse, expected, method):
152+
index1 = Index([1, 2, 3, 4, 5])
153+
index2 = Index([2, 4, 6])
154+
155+
if reverse:
156+
index1 = index1[::-1]
157+
expected = expected[::-1]
158+
159+
result = index2.get_indexer(index1, method=method)
160+
tm.assert_almost_equal(result, expected)
161+
162+
def test_get_indexer_invalid(self):
163+
# GH10411
164+
index = Index(np.arange(10))
165+
166+
with pytest.raises(ValueError, match="tolerance argument"):
167+
index.get_indexer([1, 0], tolerance=1)
168+
169+
with pytest.raises(ValueError, match="limit argument"):
170+
index.get_indexer([1, 0], limit=1)
171+
172+
@pytest.mark.parametrize(
173+
"method, tolerance, indexer, expected",
174+
[
175+
("pad", None, [0, 5, 9], [0, 5, 9]),
176+
("backfill", None, [0, 5, 9], [0, 5, 9]),
177+
("nearest", None, [0, 5, 9], [0, 5, 9]),
178+
("pad", 0, [0, 5, 9], [0, 5, 9]),
179+
("backfill", 0, [0, 5, 9], [0, 5, 9]),
180+
("nearest", 0, [0, 5, 9], [0, 5, 9]),
181+
("pad", None, [0.2, 1.8, 8.5], [0, 1, 8]),
182+
("backfill", None, [0.2, 1.8, 8.5], [1, 2, 9]),
183+
("nearest", None, [0.2, 1.8, 8.5], [0, 2, 9]),
184+
("pad", 1, [0.2, 1.8, 8.5], [0, 1, 8]),
185+
("backfill", 1, [0.2, 1.8, 8.5], [1, 2, 9]),
186+
("nearest", 1, [0.2, 1.8, 8.5], [0, 2, 9]),
187+
("pad", 0.2, [0.2, 1.8, 8.5], [0, -1, -1]),
188+
("backfill", 0.2, [0.2, 1.8, 8.5], [-1, 2, -1]),
189+
("nearest", 0.2, [0.2, 1.8, 8.5], [0, 2, -1]),
190+
],
191+
)
192+
def test_get_indexer_nearest(self, method, tolerance, indexer, expected):
193+
index = Index(np.arange(10))
194+
195+
actual = index.get_indexer(indexer, method=method, tolerance=tolerance)
196+
tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
197+
198+
@pytest.mark.parametrize("listtype", [list, tuple, Series, np.array])
199+
@pytest.mark.parametrize(
200+
"tolerance, expected",
201+
list(
202+
zip(
203+
[[0.3, 0.3, 0.1], [0.2, 0.1, 0.1], [0.1, 0.5, 0.5]],
204+
[[0, 2, -1], [0, -1, -1], [-1, 2, 9]],
205+
)
206+
),
207+
)
208+
def test_get_indexer_nearest_listlike_tolerance(
209+
self, tolerance, expected, listtype
210+
):
211+
index = Index(np.arange(10))
212+
213+
actual = index.get_indexer(
214+
[0.2, 1.8, 8.5], method="nearest", tolerance=listtype(tolerance)
215+
)
216+
tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
217+
218+
def test_get_indexer_nearest_error(self):
219+
index = Index(np.arange(10))
220+
with pytest.raises(ValueError, match="limit argument"):
221+
index.get_indexer([1, 0], method="nearest", limit=1)
222+
223+
with pytest.raises(ValueError, match="tolerance size must match"):
224+
index.get_indexer([1, 0], method="nearest", tolerance=[1, 2, 3])
225+
226+
@pytest.mark.parametrize(
227+
"method,expected",
228+
[("pad", [8, 7, 0]), ("backfill", [9, 8, 1]), ("nearest", [9, 7, 0])],
229+
)
230+
def test_get_indexer_nearest_decreasing(self, method, expected):
231+
index = Index(np.arange(10))[::-1]
232+
233+
actual = index.get_indexer([0, 5, 9], method=method)
234+
tm.assert_numpy_array_equal(actual, np.array([9, 4, 0], dtype=np.intp))
235+
236+
actual = index.get_indexer([0.2, 1.8, 8.5], method=method)
237+
tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
238+
239+
@pytest.mark.parametrize(
240+
"idx_class", [Int64Index, RangeIndex, Float64Index, UInt64Index]
241+
)
242+
@pytest.mark.parametrize("method", ["get_indexer", "get_indexer_non_unique"])
243+
def test_get_indexer_numeric_index_boolean_target(self, method, idx_class):
244+
# GH 16877
245+
246+
numeric_index = idx_class(RangeIndex(4))
247+
other = Index([True, False, True])
248+
249+
result = getattr(numeric_index, method)(other)
250+
expected = np.array([-1, -1, -1], dtype=np.intp)
251+
if method == "get_indexer":
252+
tm.assert_numpy_array_equal(result, expected)
253+
else:
254+
missing = np.arange(3, dtype=np.intp)
255+
tm.assert_numpy_array_equal(result[0], expected)
256+
tm.assert_numpy_array_equal(result[1], missing)
257+
85258
@pytest.mark.parametrize("method", ["pad", "backfill", "nearest"])
86259
def test_get_indexer_with_method_numeric_vs_bool(self, method):
87260
left = Index([1, 2, 3])
@@ -274,6 +447,62 @@ def test_contains_float64_not_nans(self):
274447
assert 1.0 in index
275448

276449

450+
class TestSliceLocs:
451+
@pytest.mark.parametrize("dtype", [int, float])
452+
def test_slice_locs(self, dtype):
453+
index = Index(np.array([0, 1, 2, 5, 6, 7, 9, 10], dtype=dtype))
454+
n = len(index)
455+
456+
assert index.slice_locs(start=2) == (2, n)
457+
assert index.slice_locs(start=3) == (3, n)
458+
assert index.slice_locs(3, 8) == (3, 6)
459+
assert index.slice_locs(5, 10) == (3, n)
460+
assert index.slice_locs(end=8) == (0, 6)
461+
assert index.slice_locs(end=9) == (0, 7)
462+
463+
# reversed
464+
index2 = index[::-1]
465+
assert index2.slice_locs(8, 2) == (2, 6)
466+
assert index2.slice_locs(7, 3) == (2, 5)
467+
468+
@pytest.mark.parametrize("dtype", [int, float])
469+
def test_slice_locs_float_locs(self, dtype):
470+
index = Index(np.array([0, 1, 2, 5, 6, 7, 9, 10], dtype=dtype))
471+
n = len(index)
472+
assert index.slice_locs(5.0, 10.0) == (3, n)
473+
assert index.slice_locs(4.5, 10.5) == (3, 8)
474+
475+
index2 = index[::-1]
476+
assert index2.slice_locs(8.5, 1.5) == (2, 6)
477+
assert index2.slice_locs(10.5, -1) == (0, n)
478+
479+
@pytest.mark.parametrize("dtype", [int, float])
480+
def test_slice_locs_dup_numeric(self, dtype):
481+
index = Index(np.array([10, 12, 12, 14], dtype=dtype))
482+
assert index.slice_locs(12, 12) == (1, 3)
483+
assert index.slice_locs(11, 13) == (1, 3)
484+
485+
index2 = index[::-1]
486+
assert index2.slice_locs(12, 12) == (1, 3)
487+
assert index2.slice_locs(13, 11) == (1, 3)
488+
489+
def test_slice_locs_na(self):
490+
index = Index([np.nan, 1, 2])
491+
assert index.slice_locs(1) == (1, 3)
492+
assert index.slice_locs(np.nan) == (0, 3)
493+
494+
index = Index([0, np.nan, np.nan, 1, 2])
495+
assert index.slice_locs(np.nan) == (1, 5)
496+
497+
def test_slice_locs_na_raises(self):
498+
index = Index([np.nan, 1, 2])
499+
with pytest.raises(KeyError, match=""):
500+
index.slice_locs(start=1.5)
501+
502+
with pytest.raises(KeyError, match=""):
503+
index.slice_locs(end=1.5)
504+
505+
277506
class TestGetSliceBounds:
278507
@pytest.mark.parametrize("kind", ["getitem", "loc", None])
279508
@pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])

pandas/tests/indexes/numeric/test_setops.py

+18
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ def test_intersection_monotonic(self, index2, keeps_name, sort):
110110
expected = expected.sort_values()
111111
tm.assert_index_equal(result, expected)
112112

113+
def test_symmetric_difference(self, sort):
114+
# smoke
115+
index1 = Index([5, 2, 3, 4], name="index1")
116+
index2 = Index([2, 3, 4, 1])
117+
result = index1.symmetric_difference(index2, sort=sort)
118+
expected = Index([5, 1])
119+
assert tm.equalContents(result, expected)
120+
assert result.name is None
121+
if sort is None:
122+
expected = expected.sort_values()
123+
tm.assert_index_equal(result, expected)
124+
125+
# __xor__ syntax
126+
with tm.assert_produces_warning(FutureWarning):
127+
expected = index1 ^ index2
128+
assert tm.equalContents(result, expected)
129+
assert result.name is None
130+
113131

114132
class TestSetOpsSort:
115133
@pytest.mark.parametrize("slice_", [slice(None), slice(0)])

0 commit comments

Comments
 (0)