test_ops.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """Tests for Interval-Interval operations, such as overlaps, contains, etc."""
  2. import numpy as np
  3. import pytest
  4. from pandas import (
  5. Interval,
  6. IntervalIndex,
  7. Timedelta,
  8. Timestamp,
  9. )
  10. import pandas._testing as tm
  11. from pandas.core.arrays import IntervalArray
  12. @pytest.fixture(params=[IntervalArray, IntervalIndex])
  13. def constructor(request):
  14. """
  15. Fixture for testing both interval container classes.
  16. """
  17. return request.param
  18. @pytest.fixture(
  19. params=[
  20. (Timedelta("0 days"), Timedelta("1 day")),
  21. (Timestamp("2018-01-01"), Timedelta("1 day")),
  22. (0, 1),
  23. ],
  24. ids=lambda x: type(x[0]).__name__,
  25. )
  26. def start_shift(request):
  27. """
  28. Fixture for generating intervals of different types from a start value
  29. and a shift value that can be added to start to generate an endpoint.
  30. """
  31. return request.param
  32. class TestOverlaps:
  33. def test_overlaps_interval(self, constructor, start_shift, closed, other_closed):
  34. start, shift = start_shift
  35. interval = Interval(start, start + 3 * shift, other_closed)
  36. # intervals: identical, nested, spanning, partial, adjacent, disjoint
  37. tuples = [
  38. (start, start + 3 * shift),
  39. (start + shift, start + 2 * shift),
  40. (start - shift, start + 4 * shift),
  41. (start + 2 * shift, start + 4 * shift),
  42. (start + 3 * shift, start + 4 * shift),
  43. (start + 4 * shift, start + 5 * shift),
  44. ]
  45. interval_container = constructor.from_tuples(tuples, closed)
  46. adjacent = interval.closed_right and interval_container.closed_left
  47. expected = np.array([True, True, True, True, adjacent, False])
  48. result = interval_container.overlaps(interval)
  49. tm.assert_numpy_array_equal(result, expected)
  50. @pytest.mark.parametrize("other_constructor", [IntervalArray, IntervalIndex])
  51. def test_overlaps_interval_container(self, constructor, other_constructor):
  52. # TODO: modify this test when implemented
  53. interval_container = constructor.from_breaks(range(5))
  54. other_container = other_constructor.from_breaks(range(5))
  55. with pytest.raises(NotImplementedError, match="^$"):
  56. interval_container.overlaps(other_container)
  57. def test_overlaps_na(self, constructor, start_shift):
  58. """NA values are marked as False"""
  59. start, shift = start_shift
  60. interval = Interval(start, start + shift)
  61. tuples = [
  62. (start, start + shift),
  63. np.nan,
  64. (start + 2 * shift, start + 3 * shift),
  65. ]
  66. interval_container = constructor.from_tuples(tuples)
  67. expected = np.array([True, False, False])
  68. result = interval_container.overlaps(interval)
  69. tm.assert_numpy_array_equal(result, expected)
  70. @pytest.mark.parametrize(
  71. "other",
  72. [10, True, "foo", Timedelta("1 day"), Timestamp("2018-01-01")],
  73. ids=lambda x: type(x).__name__,
  74. )
  75. def test_overlaps_invalid_type(self, constructor, other):
  76. interval_container = constructor.from_breaks(range(5))
  77. msg = f"`other` must be Interval-like, got {type(other).__name__}"
  78. with pytest.raises(TypeError, match=msg):
  79. interval_container.overlaps(other)