test_ops.py 3.2 KB

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