test_indexing.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. import numpy as np
  2. import pytest
  3. from pandas.errors import InvalidIndexError
  4. from pandas import (
  5. NA,
  6. Index,
  7. RangeIndex,
  8. Series,
  9. Timestamp,
  10. )
  11. import pandas._testing as tm
  12. from pandas.core.arrays import (
  13. ArrowExtensionArray,
  14. FloatingArray,
  15. )
  16. @pytest.fixture
  17. def index_large():
  18. # large values used in Index[uint64] tests where no compat needed with Int64/Float64
  19. large = [2**63, 2**63 + 10, 2**63 + 15, 2**63 + 20, 2**63 + 25]
  20. return Index(large, dtype=np.uint64)
  21. class TestGetLoc:
  22. def test_get_loc(self):
  23. index = Index([0, 1, 2])
  24. assert index.get_loc(1) == 1
  25. def test_get_loc_raises_bad_label(self):
  26. index = Index([0, 1, 2])
  27. with pytest.raises(InvalidIndexError, match=r"\[1, 2\]"):
  28. index.get_loc([1, 2])
  29. def test_get_loc_float64(self):
  30. idx = Index([0.0, 1.0, 2.0], dtype=np.float64)
  31. with pytest.raises(KeyError, match="^'foo'$"):
  32. idx.get_loc("foo")
  33. with pytest.raises(KeyError, match=r"^1\.5$"):
  34. idx.get_loc(1.5)
  35. with pytest.raises(KeyError, match="^True$"):
  36. idx.get_loc(True)
  37. with pytest.raises(KeyError, match="^False$"):
  38. idx.get_loc(False)
  39. def test_get_loc_na(self):
  40. idx = Index([np.nan, 1, 2], dtype=np.float64)
  41. assert idx.get_loc(1) == 1
  42. assert idx.get_loc(np.nan) == 0
  43. idx = Index([np.nan, 1, np.nan], dtype=np.float64)
  44. assert idx.get_loc(1) == 1
  45. # representable by slice [0:2:2]
  46. msg = "'Cannot get left slice bound for non-unique label: nan'"
  47. with pytest.raises(KeyError, match=msg):
  48. idx.slice_locs(np.nan)
  49. # not representable by slice
  50. idx = Index([np.nan, 1, np.nan, np.nan], dtype=np.float64)
  51. assert idx.get_loc(1) == 1
  52. msg = "'Cannot get left slice bound for non-unique label: nan"
  53. with pytest.raises(KeyError, match=msg):
  54. idx.slice_locs(np.nan)
  55. def test_get_loc_missing_nan(self):
  56. # GH#8569
  57. idx = Index([1, 2], dtype=np.float64)
  58. assert idx.get_loc(1) == 0
  59. with pytest.raises(KeyError, match=r"^3$"):
  60. idx.get_loc(3)
  61. with pytest.raises(KeyError, match="^nan$"):
  62. idx.get_loc(np.nan)
  63. with pytest.raises(InvalidIndexError, match=r"\[nan\]"):
  64. # listlike/non-hashable raises TypeError
  65. idx.get_loc([np.nan])
  66. @pytest.mark.parametrize("vals", [[1], [1.0], [Timestamp("2019-12-31")], ["test"]])
  67. def test_get_loc_float_index_nan_with_method(self, vals):
  68. # GH#39382
  69. idx = Index(vals)
  70. with pytest.raises(KeyError, match="nan"):
  71. idx.get_loc(np.nan)
  72. @pytest.mark.parametrize("dtype", ["f8", "i8", "u8"])
  73. def test_get_loc_numericindex_none_raises(self, dtype):
  74. # case that goes through searchsorted and key is non-comparable to values
  75. arr = np.arange(10**7, dtype=dtype)
  76. idx = Index(arr)
  77. with pytest.raises(KeyError, match="None"):
  78. idx.get_loc(None)
  79. def test_get_loc_overflows(self):
  80. # unique but non-monotonic goes through IndexEngine.mapping.get_item
  81. idx = Index([0, 2, 1])
  82. val = np.iinfo(np.int64).max + 1
  83. with pytest.raises(KeyError, match=str(val)):
  84. idx.get_loc(val)
  85. with pytest.raises(KeyError, match=str(val)):
  86. idx._engine.get_loc(val)
  87. class TestGetIndexer:
  88. def test_get_indexer(self):
  89. index1 = Index([1, 2, 3, 4, 5])
  90. index2 = Index([2, 4, 6])
  91. r1 = index1.get_indexer(index2)
  92. e1 = np.array([1, 3, -1], dtype=np.intp)
  93. tm.assert_almost_equal(r1, e1)
  94. @pytest.mark.parametrize("reverse", [True, False])
  95. @pytest.mark.parametrize(
  96. "expected,method",
  97. [
  98. (np.array([-1, 0, 0, 1, 1], dtype=np.intp), "pad"),
  99. (np.array([-1, 0, 0, 1, 1], dtype=np.intp), "ffill"),
  100. (np.array([0, 0, 1, 1, 2], dtype=np.intp), "backfill"),
  101. (np.array([0, 0, 1, 1, 2], dtype=np.intp), "bfill"),
  102. ],
  103. )
  104. def test_get_indexer_methods(self, reverse, expected, method):
  105. index1 = Index([1, 2, 3, 4, 5])
  106. index2 = Index([2, 4, 6])
  107. if reverse:
  108. index1 = index1[::-1]
  109. expected = expected[::-1]
  110. result = index2.get_indexer(index1, method=method)
  111. tm.assert_almost_equal(result, expected)
  112. def test_get_indexer_invalid(self):
  113. # GH10411
  114. index = Index(np.arange(10))
  115. with pytest.raises(ValueError, match="tolerance argument"):
  116. index.get_indexer([1, 0], tolerance=1)
  117. with pytest.raises(ValueError, match="limit argument"):
  118. index.get_indexer([1, 0], limit=1)
  119. @pytest.mark.parametrize(
  120. "method, tolerance, indexer, expected",
  121. [
  122. ("pad", None, [0, 5, 9], [0, 5, 9]),
  123. ("backfill", None, [0, 5, 9], [0, 5, 9]),
  124. ("nearest", None, [0, 5, 9], [0, 5, 9]),
  125. ("pad", 0, [0, 5, 9], [0, 5, 9]),
  126. ("backfill", 0, [0, 5, 9], [0, 5, 9]),
  127. ("nearest", 0, [0, 5, 9], [0, 5, 9]),
  128. ("pad", None, [0.2, 1.8, 8.5], [0, 1, 8]),
  129. ("backfill", None, [0.2, 1.8, 8.5], [1, 2, 9]),
  130. ("nearest", None, [0.2, 1.8, 8.5], [0, 2, 9]),
  131. ("pad", 1, [0.2, 1.8, 8.5], [0, 1, 8]),
  132. ("backfill", 1, [0.2, 1.8, 8.5], [1, 2, 9]),
  133. ("nearest", 1, [0.2, 1.8, 8.5], [0, 2, 9]),
  134. ("pad", 0.2, [0.2, 1.8, 8.5], [0, -1, -1]),
  135. ("backfill", 0.2, [0.2, 1.8, 8.5], [-1, 2, -1]),
  136. ("nearest", 0.2, [0.2, 1.8, 8.5], [0, 2, -1]),
  137. ],
  138. )
  139. def test_get_indexer_nearest(self, method, tolerance, indexer, expected):
  140. index = Index(np.arange(10))
  141. actual = index.get_indexer(indexer, method=method, tolerance=tolerance)
  142. tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
  143. @pytest.mark.parametrize("listtype", [list, tuple, Series, np.array])
  144. @pytest.mark.parametrize(
  145. "tolerance, expected",
  146. list(
  147. zip(
  148. [[0.3, 0.3, 0.1], [0.2, 0.1, 0.1], [0.1, 0.5, 0.5]],
  149. [[0, 2, -1], [0, -1, -1], [-1, 2, 9]],
  150. )
  151. ),
  152. )
  153. def test_get_indexer_nearest_listlike_tolerance(
  154. self, tolerance, expected, listtype
  155. ):
  156. index = Index(np.arange(10))
  157. actual = index.get_indexer(
  158. [0.2, 1.8, 8.5], method="nearest", tolerance=listtype(tolerance)
  159. )
  160. tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
  161. def test_get_indexer_nearest_error(self):
  162. index = Index(np.arange(10))
  163. with pytest.raises(ValueError, match="limit argument"):
  164. index.get_indexer([1, 0], method="nearest", limit=1)
  165. with pytest.raises(ValueError, match="tolerance size must match"):
  166. index.get_indexer([1, 0], method="nearest", tolerance=[1, 2, 3])
  167. @pytest.mark.parametrize(
  168. "method,expected",
  169. [("pad", [8, 7, 0]), ("backfill", [9, 8, 1]), ("nearest", [9, 7, 0])],
  170. )
  171. def test_get_indexer_nearest_decreasing(self, method, expected):
  172. index = Index(np.arange(10))[::-1]
  173. actual = index.get_indexer([0, 5, 9], method=method)
  174. tm.assert_numpy_array_equal(actual, np.array([9, 4, 0], dtype=np.intp))
  175. actual = index.get_indexer([0.2, 1.8, 8.5], method=method)
  176. tm.assert_numpy_array_equal(actual, np.array(expected, dtype=np.intp))
  177. @pytest.mark.parametrize("idx_dtype", ["int64", "float64", "uint64", "range"])
  178. @pytest.mark.parametrize("method", ["get_indexer", "get_indexer_non_unique"])
  179. def test_get_indexer_numeric_index_boolean_target(self, method, idx_dtype):
  180. # GH 16877
  181. if idx_dtype == "range":
  182. numeric_index = RangeIndex(4)
  183. else:
  184. numeric_index = Index(np.arange(4, dtype=idx_dtype))
  185. other = Index([True, False, True])
  186. result = getattr(numeric_index, method)(other)
  187. expected = np.array([-1, -1, -1], dtype=np.intp)
  188. if method == "get_indexer":
  189. tm.assert_numpy_array_equal(result, expected)
  190. else:
  191. missing = np.arange(3, dtype=np.intp)
  192. tm.assert_numpy_array_equal(result[0], expected)
  193. tm.assert_numpy_array_equal(result[1], missing)
  194. @pytest.mark.parametrize("method", ["pad", "backfill", "nearest"])
  195. def test_get_indexer_with_method_numeric_vs_bool(self, method):
  196. left = Index([1, 2, 3])
  197. right = Index([True, False])
  198. with pytest.raises(TypeError, match="Cannot compare"):
  199. left.get_indexer(right, method=method)
  200. with pytest.raises(TypeError, match="Cannot compare"):
  201. right.get_indexer(left, method=method)
  202. def test_get_indexer_numeric_vs_bool(self):
  203. left = Index([1, 2, 3])
  204. right = Index([True, False])
  205. res = left.get_indexer(right)
  206. expected = -1 * np.ones(len(right), dtype=np.intp)
  207. tm.assert_numpy_array_equal(res, expected)
  208. res = right.get_indexer(left)
  209. expected = -1 * np.ones(len(left), dtype=np.intp)
  210. tm.assert_numpy_array_equal(res, expected)
  211. res = left.get_indexer_non_unique(right)[0]
  212. expected = -1 * np.ones(len(right), dtype=np.intp)
  213. tm.assert_numpy_array_equal(res, expected)
  214. res = right.get_indexer_non_unique(left)[0]
  215. expected = -1 * np.ones(len(left), dtype=np.intp)
  216. tm.assert_numpy_array_equal(res, expected)
  217. def test_get_indexer_float64(self):
  218. idx = Index([0.0, 1.0, 2.0], dtype=np.float64)
  219. tm.assert_numpy_array_equal(
  220. idx.get_indexer(idx), np.array([0, 1, 2], dtype=np.intp)
  221. )
  222. target = [-0.1, 0.5, 1.1]
  223. tm.assert_numpy_array_equal(
  224. idx.get_indexer(target, "pad"), np.array([-1, 0, 1], dtype=np.intp)
  225. )
  226. tm.assert_numpy_array_equal(
  227. idx.get_indexer(target, "backfill"), np.array([0, 1, 2], dtype=np.intp)
  228. )
  229. tm.assert_numpy_array_equal(
  230. idx.get_indexer(target, "nearest"), np.array([0, 1, 1], dtype=np.intp)
  231. )
  232. def test_get_indexer_nan(self):
  233. # GH#7820
  234. result = Index([1, 2, np.nan], dtype=np.float64).get_indexer([np.nan])
  235. expected = np.array([2], dtype=np.intp)
  236. tm.assert_numpy_array_equal(result, expected)
  237. def test_get_indexer_int64(self):
  238. index = Index(range(0, 20, 2), dtype=np.int64)
  239. target = Index(np.arange(10), dtype=np.int64)
  240. indexer = index.get_indexer(target)
  241. expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp)
  242. tm.assert_numpy_array_equal(indexer, expected)
  243. target = Index(np.arange(10), dtype=np.int64)
  244. indexer = index.get_indexer(target, method="pad")
  245. expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp)
  246. tm.assert_numpy_array_equal(indexer, expected)
  247. target = Index(np.arange(10), dtype=np.int64)
  248. indexer = index.get_indexer(target, method="backfill")
  249. expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp)
  250. tm.assert_numpy_array_equal(indexer, expected)
  251. def test_get_indexer_uint64(self, index_large):
  252. target = Index(np.arange(10).astype("uint64") * 5 + 2**63)
  253. indexer = index_large.get_indexer(target)
  254. expected = np.array([0, -1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp)
  255. tm.assert_numpy_array_equal(indexer, expected)
  256. target = Index(np.arange(10).astype("uint64") * 5 + 2**63)
  257. indexer = index_large.get_indexer(target, method="pad")
  258. expected = np.array([0, 0, 1, 2, 3, 4, 4, 4, 4, 4], dtype=np.intp)
  259. tm.assert_numpy_array_equal(indexer, expected)
  260. target = Index(np.arange(10).astype("uint64") * 5 + 2**63)
  261. indexer = index_large.get_indexer(target, method="backfill")
  262. expected = np.array([0, 1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp)
  263. tm.assert_numpy_array_equal(indexer, expected)
  264. @pytest.mark.parametrize("val, val2", [(4, 5), (4, 4), (4, NA), (NA, NA)])
  265. def test_get_loc_masked(self, val, val2, any_numeric_ea_and_arrow_dtype):
  266. # GH#39133
  267. idx = Index([1, 2, 3, val, val2], dtype=any_numeric_ea_and_arrow_dtype)
  268. result = idx.get_loc(2)
  269. assert result == 1
  270. with pytest.raises(KeyError, match="9"):
  271. idx.get_loc(9)
  272. def test_get_loc_masked_na(self, any_numeric_ea_and_arrow_dtype):
  273. # GH#39133
  274. idx = Index([1, 2, NA], dtype=any_numeric_ea_and_arrow_dtype)
  275. result = idx.get_loc(NA)
  276. assert result == 2
  277. idx = Index([1, 2, NA, NA], dtype=any_numeric_ea_and_arrow_dtype)
  278. result = idx.get_loc(NA)
  279. tm.assert_numpy_array_equal(result, np.array([False, False, True, True]))
  280. idx = Index([1, 2, 3], dtype=any_numeric_ea_and_arrow_dtype)
  281. with pytest.raises(KeyError, match="NA"):
  282. idx.get_loc(NA)
  283. def test_get_loc_masked_na_and_nan(self):
  284. # GH#39133
  285. idx = Index(
  286. FloatingArray(
  287. np.array([1, 2, 1, np.nan]), mask=np.array([False, False, True, False])
  288. )
  289. )
  290. result = idx.get_loc(NA)
  291. assert result == 2
  292. result = idx.get_loc(np.nan)
  293. assert result == 3
  294. idx = Index(
  295. FloatingArray(np.array([1, 2, 1.0]), mask=np.array([False, False, True]))
  296. )
  297. result = idx.get_loc(NA)
  298. assert result == 2
  299. with pytest.raises(KeyError, match="nan"):
  300. idx.get_loc(np.nan)
  301. idx = Index(
  302. FloatingArray(
  303. np.array([1, 2, np.nan]), mask=np.array([False, False, False])
  304. )
  305. )
  306. result = idx.get_loc(np.nan)
  307. assert result == 2
  308. with pytest.raises(KeyError, match="NA"):
  309. idx.get_loc(NA)
  310. @pytest.mark.parametrize("val", [4, 2])
  311. def test_get_indexer_masked_na(self, any_numeric_ea_and_arrow_dtype, val):
  312. # GH#39133
  313. idx = Index([1, 2, NA, 3, val], dtype=any_numeric_ea_and_arrow_dtype)
  314. result = idx.get_indexer_for([1, NA, 5])
  315. expected = np.array([0, 2, -1])
  316. tm.assert_numpy_array_equal(result, expected, check_dtype=False)
  317. @pytest.mark.parametrize("dtype", ["boolean", "bool[pyarrow]"])
  318. def test_get_indexer_masked_na_boolean(self, dtype):
  319. # GH#39133
  320. if dtype == "bool[pyarrow]":
  321. pytest.importorskip("pyarrow")
  322. idx = Index([True, False, NA], dtype=dtype)
  323. result = idx.get_loc(False)
  324. assert result == 1
  325. result = idx.get_loc(NA)
  326. assert result == 2
  327. def test_get_indexer_arrow_dictionary_target(self):
  328. pa = pytest.importorskip("pyarrow")
  329. target = Index(
  330. ArrowExtensionArray(
  331. pa.array([1, 2], type=pa.dictionary(pa.int8(), pa.int8()))
  332. )
  333. )
  334. idx = Index([1])
  335. result = idx.get_indexer(target)
  336. expected = np.array([0, -1], dtype=np.int64)
  337. tm.assert_numpy_array_equal(result, expected)
  338. result_1, result_2 = idx.get_indexer_non_unique(target)
  339. expected_1, expected_2 = np.array([0, -1], dtype=np.int64), np.array(
  340. [1], dtype=np.int64
  341. )
  342. tm.assert_numpy_array_equal(result_1, expected_1)
  343. tm.assert_numpy_array_equal(result_2, expected_2)
  344. class TestWhere:
  345. @pytest.mark.parametrize(
  346. "index",
  347. [
  348. Index(np.arange(5, dtype="float64")),
  349. Index(range(0, 20, 2), dtype=np.int64),
  350. Index(np.arange(5, dtype="uint64")),
  351. ],
  352. )
  353. def test_where(self, listlike_box, index):
  354. cond = [True] * len(index)
  355. expected = index
  356. result = index.where(listlike_box(cond))
  357. cond = [False] + [True] * (len(index) - 1)
  358. expected = Index([index._na_value] + index[1:].tolist(), dtype=np.float64)
  359. result = index.where(listlike_box(cond))
  360. tm.assert_index_equal(result, expected)
  361. def test_where_uint64(self):
  362. idx = Index([0, 6, 2], dtype=np.uint64)
  363. mask = np.array([False, True, False])
  364. other = np.array([1], dtype=np.int64)
  365. expected = Index([1, 6, 1], dtype=np.uint64)
  366. result = idx.where(mask, other)
  367. tm.assert_index_equal(result, expected)
  368. result = idx.putmask(~mask, other)
  369. tm.assert_index_equal(result, expected)
  370. def test_where_infers_type_instead_of_trying_to_convert_string_to_float(self):
  371. # GH 32413
  372. index = Index([1, np.nan])
  373. cond = index.notna()
  374. other = Index(["a", "b"], dtype="string")
  375. expected = Index([1.0, "b"])
  376. result = index.where(cond, other)
  377. tm.assert_index_equal(result, expected)
  378. class TestTake:
  379. @pytest.mark.parametrize("idx_dtype", [np.float64, np.int64, np.uint64])
  380. def test_take_preserve_name(self, idx_dtype):
  381. index = Index([1, 2, 3, 4], dtype=idx_dtype, name="foo")
  382. taken = index.take([3, 0, 1])
  383. assert index.name == taken.name
  384. def test_take_fill_value_float64(self):
  385. # GH 12631
  386. idx = Index([1.0, 2.0, 3.0], name="xxx", dtype=np.float64)
  387. result = idx.take(np.array([1, 0, -1]))
  388. expected = Index([2.0, 1.0, 3.0], dtype=np.float64, name="xxx")
  389. tm.assert_index_equal(result, expected)
  390. # fill_value
  391. result = idx.take(np.array([1, 0, -1]), fill_value=True)
  392. expected = Index([2.0, 1.0, np.nan], dtype=np.float64, name="xxx")
  393. tm.assert_index_equal(result, expected)
  394. # allow_fill=False
  395. result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
  396. expected = Index([2.0, 1.0, 3.0], dtype=np.float64, name="xxx")
  397. tm.assert_index_equal(result, expected)
  398. msg = (
  399. "When allow_fill=True and fill_value is not None, "
  400. "all indices must be >= -1"
  401. )
  402. with pytest.raises(ValueError, match=msg):
  403. idx.take(np.array([1, 0, -2]), fill_value=True)
  404. with pytest.raises(ValueError, match=msg):
  405. idx.take(np.array([1, 0, -5]), fill_value=True)
  406. msg = "index -5 is out of bounds for (axis 0 with )?size 3"
  407. with pytest.raises(IndexError, match=msg):
  408. idx.take(np.array([1, -5]))
  409. @pytest.mark.parametrize("dtype", [np.int64, np.uint64])
  410. def test_take_fill_value_ints(self, dtype):
  411. # see gh-12631
  412. idx = Index([1, 2, 3], dtype=dtype, name="xxx")
  413. result = idx.take(np.array([1, 0, -1]))
  414. expected = Index([2, 1, 3], dtype=dtype, name="xxx")
  415. tm.assert_index_equal(result, expected)
  416. name = type(idx).__name__
  417. msg = f"Unable to fill values because {name} cannot contain NA"
  418. # fill_value=True
  419. with pytest.raises(ValueError, match=msg):
  420. idx.take(np.array([1, 0, -1]), fill_value=True)
  421. # allow_fill=False
  422. result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
  423. expected = Index([2, 1, 3], dtype=dtype, name="xxx")
  424. tm.assert_index_equal(result, expected)
  425. with pytest.raises(ValueError, match=msg):
  426. idx.take(np.array([1, 0, -2]), fill_value=True)
  427. with pytest.raises(ValueError, match=msg):
  428. idx.take(np.array([1, 0, -5]), fill_value=True)
  429. msg = "index -5 is out of bounds for (axis 0 with )?size 3"
  430. with pytest.raises(IndexError, match=msg):
  431. idx.take(np.array([1, -5]))
  432. class TestContains:
  433. @pytest.mark.parametrize("dtype", [np.float64, np.int64, np.uint64])
  434. def test_contains_none(self, dtype):
  435. # GH#35788 should return False, not raise TypeError
  436. index = Index([0, 1, 2, 3, 4], dtype=dtype)
  437. assert None not in index
  438. def test_contains_float64_nans(self):
  439. index = Index([1.0, 2.0, np.nan], dtype=np.float64)
  440. assert np.nan in index
  441. def test_contains_float64_not_nans(self):
  442. index = Index([1.0, 2.0, np.nan], dtype=np.float64)
  443. assert 1.0 in index
  444. class TestSliceLocs:
  445. @pytest.mark.parametrize("dtype", [int, float])
  446. def test_slice_locs(self, dtype):
  447. index = Index(np.array([0, 1, 2, 5, 6, 7, 9, 10], dtype=dtype))
  448. n = len(index)
  449. assert index.slice_locs(start=2) == (2, n)
  450. assert index.slice_locs(start=3) == (3, n)
  451. assert index.slice_locs(3, 8) == (3, 6)
  452. assert index.slice_locs(5, 10) == (3, n)
  453. assert index.slice_locs(end=8) == (0, 6)
  454. assert index.slice_locs(end=9) == (0, 7)
  455. # reversed
  456. index2 = index[::-1]
  457. assert index2.slice_locs(8, 2) == (2, 6)
  458. assert index2.slice_locs(7, 3) == (2, 5)
  459. @pytest.mark.parametrize("dtype", [int, float])
  460. def test_slice_locs_float_locs(self, dtype):
  461. index = Index(np.array([0, 1, 2, 5, 6, 7, 9, 10], dtype=dtype))
  462. n = len(index)
  463. assert index.slice_locs(5.0, 10.0) == (3, n)
  464. assert index.slice_locs(4.5, 10.5) == (3, 8)
  465. index2 = index[::-1]
  466. assert index2.slice_locs(8.5, 1.5) == (2, 6)
  467. assert index2.slice_locs(10.5, -1) == (0, n)
  468. @pytest.mark.parametrize("dtype", [int, float])
  469. def test_slice_locs_dup_numeric(self, dtype):
  470. index = Index(np.array([10, 12, 12, 14], dtype=dtype))
  471. assert index.slice_locs(12, 12) == (1, 3)
  472. assert index.slice_locs(11, 13) == (1, 3)
  473. index2 = index[::-1]
  474. assert index2.slice_locs(12, 12) == (1, 3)
  475. assert index2.slice_locs(13, 11) == (1, 3)
  476. def test_slice_locs_na(self):
  477. index = Index([np.nan, 1, 2])
  478. assert index.slice_locs(1) == (1, 3)
  479. assert index.slice_locs(np.nan) == (0, 3)
  480. index = Index([0, np.nan, np.nan, 1, 2])
  481. assert index.slice_locs(np.nan) == (1, 5)
  482. def test_slice_locs_na_raises(self):
  483. index = Index([np.nan, 1, 2])
  484. with pytest.raises(KeyError, match=""):
  485. index.slice_locs(start=1.5)
  486. with pytest.raises(KeyError, match=""):
  487. index.slice_locs(end=1.5)
  488. class TestGetSliceBounds:
  489. @pytest.mark.parametrize("side, expected", [("left", 4), ("right", 5)])
  490. def test_get_slice_bounds_within(self, side, expected):
  491. index = Index(range(6))
  492. result = index.get_slice_bound(4, side=side)
  493. assert result == expected
  494. @pytest.mark.parametrize("side", ["left", "right"])
  495. @pytest.mark.parametrize("bound, expected", [(-1, 0), (10, 6)])
  496. def test_get_slice_bounds_outside(self, side, expected, bound):
  497. index = Index(range(6))
  498. result = index.get_slice_bound(bound, side=side)
  499. assert result == expected