123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- """Tests for Interval-Interval operations, such as overlaps, contains, etc."""
- import pytest
- from pandas import (
- Interval,
- Timedelta,
- Timestamp,
- )
- @pytest.fixture(
- params=[
- (Timedelta("0 days"), Timedelta("1 day")),
- (Timestamp("2018-01-01"), Timedelta("1 day")),
- (0, 1),
- ],
- ids=lambda x: type(x[0]).__name__,
- )
- def start_shift(request):
- """
- Fixture for generating intervals of types from a start value and a shift
- value that can be added to start to generate an endpoint
- """
- return request.param
- class TestOverlaps:
- def test_overlaps_self(self, start_shift, closed):
- start, shift = start_shift
- interval = Interval(start, start + shift, closed)
- assert interval.overlaps(interval)
- def test_overlaps_nested(self, start_shift, closed, other_closed):
- start, shift = start_shift
- interval1 = Interval(start, start + 3 * shift, other_closed)
- interval2 = Interval(start + shift, start + 2 * shift, closed)
- # nested intervals should always overlap
- assert interval1.overlaps(interval2)
- def test_overlaps_disjoint(self, start_shift, closed, other_closed):
- start, shift = start_shift
- interval1 = Interval(start, start + shift, other_closed)
- interval2 = Interval(start + 2 * shift, start + 3 * shift, closed)
- # disjoint intervals should never overlap
- assert not interval1.overlaps(interval2)
- def test_overlaps_endpoint(self, start_shift, closed, other_closed):
- start, shift = start_shift
- interval1 = Interval(start, start + shift, other_closed)
- interval2 = Interval(start + shift, start + 2 * shift, closed)
- # overlap if shared endpoint is closed for both (overlap at a point)
- result = interval1.overlaps(interval2)
- expected = interval1.closed_right and interval2.closed_left
- assert result == expected
- @pytest.mark.parametrize(
- "other",
- [10, True, "foo", Timedelta("1 day"), Timestamp("2018-01-01")],
- ids=lambda x: type(x).__name__,
- )
- def test_overlaps_invalid_type(self, other):
- interval = Interval(0, 1)
- msg = f"`other` must be an Interval, got {type(other).__name__}"
- with pytest.raises(TypeError, match=msg):
- interval.overlaps(other)
- class TestContains:
- def test_contains_interval(self, inclusive_endpoints_fixture):
- interval1 = Interval(0, 1, "both")
- interval2 = Interval(0, 1, inclusive_endpoints_fixture)
- assert interval1 in interval1
- assert interval2 in interval2
- assert interval2 in interval1
- assert interval1 not in interval2 or inclusive_endpoints_fixture == "both"
- def test_contains_infinite_length(self):
- interval1 = Interval(0, 1, "both")
- interval2 = Interval(float("-inf"), float("inf"), "neither")
- assert interval1 in interval2
- assert interval2 not in interval1
- def test_contains_zero_length(self):
- interval1 = Interval(0, 1, "both")
- interval2 = Interval(-1, -1, "both")
- interval3 = Interval(0.5, 0.5, "both")
- assert interval2 not in interval1
- assert interval3 in interval1
- assert interval2 not in interval3 and interval3 not in interval2
- assert interval1 not in interval2 and interval1 not in interval3
- @pytest.mark.parametrize(
- "type1",
- [
- (0, 1),
- (Timestamp(2000, 1, 1, 0), Timestamp(2000, 1, 1, 1)),
- (Timedelta("0h"), Timedelta("1h")),
- ],
- )
- @pytest.mark.parametrize(
- "type2",
- [
- (0, 1),
- (Timestamp(2000, 1, 1, 0), Timestamp(2000, 1, 1, 1)),
- (Timedelta("0h"), Timedelta("1h")),
- ],
- )
- def test_contains_mixed_types(self, type1, type2):
- interval1 = Interval(*type1)
- interval2 = Interval(*type2)
- if type1 == type2:
- assert interval1 in interval2
- else:
- msg = "^'<=' not supported between instances of"
- with pytest.raises(TypeError, match=msg):
- interval1 in interval2
|