done
This commit is contained in:
		| @ -0,0 +1,192 @@ | ||||
| from datetime import timedelta | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Interval, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestIntervalArithmetic: | ||||
|     def test_interval_add(self, closed): | ||||
|         interval = Interval(0, 1, closed=closed) | ||||
|         expected = Interval(1, 2, closed=closed) | ||||
|  | ||||
|         result = interval + 1 | ||||
|         assert result == expected | ||||
|  | ||||
|         result = 1 + interval | ||||
|         assert result == expected | ||||
|  | ||||
|         result = interval | ||||
|         result += 1 | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for \+" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval + interval | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval + "foo" | ||||
|  | ||||
|     def test_interval_sub(self, closed): | ||||
|         interval = Interval(0, 1, closed=closed) | ||||
|         expected = Interval(-1, 0, closed=closed) | ||||
|  | ||||
|         result = interval - 1 | ||||
|         assert result == expected | ||||
|  | ||||
|         result = interval | ||||
|         result -= 1 | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for -" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval - interval | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval - "foo" | ||||
|  | ||||
|     def test_interval_mult(self, closed): | ||||
|         interval = Interval(0, 1, closed=closed) | ||||
|         expected = Interval(0, 2, closed=closed) | ||||
|  | ||||
|         result = interval * 2 | ||||
|         assert result == expected | ||||
|  | ||||
|         result = 2 * interval | ||||
|         assert result == expected | ||||
|  | ||||
|         result = interval | ||||
|         result *= 2 | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for \*" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval * interval | ||||
|  | ||||
|         msg = r"can\'t multiply sequence by non-int" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval * "foo" | ||||
|  | ||||
|     def test_interval_div(self, closed): | ||||
|         interval = Interval(0, 1, closed=closed) | ||||
|         expected = Interval(0, 0.5, closed=closed) | ||||
|  | ||||
|         result = interval / 2.0 | ||||
|         assert result == expected | ||||
|  | ||||
|         result = interval | ||||
|         result /= 2.0 | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for /" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval / interval | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval / "foo" | ||||
|  | ||||
|     def test_interval_floordiv(self, closed): | ||||
|         interval = Interval(1, 2, closed=closed) | ||||
|         expected = Interval(0, 1, closed=closed) | ||||
|  | ||||
|         result = interval // 2 | ||||
|         assert result == expected | ||||
|  | ||||
|         result = interval | ||||
|         result //= 2 | ||||
|         assert result == expected | ||||
|  | ||||
|         msg = r"unsupported operand type\(s\) for //" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval // interval | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             interval // "foo" | ||||
|  | ||||
|     @pytest.mark.parametrize("method", ["__add__", "__sub__"]) | ||||
|     @pytest.mark.parametrize( | ||||
|         "interval", | ||||
|         [ | ||||
|             Interval( | ||||
|                 Timestamp("2017-01-01 00:00:00"), Timestamp("2018-01-01 00:00:00") | ||||
|             ), | ||||
|             Interval(Timedelta(days=7), Timedelta(days=14)), | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize( | ||||
|         "delta", [Timedelta(days=7), timedelta(7), np.timedelta64(7, "D")] | ||||
|     ) | ||||
|     def test_time_interval_add_subtract_timedelta(self, interval, delta, method): | ||||
|         # https://github.com/pandas-dev/pandas/issues/32023 | ||||
|         result = getattr(interval, method)(delta) | ||||
|         left = getattr(interval.left, method)(delta) | ||||
|         right = getattr(interval.right, method)(delta) | ||||
|         expected = Interval(left, right) | ||||
|  | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize("interval", [Interval(1, 2), Interval(1.0, 2.0)]) | ||||
|     @pytest.mark.parametrize( | ||||
|         "delta", [Timedelta(days=7), timedelta(7), np.timedelta64(7, "D")] | ||||
|     ) | ||||
|     def test_numeric_interval_add_timedelta_raises(self, interval, delta): | ||||
|         # https://github.com/pandas-dev/pandas/issues/32023 | ||||
|         msg = "|".join( | ||||
|             [ | ||||
|                 "unsupported operand", | ||||
|                 "cannot use operands", | ||||
|                 "Only numeric, Timestamp and Timedelta endpoints are allowed", | ||||
|             ] | ||||
|         ) | ||||
|         with pytest.raises((TypeError, ValueError), match=msg): | ||||
|             interval + delta | ||||
|  | ||||
|         with pytest.raises((TypeError, ValueError), match=msg): | ||||
|             delta + interval | ||||
|  | ||||
|     @pytest.mark.parametrize("klass", [timedelta, np.timedelta64, Timedelta]) | ||||
|     def test_timedelta_add_timestamp_interval(self, klass): | ||||
|         delta = klass(0) | ||||
|         expected = Interval(Timestamp("2020-01-01"), Timestamp("2020-02-01")) | ||||
|  | ||||
|         result = delta + expected | ||||
|         assert result == expected | ||||
|  | ||||
|         result = expected + delta | ||||
|         assert result == expected | ||||
|  | ||||
|  | ||||
| class TestIntervalComparisons: | ||||
|     def test_interval_equal(self): | ||||
|         assert Interval(0, 1) == Interval(0, 1, closed="right") | ||||
|         assert Interval(0, 1) != Interval(0, 1, closed="left") | ||||
|         assert Interval(0, 1) != 0 | ||||
|  | ||||
|     def test_interval_comparison(self): | ||||
|         msg = ( | ||||
|             "'<' not supported between instances of " | ||||
|             "'pandas._libs.interval.Interval' and 'int'" | ||||
|         ) | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             Interval(0, 1) < 2 | ||||
|  | ||||
|         assert Interval(0, 1) < Interval(1, 2) | ||||
|         assert Interval(0, 1) < Interval(0, 2) | ||||
|         assert Interval(0, 1) < Interval(0.5, 1.5) | ||||
|         assert Interval(0, 1) <= Interval(0, 1) | ||||
|         assert Interval(0, 1) > Interval(-1, 2) | ||||
|         assert Interval(0, 1) >= Interval(0, 1) | ||||
|  | ||||
|     def test_equality_comparison_broadcasts_over_array(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/35931 | ||||
|         interval = Interval(0, 1) | ||||
|         arr = np.array([interval, interval]) | ||||
|         result = interval == arr | ||||
|         expected = np.array([True, True]) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
| @ -0,0 +1,51 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Interval, | ||||
|     Period, | ||||
|     Timestamp, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class TestIntervalConstructors: | ||||
|     @pytest.mark.parametrize( | ||||
|         "left, right", | ||||
|         [ | ||||
|             ("a", "z"), | ||||
|             (("a", "b"), ("c", "d")), | ||||
|             (list("AB"), list("ab")), | ||||
|             (Interval(0, 1), Interval(1, 2)), | ||||
|             (Period("2018Q1", freq="Q"), Period("2018Q1", freq="Q")), | ||||
|         ], | ||||
|     ) | ||||
|     def test_construct_errors(self, left, right): | ||||
|         # GH#23013 | ||||
|         msg = "Only numeric, Timestamp and Timedelta endpoints are allowed" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             Interval(left, right) | ||||
|  | ||||
|     def test_constructor_errors(self): | ||||
|         msg = "invalid option for 'closed': foo" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             Interval(0, 1, closed="foo") | ||||
|  | ||||
|         msg = "left side of interval must be <= right side" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             Interval(1, 0) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "tz_left, tz_right", [(None, "UTC"), ("UTC", None), ("UTC", "US/Eastern")] | ||||
|     ) | ||||
|     def test_constructor_errors_tz(self, tz_left, tz_right): | ||||
|         # GH#18538 | ||||
|         left = Timestamp("2017-01-01", tz=tz_left) | ||||
|         right = Timestamp("2017-01-02", tz=tz_right) | ||||
|  | ||||
|         if tz_left is None or tz_right is None: | ||||
|             error = TypeError | ||||
|             msg = "Cannot compare tz-naive and tz-aware timestamps" | ||||
|         else: | ||||
|             error = ValueError | ||||
|             msg = "left and right must have the same time zone" | ||||
|         with pytest.raises(error, match=msg): | ||||
|             Interval(left, right) | ||||
| @ -0,0 +1,73 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Interval, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class TestContains: | ||||
|     def test_contains(self): | ||||
|         interval = Interval(0, 1) | ||||
|         assert 0.5 in interval | ||||
|         assert 1 in interval | ||||
|         assert 0 not in interval | ||||
|  | ||||
|         interval_both = Interval(0, 1, "both") | ||||
|         assert 0 in interval_both | ||||
|         assert 1 in interval_both | ||||
|  | ||||
|         interval_neither = Interval(0, 1, closed="neither") | ||||
|         assert 0 not in interval_neither | ||||
|         assert 0.5 in interval_neither | ||||
|         assert 1 not in interval_neither | ||||
|  | ||||
|     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 | ||||
| @ -0,0 +1,11 @@ | ||||
| from pandas import Interval | ||||
|  | ||||
|  | ||||
| def test_interval_repr(): | ||||
|     interval = Interval(0, 1) | ||||
|     assert repr(interval) == "Interval(0, 1, closed='right')" | ||||
|     assert str(interval) == "(0, 1]" | ||||
|  | ||||
|     interval_left = Interval(0, 1, closed="left") | ||||
|     assert repr(interval_left) == "Interval(0, 1, closed='left')" | ||||
|     assert str(interval_left) == "[0, 1)" | ||||
| @ -0,0 +1,87 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Interval, | ||||
|     Timedelta, | ||||
|     Timestamp, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @pytest.fixture | ||||
| def interval(): | ||||
|     return Interval(0, 1) | ||||
|  | ||||
|  | ||||
| class TestInterval: | ||||
|     def test_properties(self, interval): | ||||
|         assert interval.closed == "right" | ||||
|         assert interval.left == 0 | ||||
|         assert interval.right == 1 | ||||
|         assert interval.mid == 0.5 | ||||
|  | ||||
|     def test_hash(self, interval): | ||||
|         # should not raise | ||||
|         hash(interval) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "left, right, expected", | ||||
|         [ | ||||
|             (0, 5, 5), | ||||
|             (-2, 5.5, 7.5), | ||||
|             (10, 10, 0), | ||||
|             (10, np.inf, np.inf), | ||||
|             (-np.inf, -5, np.inf), | ||||
|             (-np.inf, np.inf, np.inf), | ||||
|             (Timedelta("0 days"), Timedelta("5 days"), Timedelta("5 days")), | ||||
|             (Timedelta("10 days"), Timedelta("10 days"), Timedelta("0 days")), | ||||
|             (Timedelta("1h10min"), Timedelta("5h5min"), Timedelta("3h55min")), | ||||
|             (Timedelta("5s"), Timedelta("1h"), Timedelta("59min55s")), | ||||
|         ], | ||||
|     ) | ||||
|     def test_length(self, left, right, expected): | ||||
|         # GH 18789 | ||||
|         iv = Interval(left, right) | ||||
|         result = iv.length | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "left, right, expected", | ||||
|         [ | ||||
|             ("2017-01-01", "2017-01-06", "5 days"), | ||||
|             ("2017-01-01", "2017-01-01 12:00:00", "12 hours"), | ||||
|             ("2017-01-01 12:00", "2017-01-01 12:00:00", "0 days"), | ||||
|             ("2017-01-01 12:01", "2017-01-05 17:31:00", "4 days 5 hours 30 min"), | ||||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.parametrize("tz", (None, "UTC", "CET", "US/Eastern")) | ||||
|     def test_length_timestamp(self, tz, left, right, expected): | ||||
|         # GH 18789 | ||||
|         iv = Interval(Timestamp(left, tz=tz), Timestamp(right, tz=tz)) | ||||
|         result = iv.length | ||||
|         expected = Timedelta(expected) | ||||
|         assert result == expected | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "left, right", | ||||
|         [ | ||||
|             (0, 1), | ||||
|             (Timedelta("0 days"), Timedelta("1 day")), | ||||
|             (Timestamp("2018-01-01"), Timestamp("2018-01-02")), | ||||
|             ( | ||||
|                 Timestamp("2018-01-01", tz="US/Eastern"), | ||||
|                 Timestamp("2018-01-02", tz="US/Eastern"), | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_is_empty(self, left, right, closed): | ||||
|         # GH27219 | ||||
|         # non-empty always return False | ||||
|         iv = Interval(left, right, closed) | ||||
|         assert iv.is_empty is False | ||||
|  | ||||
|         # same endpoint is empty except when closed='both' (contains one point) | ||||
|         iv = Interval(left, left, closed) | ||||
|         result = iv.is_empty | ||||
|         expected = closed != "both" | ||||
|         assert result is expected | ||||
| @ -0,0 +1,67 @@ | ||||
| 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) | ||||
		Reference in New Issue
	
	Block a user