done
This commit is contained in:
		| @ -0,0 +1,181 @@ | ||||
| from datetime import timedelta | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     NaT, | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
| from pandas.core.arrays import TimedeltaArray | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndex: | ||||
|     def test_astype_object(self): | ||||
|         idx = timedelta_range(start="1 days", periods=4, freq="D", name="idx") | ||||
|         expected_list = [ | ||||
|             Timedelta("1 days"), | ||||
|             Timedelta("2 days"), | ||||
|             Timedelta("3 days"), | ||||
|             Timedelta("4 days"), | ||||
|         ] | ||||
|         result = idx.astype(object) | ||||
|         expected = Index(expected_list, dtype=object, name="idx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert idx.tolist() == expected_list | ||||
|  | ||||
|     def test_astype_object_with_nat(self): | ||||
|         idx = TimedeltaIndex( | ||||
|             [timedelta(days=1), timedelta(days=2), NaT, timedelta(days=4)], name="idx" | ||||
|         ) | ||||
|         expected_list = [ | ||||
|             Timedelta("1 days"), | ||||
|             Timedelta("2 days"), | ||||
|             NaT, | ||||
|             Timedelta("4 days"), | ||||
|         ] | ||||
|         result = idx.astype(object) | ||||
|         expected = Index(expected_list, dtype=object, name="idx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert idx.tolist() == expected_list | ||||
|  | ||||
|     def test_astype(self, using_infer_string): | ||||
|         # GH 13149, GH 13209 | ||||
|         idx = TimedeltaIndex([1e14, "NaT", NaT, np.nan], name="idx") | ||||
|  | ||||
|         result = idx.astype(object) | ||||
|         expected = Index( | ||||
|             [Timedelta("1 days 03:46:40")] + [NaT] * 3, dtype=object, name="idx" | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         result = idx.astype(np.int64) | ||||
|         expected = Index( | ||||
|             [100000000000000] + [-9223372036854775808] * 3, dtype=np.int64, name="idx" | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         result = idx.astype(str) | ||||
|         if using_infer_string: | ||||
|             expected = Index( | ||||
|                 [str(x) if x is not NaT else None for x in idx], name="idx", dtype="str" | ||||
|             ) | ||||
|         else: | ||||
|             expected = Index([str(x) for x in idx], name="idx", dtype=object) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         rng = timedelta_range("1 days", periods=10) | ||||
|         result = rng.astype("i8") | ||||
|         tm.assert_index_equal(result, Index(rng.asi8)) | ||||
|         tm.assert_numpy_array_equal(rng.asi8, result.values) | ||||
|  | ||||
|     def test_astype_uint(self): | ||||
|         arr = timedelta_range("1h", periods=2) | ||||
|  | ||||
|         with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"): | ||||
|             arr.astype("uint64") | ||||
|         with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"): | ||||
|             arr.astype("uint32") | ||||
|  | ||||
|     def test_astype_timedelta64(self): | ||||
|         # GH 13149, GH 13209 | ||||
|         idx = TimedeltaIndex([1e14, "NaT", NaT, np.nan]) | ||||
|  | ||||
|         msg = ( | ||||
|             r"Cannot convert from timedelta64\[ns\] to timedelta64. " | ||||
|             "Supported resolutions are 's', 'ms', 'us', 'ns'" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx.astype("timedelta64") | ||||
|  | ||||
|         result = idx.astype("timedelta64[ns]") | ||||
|         tm.assert_index_equal(result, idx) | ||||
|         assert result is not idx | ||||
|  | ||||
|         result = idx.astype("timedelta64[ns]", copy=False) | ||||
|         tm.assert_index_equal(result, idx) | ||||
|         assert result is idx | ||||
|  | ||||
|     def test_astype_to_td64d_raises(self, index_or_series): | ||||
|         # We don't support "D" reso | ||||
|         scalar = Timedelta(days=31) | ||||
|         td = index_or_series( | ||||
|             [scalar, scalar, scalar + timedelta(minutes=5, seconds=3), NaT], | ||||
|             dtype="m8[ns]", | ||||
|         ) | ||||
|         msg = ( | ||||
|             r"Cannot convert from timedelta64\[ns\] to timedelta64\[D\]. " | ||||
|             "Supported resolutions are 's', 'ms', 'us', 'ns'" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             td.astype("timedelta64[D]") | ||||
|  | ||||
|     def test_astype_ms_to_s(self, index_or_series): | ||||
|         scalar = Timedelta(days=31) | ||||
|         td = index_or_series( | ||||
|             [scalar, scalar, scalar + timedelta(minutes=5, seconds=3), NaT], | ||||
|             dtype="m8[ns]", | ||||
|         ) | ||||
|  | ||||
|         exp_values = np.asarray(td).astype("m8[s]") | ||||
|         exp_tda = TimedeltaArray._simple_new(exp_values, dtype=exp_values.dtype) | ||||
|         expected = index_or_series(exp_tda) | ||||
|         assert expected.dtype == "m8[s]" | ||||
|         result = td.astype("timedelta64[s]") | ||||
|         tm.assert_equal(result, expected) | ||||
|  | ||||
|     def test_astype_freq_conversion(self): | ||||
|         # pre-2.0 td64 astype converted to float64. now for supported units | ||||
|         #  (s, ms, us, ns) this converts to the requested dtype. | ||||
|         # This matches TDA and Series | ||||
|         tdi = timedelta_range("1 Day", periods=30) | ||||
|  | ||||
|         res = tdi.astype("m8[s]") | ||||
|         exp_values = np.asarray(tdi).astype("m8[s]") | ||||
|         exp_tda = TimedeltaArray._simple_new( | ||||
|             exp_values, dtype=exp_values.dtype, freq=tdi.freq | ||||
|         ) | ||||
|         expected = Index(exp_tda) | ||||
|         assert expected.dtype == "m8[s]" | ||||
|         tm.assert_index_equal(res, expected) | ||||
|  | ||||
|         # check this matches Series and TimedeltaArray | ||||
|         res = tdi._data.astype("m8[s]") | ||||
|         tm.assert_equal(res, expected._values) | ||||
|  | ||||
|         res = tdi.to_series().astype("m8[s]") | ||||
|         tm.assert_equal(res._values, expected._values._with_freq(None)) | ||||
|  | ||||
|     @pytest.mark.parametrize("dtype", [float, "datetime64", "datetime64[ns]"]) | ||||
|     def test_astype_raises(self, dtype): | ||||
|         # GH 13149, GH 13209 | ||||
|         idx = TimedeltaIndex([1e14, "NaT", NaT, np.nan]) | ||||
|         msg = "Cannot cast TimedeltaIndex to dtype" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             idx.astype(dtype) | ||||
|  | ||||
|     def test_astype_category(self): | ||||
|         obj = timedelta_range("1h", periods=2, freq="h") | ||||
|  | ||||
|         result = obj.astype("category") | ||||
|         expected = pd.CategoricalIndex([Timedelta("1h"), Timedelta("2h")]) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         result = obj._data.astype("category") | ||||
|         expected = expected.values | ||||
|         tm.assert_categorical_equal(result, expected) | ||||
|  | ||||
|     def test_astype_array_fallback(self): | ||||
|         obj = timedelta_range("1h", periods=2) | ||||
|         result = obj.astype(bool) | ||||
|         expected = Index(np.array([True, True])) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         result = obj._data.astype(bool) | ||||
|         expected = np.array([True, True]) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
| @ -0,0 +1,40 @@ | ||||
| import numpy as np | ||||
|  | ||||
| from pandas import ( | ||||
|     TimedeltaIndex, | ||||
|     factorize, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexFactorize: | ||||
|     def test_factorize(self): | ||||
|         idx1 = TimedeltaIndex(["1 day", "1 day", "2 day", "2 day", "3 day", "3 day"]) | ||||
|  | ||||
|         exp_arr = np.array([0, 0, 1, 1, 2, 2], dtype=np.intp) | ||||
|         exp_idx = TimedeltaIndex(["1 day", "2 day", "3 day"]) | ||||
|  | ||||
|         arr, idx = idx1.factorize() | ||||
|         tm.assert_numpy_array_equal(arr, exp_arr) | ||||
|         tm.assert_index_equal(idx, exp_idx) | ||||
|         assert idx.freq == exp_idx.freq | ||||
|  | ||||
|         arr, idx = idx1.factorize(sort=True) | ||||
|         tm.assert_numpy_array_equal(arr, exp_arr) | ||||
|         tm.assert_index_equal(idx, exp_idx) | ||||
|         assert idx.freq == exp_idx.freq | ||||
|  | ||||
|     def test_factorize_preserves_freq(self): | ||||
|         # GH#38120 freq should be preserved | ||||
|         idx3 = timedelta_range("1 day", periods=4, freq="s") | ||||
|         exp_arr = np.array([0, 1, 2, 3], dtype=np.intp) | ||||
|         arr, idx = idx3.factorize() | ||||
|         tm.assert_numpy_array_equal(arr, exp_arr) | ||||
|         tm.assert_index_equal(idx, idx3) | ||||
|         assert idx.freq == idx3.freq | ||||
|  | ||||
|         arr, idx = factorize(idx3) | ||||
|         tm.assert_numpy_array_equal(arr, exp_arr) | ||||
|         tm.assert_index_equal(idx, idx3) | ||||
|         assert idx.freq == idx3.freq | ||||
| @ -0,0 +1,22 @@ | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     NaT, | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestFillNA: | ||||
|     def test_fillna_timedelta(self): | ||||
|         # GH#11343 | ||||
|         idx = TimedeltaIndex(["1 day", NaT, "3 day"]) | ||||
|  | ||||
|         exp = TimedeltaIndex(["1 day", "2 day", "3 day"]) | ||||
|         tm.assert_index_equal(idx.fillna(Timedelta("2 day")), exp) | ||||
|  | ||||
|         exp = TimedeltaIndex(["1 day", "3 hour", "3 day"]) | ||||
|         idx.fillna(Timedelta("3 hour")) | ||||
|  | ||||
|         exp = Index([Timedelta("1 day"), "x", Timedelta("3 day")], dtype=object) | ||||
|         tm.assert_index_equal(idx.fillna("x"), exp) | ||||
| @ -0,0 +1,145 @@ | ||||
| from datetime import timedelta | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas._libs import lib | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexInsert: | ||||
|     def test_insert(self): | ||||
|         idx = TimedeltaIndex(["4day", "1day", "2day"], name="idx") | ||||
|  | ||||
|         result = idx.insert(2, timedelta(days=5)) | ||||
|         exp = TimedeltaIndex(["4day", "1day", "5day", "2day"], name="idx") | ||||
|         tm.assert_index_equal(result, exp) | ||||
|  | ||||
|         # insertion of non-datetime should coerce to object index | ||||
|         result = idx.insert(1, "inserted") | ||||
|         expected = Index( | ||||
|             [Timedelta("4day"), "inserted", Timedelta("1day"), Timedelta("2day")], | ||||
|             name="idx", | ||||
|         ) | ||||
|         assert not isinstance(result, TimedeltaIndex) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert result.name == expected.name | ||||
|  | ||||
|         idx = timedelta_range("1day 00:00:01", periods=3, freq="s", name="idx") | ||||
|  | ||||
|         # preserve freq | ||||
|         expected_0 = TimedeltaIndex( | ||||
|             ["1day", "1day 00:00:01", "1day 00:00:02", "1day 00:00:03"], | ||||
|             name="idx", | ||||
|             freq="s", | ||||
|         ) | ||||
|         expected_3 = TimedeltaIndex( | ||||
|             ["1day 00:00:01", "1day 00:00:02", "1day 00:00:03", "1day 00:00:04"], | ||||
|             name="idx", | ||||
|             freq="s", | ||||
|         ) | ||||
|  | ||||
|         # reset freq to None | ||||
|         expected_1_nofreq = TimedeltaIndex( | ||||
|             ["1day 00:00:01", "1day 00:00:01", "1day 00:00:02", "1day 00:00:03"], | ||||
|             name="idx", | ||||
|             freq=None, | ||||
|         ) | ||||
|         expected_3_nofreq = TimedeltaIndex( | ||||
|             ["1day 00:00:01", "1day 00:00:02", "1day 00:00:03", "1day 00:00:05"], | ||||
|             name="idx", | ||||
|             freq=None, | ||||
|         ) | ||||
|  | ||||
|         cases = [ | ||||
|             (0, Timedelta("1day"), expected_0), | ||||
|             (-3, Timedelta("1day"), expected_0), | ||||
|             (3, Timedelta("1day 00:00:04"), expected_3), | ||||
|             (1, Timedelta("1day 00:00:01"), expected_1_nofreq), | ||||
|             (3, Timedelta("1day 00:00:05"), expected_3_nofreq), | ||||
|         ] | ||||
|  | ||||
|         for n, d, expected in cases: | ||||
|             result = idx.insert(n, d) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.name == expected.name | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "null", [None, np.nan, np.timedelta64("NaT"), pd.NaT, pd.NA] | ||||
|     ) | ||||
|     def test_insert_nat(self, null): | ||||
|         # GH 18295 (test missing) | ||||
|         idx = timedelta_range("1day", "3day") | ||||
|         result = idx.insert(1, null) | ||||
|         expected = TimedeltaIndex(["1day", pd.NaT, "2day", "3day"]) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_insert_invalid_na(self): | ||||
|         idx = TimedeltaIndex(["4day", "1day", "2day"], name="idx") | ||||
|  | ||||
|         item = np.datetime64("NaT") | ||||
|         result = idx.insert(0, item) | ||||
|  | ||||
|         expected = Index([item] + list(idx), dtype=object, name="idx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         # Also works if we pass a different dt64nat object | ||||
|         item2 = np.datetime64("NaT") | ||||
|         result = idx.insert(0, item2) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "item", [0, np.int64(0), np.float64(0), np.array(0), np.datetime64(456, "us")] | ||||
|     ) | ||||
|     def test_insert_mismatched_types_raises(self, item): | ||||
|         # GH#33703 dont cast these to td64 | ||||
|         tdi = TimedeltaIndex(["4day", "1day", "2day"], name="idx") | ||||
|  | ||||
|         result = tdi.insert(1, item) | ||||
|  | ||||
|         expected = Index( | ||||
|             [tdi[0], lib.item_from_zerodim(item)] + list(tdi[1:]), | ||||
|             dtype=object, | ||||
|             name="idx", | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_insert_castable_str(self): | ||||
|         idx = timedelta_range("1day", "3day") | ||||
|  | ||||
|         result = idx.insert(0, "1 Day") | ||||
|  | ||||
|         expected = TimedeltaIndex([idx[0]] + list(idx)) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_insert_non_castable_str(self): | ||||
|         idx = timedelta_range("1day", "3day") | ||||
|  | ||||
|         result = idx.insert(0, "foo") | ||||
|  | ||||
|         expected = Index(["foo"] + list(idx), dtype=object) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_insert_empty(self): | ||||
|         # Corner case inserting with length zero doesn't raise IndexError | ||||
|         # GH#33573 for freq preservation | ||||
|         idx = timedelta_range("1 Day", periods=3) | ||||
|         td = idx[0] | ||||
|  | ||||
|         result = idx[:0].insert(0, td) | ||||
|         assert result.freq == "D" | ||||
|  | ||||
|         with pytest.raises(IndexError, match="loc must be an integer between"): | ||||
|             result = idx[:0].insert(1, td) | ||||
|  | ||||
|         with pytest.raises(IndexError, match="loc must be an integer between"): | ||||
|             result = idx[:0].insert(-1, td) | ||||
| @ -0,0 +1,34 @@ | ||||
| import numpy as np | ||||
|  | ||||
| from pandas import ( | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestRepeat: | ||||
|     def test_repeat(self): | ||||
|         index = timedelta_range("1 days", periods=2, freq="D") | ||||
|         exp = TimedeltaIndex(["1 days", "1 days", "2 days", "2 days"]) | ||||
|         for res in [index.repeat(2), np.repeat(index, 2)]: | ||||
|             tm.assert_index_equal(res, exp) | ||||
|             assert res.freq is None | ||||
|  | ||||
|         index = TimedeltaIndex(["1 days", "NaT", "3 days"]) | ||||
|         exp = TimedeltaIndex( | ||||
|             [ | ||||
|                 "1 days", | ||||
|                 "1 days", | ||||
|                 "1 days", | ||||
|                 "NaT", | ||||
|                 "NaT", | ||||
|                 "NaT", | ||||
|                 "3 days", | ||||
|                 "3 days", | ||||
|                 "3 days", | ||||
|             ] | ||||
|         ) | ||||
|         for res in [index.repeat(3), np.repeat(index, 3)]: | ||||
|             tm.assert_index_equal(res, exp) | ||||
|             assert res.freq is None | ||||
| @ -0,0 +1,76 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas.errors import NullFrequencyError | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import TimedeltaIndex | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexShift: | ||||
|     # ------------------------------------------------------------- | ||||
|     # TimedeltaIndex.shift is used by __add__/__sub__ | ||||
|  | ||||
|     def test_tdi_shift_empty(self): | ||||
|         # GH#9903 | ||||
|         idx = TimedeltaIndex([], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(0, freq="h"), idx) | ||||
|         tm.assert_index_equal(idx.shift(3, freq="h"), idx) | ||||
|  | ||||
|     def test_tdi_shift_hours(self): | ||||
|         # GH#9903 | ||||
|         idx = TimedeltaIndex(["5 hours", "6 hours", "9 hours"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(0, freq="h"), idx) | ||||
|         exp = TimedeltaIndex(["8 hours", "9 hours", "12 hours"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(3, freq="h"), exp) | ||||
|         exp = TimedeltaIndex(["2 hours", "3 hours", "6 hours"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(-3, freq="h"), exp) | ||||
|  | ||||
|     def test_tdi_shift_minutes(self): | ||||
|         # GH#9903 | ||||
|         idx = TimedeltaIndex(["5 hours", "6 hours", "9 hours"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(0, freq="min"), idx) | ||||
|         exp = TimedeltaIndex(["05:03:00", "06:03:00", "9:03:00"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(3, freq="min"), exp) | ||||
|         exp = TimedeltaIndex(["04:57:00", "05:57:00", "8:57:00"], name="xxx") | ||||
|         tm.assert_index_equal(idx.shift(-3, freq="min"), exp) | ||||
|  | ||||
|     def test_tdi_shift_int(self): | ||||
|         # GH#8083 | ||||
|         tdi = pd.to_timedelta(range(5), unit="d") | ||||
|         trange = tdi._with_freq("infer") + pd.offsets.Hour(1) | ||||
|         result = trange.shift(1) | ||||
|         expected = TimedeltaIndex( | ||||
|             [ | ||||
|                 "1 days 01:00:00", | ||||
|                 "2 days 01:00:00", | ||||
|                 "3 days 01:00:00", | ||||
|                 "4 days 01:00:00", | ||||
|                 "5 days 01:00:00", | ||||
|             ], | ||||
|             freq="D", | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_tdi_shift_nonstandard_freq(self): | ||||
|         # GH#8083 | ||||
|         tdi = pd.to_timedelta(range(5), unit="d") | ||||
|         trange = tdi._with_freq("infer") + pd.offsets.Hour(1) | ||||
|         result = trange.shift(3, freq="2D 1s") | ||||
|         expected = TimedeltaIndex( | ||||
|             [ | ||||
|                 "6 days 01:00:03", | ||||
|                 "7 days 01:00:03", | ||||
|                 "8 days 01:00:03", | ||||
|                 "9 days 01:00:03", | ||||
|                 "10 days 01:00:03", | ||||
|             ], | ||||
|             freq="D", | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_shift_no_freq(self): | ||||
|         # GH#19147 | ||||
|         tdi = TimedeltaIndex(["1 days 01:00:00", "2 days 01:00:00"], freq=None) | ||||
|         with pytest.raises(NullFrequencyError, match="Cannot shift with no freq"): | ||||
|             tdi.shift(2) | ||||
| @ -0,0 +1,51 @@ | ||||
| # Arithmetic tests for TimedeltaIndex are generally about the result's `freq` attribute. | ||||
| # Other cases can be shared in tests.arithmetic.test_timedelta64 | ||||
| import numpy as np | ||||
|  | ||||
| from pandas import ( | ||||
|     NaT, | ||||
|     Timedelta, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexArithmetic: | ||||
|     def test_arithmetic_zero_freq(self): | ||||
|         # GH#51575 don't get a .freq with freq.n = 0 | ||||
|         tdi = timedelta_range(0, periods=100, freq="ns") | ||||
|         result = tdi / 2 | ||||
|         assert result.freq is None | ||||
|         expected = tdi[:50].repeat(2) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         result2 = tdi // 2 | ||||
|         assert result2.freq is None | ||||
|         expected2 = expected | ||||
|         tm.assert_index_equal(result2, expected2) | ||||
|  | ||||
|         result3 = tdi * 0 | ||||
|         assert result3.freq is None | ||||
|         expected3 = tdi[:1].repeat(100) | ||||
|         tm.assert_index_equal(result3, expected3) | ||||
|  | ||||
|     def test_tdi_division(self, index_or_series): | ||||
|         # doc example | ||||
|  | ||||
|         scalar = Timedelta(days=31) | ||||
|         td = index_or_series( | ||||
|             [scalar, scalar, scalar + Timedelta(minutes=5, seconds=3), NaT], | ||||
|             dtype="m8[ns]", | ||||
|         ) | ||||
|  | ||||
|         result = td / np.timedelta64(1, "D") | ||||
|         expected = index_or_series( | ||||
|             [31, 31, (31 * 86400 + 5 * 60 + 3) / 86400.0, np.nan] | ||||
|         ) | ||||
|         tm.assert_equal(result, expected) | ||||
|  | ||||
|         result = td / np.timedelta64(1, "s") | ||||
|         expected = index_or_series( | ||||
|             [31 * 86400, 31 * 86400, 31 * 86400 + 5 * 60 + 3, np.nan] | ||||
|         ) | ||||
|         tm.assert_equal(result, expected) | ||||
| @ -0,0 +1,291 @@ | ||||
| from datetime import timedelta | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
|     to_timedelta, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
| from pandas.core.arrays.timedeltas import TimedeltaArray | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndex: | ||||
|     def test_closed_deprecated(self): | ||||
|         # GH#52628 | ||||
|         msg = "The 'closed' keyword" | ||||
|         with tm.assert_produces_warning(FutureWarning, match=msg): | ||||
|             TimedeltaIndex([], closed=True) | ||||
|  | ||||
|     def test_array_of_dt64_nat_raises(self): | ||||
|         # GH#39462 | ||||
|         nat = np.datetime64("NaT", "ns") | ||||
|         arr = np.array([nat], dtype=object) | ||||
|  | ||||
|         msg = "Invalid type for timedelta scalar" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaIndex(arr) | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaArray._from_sequence(arr, dtype="m8[ns]") | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             to_timedelta(arr) | ||||
|  | ||||
|     @pytest.mark.parametrize("unit", ["Y", "y", "M"]) | ||||
|     def test_unit_m_y_raises(self, unit): | ||||
|         msg = "Units 'M', 'Y', and 'y' are no longer supported" | ||||
|         depr_msg = "The 'unit' keyword in TimedeltaIndex construction is deprecated" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             with tm.assert_produces_warning(FutureWarning, match=depr_msg): | ||||
|                 TimedeltaIndex([1, 3, 7], unit) | ||||
|  | ||||
|     def test_int64_nocopy(self): | ||||
|         # GH#23539 check that a copy isn't made when we pass int64 data | ||||
|         #  and copy=False | ||||
|         arr = np.arange(10, dtype=np.int64) | ||||
|         tdi = TimedeltaIndex(arr, copy=False) | ||||
|         assert tdi._data._ndarray.base is arr | ||||
|  | ||||
|     def test_infer_from_tdi(self): | ||||
|         # GH#23539 | ||||
|         # fast-path for inferring a frequency if the passed data already | ||||
|         #  has one | ||||
|         tdi = timedelta_range("1 second", periods=10**7, freq="1s") | ||||
|  | ||||
|         result = TimedeltaIndex(tdi, freq="infer") | ||||
|         assert result.freq == tdi.freq | ||||
|  | ||||
|         # check that inferred_freq was not called by checking that the | ||||
|         #  value has not been cached | ||||
|         assert "inferred_freq" not in getattr(result, "_cache", {}) | ||||
|  | ||||
|     def test_infer_from_tdi_mismatch(self): | ||||
|         # GH#23539 | ||||
|         # fast-path for invalidating a frequency if the passed data already | ||||
|         #  has one and it does not match the `freq` input | ||||
|         tdi = timedelta_range("1 second", periods=100, freq="1s") | ||||
|  | ||||
|         depr_msg = "TimedeltaArray.__init__ is deprecated" | ||||
|         msg = ( | ||||
|             "Inferred frequency .* from passed values does " | ||||
|             "not conform to passed frequency" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             TimedeltaIndex(tdi, freq="D") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             # GH#23789 | ||||
|             with tm.assert_produces_warning(FutureWarning, match=depr_msg): | ||||
|                 TimedeltaArray(tdi, freq="D") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             TimedeltaIndex(tdi._data, freq="D") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             with tm.assert_produces_warning(FutureWarning, match=depr_msg): | ||||
|                 TimedeltaArray(tdi._data, freq="D") | ||||
|  | ||||
|     def test_dt64_data_invalid(self): | ||||
|         # GH#23539 | ||||
|         # passing tz-aware DatetimeIndex raises, naive or ndarray[datetime64] | ||||
|         #  raise as of GH#29794 | ||||
|         dti = pd.date_range("2016-01-01", periods=3) | ||||
|  | ||||
|         msg = "cannot be converted to timedelta64" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaIndex(dti.tz_localize("Europe/Brussels")) | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaIndex(dti) | ||||
|  | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaIndex(np.asarray(dti)) | ||||
|  | ||||
|     def test_float64_ns_rounded(self): | ||||
|         # GH#23539 without specifying a unit, floats are regarded as nanos, | ||||
|         #  and fractional portions are truncated | ||||
|         tdi = TimedeltaIndex([2.3, 9.7]) | ||||
|         expected = TimedeltaIndex([2, 9]) | ||||
|         tm.assert_index_equal(tdi, expected) | ||||
|  | ||||
|         # integral floats are non-lossy | ||||
|         tdi = TimedeltaIndex([2.0, 9.0]) | ||||
|         expected = TimedeltaIndex([2, 9]) | ||||
|         tm.assert_index_equal(tdi, expected) | ||||
|  | ||||
|         # NaNs get converted to NaT | ||||
|         tdi = TimedeltaIndex([2.0, np.nan]) | ||||
|         expected = TimedeltaIndex([Timedelta(nanoseconds=2), pd.NaT]) | ||||
|         tm.assert_index_equal(tdi, expected) | ||||
|  | ||||
|     def test_float64_unit_conversion(self): | ||||
|         # GH#23539 | ||||
|         tdi = to_timedelta([1.5, 2.25], unit="D") | ||||
|         expected = TimedeltaIndex([Timedelta(days=1.5), Timedelta(days=2.25)]) | ||||
|         tm.assert_index_equal(tdi, expected) | ||||
|  | ||||
|     def test_construction_base_constructor(self): | ||||
|         arr = [Timedelta("1 days"), pd.NaT, Timedelta("3 days")] | ||||
|         tm.assert_index_equal(pd.Index(arr), TimedeltaIndex(arr)) | ||||
|         tm.assert_index_equal(pd.Index(np.array(arr)), TimedeltaIndex(np.array(arr))) | ||||
|  | ||||
|         arr = [np.nan, pd.NaT, Timedelta("1 days")] | ||||
|         tm.assert_index_equal(pd.Index(arr), TimedeltaIndex(arr)) | ||||
|         tm.assert_index_equal(pd.Index(np.array(arr)), TimedeltaIndex(np.array(arr))) | ||||
|  | ||||
|     @pytest.mark.filterwarnings( | ||||
|         "ignore:The 'unit' keyword in TimedeltaIndex construction:FutureWarning" | ||||
|     ) | ||||
|     def test_constructor(self): | ||||
|         expected = TimedeltaIndex( | ||||
|             [ | ||||
|                 "1 days", | ||||
|                 "1 days 00:00:05", | ||||
|                 "2 days", | ||||
|                 "2 days 00:00:02", | ||||
|                 "0 days 00:00:03", | ||||
|             ] | ||||
|         ) | ||||
|         result = TimedeltaIndex( | ||||
|             [ | ||||
|                 "1 days", | ||||
|                 "1 days, 00:00:05", | ||||
|                 np.timedelta64(2, "D"), | ||||
|                 timedelta(days=2, seconds=2), | ||||
|                 pd.offsets.Second(3), | ||||
|             ] | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         expected = TimedeltaIndex( | ||||
|             ["0 days 00:00:00", "0 days 00:00:01", "0 days 00:00:02"] | ||||
|         ) | ||||
|         result = TimedeltaIndex(range(3), unit="s") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         expected = TimedeltaIndex( | ||||
|             ["0 days 00:00:00", "0 days 00:00:05", "0 days 00:00:09"] | ||||
|         ) | ||||
|         result = TimedeltaIndex([0, 5, 9], unit="s") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         expected = TimedeltaIndex( | ||||
|             ["0 days 00:00:00.400", "0 days 00:00:00.450", "0 days 00:00:01.200"] | ||||
|         ) | ||||
|         result = TimedeltaIndex([400, 450, 1200], unit="ms") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_constructor_iso(self): | ||||
|         # GH #21877 | ||||
|         expected = timedelta_range("1s", periods=9, freq="s") | ||||
|         durations = [f"P0DT0H0M{i}S" for i in range(1, 10)] | ||||
|         result = to_timedelta(durations) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_timedelta_range_fractional_period(self): | ||||
|         msg = "Non-integer 'periods' in pd.date_range, pd.timedelta_range" | ||||
|         with tm.assert_produces_warning(FutureWarning, match=msg): | ||||
|             rng = timedelta_range("1 days", periods=10.5) | ||||
|         exp = timedelta_range("1 days", periods=10) | ||||
|         tm.assert_index_equal(rng, exp) | ||||
|  | ||||
|     def test_constructor_coverage(self): | ||||
|         msg = "periods must be a number, got foo" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             timedelta_range(start="1 days", periods="foo", freq="D") | ||||
|  | ||||
|         msg = ( | ||||
|             r"TimedeltaIndex\(\.\.\.\) must be called with a collection of some kind, " | ||||
|             "'1 days' was passed" | ||||
|         ) | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             TimedeltaIndex("1 days") | ||||
|  | ||||
|         # generator expression | ||||
|         gen = (timedelta(i) for i in range(10)) | ||||
|         result = TimedeltaIndex(gen) | ||||
|         expected = TimedeltaIndex([timedelta(i) for i in range(10)]) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         # NumPy string array | ||||
|         strings = np.array(["1 days", "2 days", "3 days"]) | ||||
|         result = TimedeltaIndex(strings) | ||||
|         expected = to_timedelta([1, 2, 3], unit="d") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         from_ints = TimedeltaIndex(expected.asi8) | ||||
|         tm.assert_index_equal(from_ints, expected) | ||||
|  | ||||
|         # non-conforming freq | ||||
|         msg = ( | ||||
|             "Inferred frequency None from passed values does not conform to " | ||||
|             "passed frequency D" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             TimedeltaIndex(["1 days", "2 days", "4 days"], freq="D") | ||||
|  | ||||
|         msg = ( | ||||
|             "Of the four parameters: start, end, periods, and freq, exactly " | ||||
|             "three must be specified" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range(periods=10, freq="D") | ||||
|  | ||||
|     def test_constructor_name(self): | ||||
|         idx = timedelta_range(start="1 days", periods=1, freq="D", name="TEST") | ||||
|         assert idx.name == "TEST" | ||||
|  | ||||
|         # GH10025 | ||||
|         idx2 = TimedeltaIndex(idx, name="something else") | ||||
|         assert idx2.name == "something else" | ||||
|  | ||||
|     def test_constructor_no_precision_raises(self): | ||||
|         # GH-24753, GH-24739 | ||||
|  | ||||
|         msg = "with no precision is not allowed" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             TimedeltaIndex(["2000"], dtype="timedelta64") | ||||
|  | ||||
|         msg = "The 'timedelta64' dtype has no unit. Please pass in" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             pd.Index(["2000"], dtype="timedelta64") | ||||
|  | ||||
|     def test_constructor_wrong_precision_raises(self): | ||||
|         msg = "Supported timedelta64 resolutions are 's', 'ms', 'us', 'ns'" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             TimedeltaIndex(["2000"], dtype="timedelta64[D]") | ||||
|  | ||||
|         # "timedelta64[us]" was unsupported pre-2.0, but now this works. | ||||
|         tdi = TimedeltaIndex(["2000"], dtype="timedelta64[us]") | ||||
|         assert tdi.dtype == "m8[us]" | ||||
|  | ||||
|     def test_explicit_none_freq(self): | ||||
|         # Explicitly passing freq=None is respected | ||||
|         tdi = timedelta_range(1, periods=5) | ||||
|         assert tdi.freq is not None | ||||
|  | ||||
|         result = TimedeltaIndex(tdi, freq=None) | ||||
|         assert result.freq is None | ||||
|  | ||||
|         result = TimedeltaIndex(tdi._data, freq=None) | ||||
|         assert result.freq is None | ||||
|  | ||||
|         msg = "TimedeltaArray.__init__ is deprecated" | ||||
|         with tm.assert_produces_warning(FutureWarning, match=msg): | ||||
|             tda = TimedeltaArray(tdi, freq=None) | ||||
|         assert tda.freq is None | ||||
|  | ||||
|     def test_from_categorical(self): | ||||
|         tdi = timedelta_range(1, periods=5) | ||||
|  | ||||
|         cat = pd.Categorical(tdi) | ||||
|  | ||||
|         result = TimedeltaIndex(cat) | ||||
|         tm.assert_index_equal(result, tdi) | ||||
|  | ||||
|         ci = pd.CategoricalIndex(tdi) | ||||
|         result = TimedeltaIndex(ci) | ||||
|         tm.assert_index_equal(result, tdi) | ||||
| @ -0,0 +1,71 @@ | ||||
| from pandas import ( | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexDelete: | ||||
|     def test_delete(self): | ||||
|         idx = timedelta_range(start="1 Days", periods=5, freq="D", name="idx") | ||||
|  | ||||
|         # preserve freq | ||||
|         expected_0 = timedelta_range(start="2 Days", periods=4, freq="D", name="idx") | ||||
|         expected_4 = timedelta_range(start="1 Days", periods=4, freq="D", name="idx") | ||||
|  | ||||
|         # reset freq to None | ||||
|         expected_1 = TimedeltaIndex( | ||||
|             ["1 day", "3 day", "4 day", "5 day"], freq=None, name="idx" | ||||
|         ) | ||||
|  | ||||
|         cases = { | ||||
|             0: expected_0, | ||||
|             -5: expected_0, | ||||
|             -1: expected_4, | ||||
|             4: expected_4, | ||||
|             1: expected_1, | ||||
|         } | ||||
|         for n, expected in cases.items(): | ||||
|             result = idx.delete(n) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.name == expected.name | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|         with tm.external_error_raised((IndexError, ValueError)): | ||||
|             # either depending on numpy version | ||||
|             idx.delete(5) | ||||
|  | ||||
|     def test_delete_slice(self): | ||||
|         idx = timedelta_range(start="1 days", periods=10, freq="D", name="idx") | ||||
|  | ||||
|         # preserve freq | ||||
|         expected_0_2 = timedelta_range(start="4 days", periods=7, freq="D", name="idx") | ||||
|         expected_7_9 = timedelta_range(start="1 days", periods=7, freq="D", name="idx") | ||||
|  | ||||
|         # reset freq to None | ||||
|         expected_3_5 = TimedeltaIndex( | ||||
|             ["1 d", "2 d", "3 d", "7 d", "8 d", "9 d", "10d"], freq=None, name="idx" | ||||
|         ) | ||||
|  | ||||
|         cases = { | ||||
|             (0, 1, 2): expected_0_2, | ||||
|             (7, 8, 9): expected_7_9, | ||||
|             (3, 4, 5): expected_3_5, | ||||
|         } | ||||
|         for n, expected in cases.items(): | ||||
|             result = idx.delete(n) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.name == expected.name | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx.delete(slice(n[0], n[-1] + 1)) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.name == expected.name | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|     def test_delete_doesnt_infer_freq(self): | ||||
|         # GH#30655 behavior matches DatetimeIndex | ||||
|  | ||||
|         tdi = TimedeltaIndex(["1 Day", "2 Days", None, "3 Days", "4 Days"]) | ||||
|         result = tdi.delete(2) | ||||
|         assert result.freq is None | ||||
| @ -0,0 +1,106 @@ | ||||
| import pytest | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     Series, | ||||
|     TimedeltaIndex, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexRendering: | ||||
|     def test_repr_round_days_non_nano(self): | ||||
|         # GH#55405 | ||||
|         # we should get "1 days", not "1 days 00:00:00" with non-nano | ||||
|         tdi = TimedeltaIndex(["1 days"], freq="D").as_unit("s") | ||||
|         result = repr(tdi) | ||||
|         expected = "TimedeltaIndex(['1 days'], dtype='timedelta64[s]', freq='D')" | ||||
|         assert result == expected | ||||
|  | ||||
|         result2 = repr(Series(tdi)) | ||||
|         expected2 = "0   1 days\ndtype: timedelta64[s]" | ||||
|         assert result2 == expected2 | ||||
|  | ||||
|     @pytest.mark.parametrize("method", ["__repr__", "__str__"]) | ||||
|     def test_representation(self, method): | ||||
|         idx1 = TimedeltaIndex([], freq="D") | ||||
|         idx2 = TimedeltaIndex(["1 days"], freq="D") | ||||
|         idx3 = TimedeltaIndex(["1 days", "2 days"], freq="D") | ||||
|         idx4 = TimedeltaIndex(["1 days", "2 days", "3 days"], freq="D") | ||||
|         idx5 = TimedeltaIndex(["1 days 00:00:01", "2 days", "3 days"]) | ||||
|  | ||||
|         exp1 = "TimedeltaIndex([], dtype='timedelta64[ns]', freq='D')" | ||||
|  | ||||
|         exp2 = "TimedeltaIndex(['1 days'], dtype='timedelta64[ns]', freq='D')" | ||||
|  | ||||
|         exp3 = "TimedeltaIndex(['1 days', '2 days'], dtype='timedelta64[ns]', freq='D')" | ||||
|  | ||||
|         exp4 = ( | ||||
|             "TimedeltaIndex(['1 days', '2 days', '3 days'], " | ||||
|             "dtype='timedelta64[ns]', freq='D')" | ||||
|         ) | ||||
|  | ||||
|         exp5 = ( | ||||
|             "TimedeltaIndex(['1 days 00:00:01', '2 days 00:00:00', " | ||||
|             "'3 days 00:00:00'], dtype='timedelta64[ns]', freq=None)" | ||||
|         ) | ||||
|  | ||||
|         with pd.option_context("display.width", 300): | ||||
|             for idx, expected in zip( | ||||
|                 [idx1, idx2, idx3, idx4, idx5], [exp1, exp2, exp3, exp4, exp5] | ||||
|             ): | ||||
|                 result = getattr(idx, method)() | ||||
|                 assert result == expected | ||||
|  | ||||
|     # TODO: this is a Series.__repr__ test | ||||
|     def test_representation_to_series(self): | ||||
|         idx1 = TimedeltaIndex([], freq="D") | ||||
|         idx2 = TimedeltaIndex(["1 days"], freq="D") | ||||
|         idx3 = TimedeltaIndex(["1 days", "2 days"], freq="D") | ||||
|         idx4 = TimedeltaIndex(["1 days", "2 days", "3 days"], freq="D") | ||||
|         idx5 = TimedeltaIndex(["1 days 00:00:01", "2 days", "3 days"]) | ||||
|  | ||||
|         exp1 = """Series([], dtype: timedelta64[ns])""" | ||||
|  | ||||
|         exp2 = "0   1 days\ndtype: timedelta64[ns]" | ||||
|  | ||||
|         exp3 = "0   1 days\n1   2 days\ndtype: timedelta64[ns]" | ||||
|  | ||||
|         exp4 = "0   1 days\n1   2 days\n2   3 days\ndtype: timedelta64[ns]" | ||||
|  | ||||
|         exp5 = ( | ||||
|             "0   1 days 00:00:01\n" | ||||
|             "1   2 days 00:00:00\n" | ||||
|             "2   3 days 00:00:00\n" | ||||
|             "dtype: timedelta64[ns]" | ||||
|         ) | ||||
|  | ||||
|         with pd.option_context("display.width", 300): | ||||
|             for idx, expected in zip( | ||||
|                 [idx1, idx2, idx3, idx4, idx5], [exp1, exp2, exp3, exp4, exp5] | ||||
|             ): | ||||
|                 result = repr(Series(idx)) | ||||
|                 assert result == expected | ||||
|  | ||||
|     def test_summary(self): | ||||
|         # GH#9116 | ||||
|         idx1 = TimedeltaIndex([], freq="D") | ||||
|         idx2 = TimedeltaIndex(["1 days"], freq="D") | ||||
|         idx3 = TimedeltaIndex(["1 days", "2 days"], freq="D") | ||||
|         idx4 = TimedeltaIndex(["1 days", "2 days", "3 days"], freq="D") | ||||
|         idx5 = TimedeltaIndex(["1 days 00:00:01", "2 days", "3 days"]) | ||||
|  | ||||
|         exp1 = "TimedeltaIndex: 0 entries\nFreq: D" | ||||
|  | ||||
|         exp2 = "TimedeltaIndex: 1 entries, 1 days to 1 days\nFreq: D" | ||||
|  | ||||
|         exp3 = "TimedeltaIndex: 2 entries, 1 days to 2 days\nFreq: D" | ||||
|  | ||||
|         exp4 = "TimedeltaIndex: 3 entries, 1 days to 3 days\nFreq: D" | ||||
|  | ||||
|         exp5 = "TimedeltaIndex: 3 entries, 1 days 00:00:01 to 3 days 00:00:00" | ||||
|  | ||||
|         for idx, expected in zip( | ||||
|             [idx1, idx2, idx3, idx4, idx5], [exp1, exp2, exp3, exp4, exp5] | ||||
|         ): | ||||
|             result = idx._summary() | ||||
|             assert result == expected | ||||
| @ -0,0 +1,72 @@ | ||||
| import pytest | ||||
|  | ||||
| from pandas import TimedeltaIndex | ||||
|  | ||||
| from pandas.tseries.offsets import ( | ||||
|     DateOffset, | ||||
|     Day, | ||||
|     Hour, | ||||
|     MonthEnd, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class TestFreq: | ||||
|     @pytest.mark.parametrize("values", [["0 days", "2 days", "4 days"], []]) | ||||
|     @pytest.mark.parametrize("freq", ["2D", Day(2), "48h", Hour(48)]) | ||||
|     def test_freq_setter(self, values, freq): | ||||
|         # GH#20678 | ||||
|         idx = TimedeltaIndex(values) | ||||
|  | ||||
|         # can set to an offset, converting from string if necessary | ||||
|         idx._data.freq = freq | ||||
|         assert idx.freq == freq | ||||
|         assert isinstance(idx.freq, DateOffset) | ||||
|  | ||||
|         # can reset to None | ||||
|         idx._data.freq = None | ||||
|         assert idx.freq is None | ||||
|  | ||||
|     def test_with_freq_empty_requires_tick(self): | ||||
|         idx = TimedeltaIndex([]) | ||||
|  | ||||
|         off = MonthEnd(1) | ||||
|         msg = "TimedeltaArray/Index freq must be a Tick" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             idx._with_freq(off) | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             idx._data._with_freq(off) | ||||
|  | ||||
|     def test_freq_setter_errors(self): | ||||
|         # GH#20678 | ||||
|         idx = TimedeltaIndex(["0 days", "2 days", "4 days"]) | ||||
|  | ||||
|         # setting with an incompatible freq | ||||
|         msg = ( | ||||
|             "Inferred frequency 2D from passed values does not conform to " | ||||
|             "passed frequency 5D" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx._data.freq = "5D" | ||||
|  | ||||
|         # setting with a non-fixed frequency | ||||
|         msg = r"<2 \* BusinessDays> is a non-fixed frequency" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx._data.freq = "2B" | ||||
|  | ||||
|         # setting with non-freq string | ||||
|         with pytest.raises(ValueError, match="Invalid frequency"): | ||||
|             idx._data.freq = "foo" | ||||
|  | ||||
|     def test_freq_view_safe(self): | ||||
|         # Setting the freq for one TimedeltaIndex shouldn't alter the freq | ||||
|         #  for another that views the same data | ||||
|  | ||||
|         tdi = TimedeltaIndex(["0 days", "2 days", "4 days"], freq="2D") | ||||
|         tda = tdi._data | ||||
|  | ||||
|         tdi2 = TimedeltaIndex(tda)._with_freq(None) | ||||
|         assert tdi2.freq is None | ||||
|  | ||||
|         # Original was not altered | ||||
|         assert tdi.freq == "2D" | ||||
|         assert tda.freq == "2D" | ||||
| @ -0,0 +1,347 @@ | ||||
| from datetime import datetime | ||||
| import re | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     NaT, | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     Timestamp, | ||||
|     notna, | ||||
|     offsets, | ||||
|     timedelta_range, | ||||
|     to_timedelta, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestGetItem: | ||||
|     def test_getitem_slice_keeps_name(self): | ||||
|         # GH#4226 | ||||
|         tdi = timedelta_range("1d", "5d", freq="h", name="timebucket") | ||||
|         assert tdi[1:].name == tdi.name | ||||
|  | ||||
|     def test_getitem(self): | ||||
|         idx1 = timedelta_range("1 day", "31 day", freq="D", name="idx") | ||||
|  | ||||
|         for idx in [idx1]: | ||||
|             result = idx[0] | ||||
|             assert result == Timedelta("1 day") | ||||
|  | ||||
|             result = idx[0:5] | ||||
|             expected = timedelta_range("1 day", "5 day", freq="D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx[0:10:2] | ||||
|             expected = timedelta_range("1 day", "9 day", freq="2D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx[-20:-5:3] | ||||
|             expected = timedelta_range("12 day", "24 day", freq="3D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx[4::-1] | ||||
|             expected = TimedeltaIndex( | ||||
|                 ["5 day", "4 day", "3 day", "2 day", "1 day"], freq="-1D", name="idx" | ||||
|             ) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "key", | ||||
|         [ | ||||
|             Timestamp("1970-01-01"), | ||||
|             Timestamp("1970-01-02"), | ||||
|             datetime(1970, 1, 1), | ||||
|             Timestamp("1970-01-03").to_datetime64(), | ||||
|             # non-matching NA values | ||||
|             np.datetime64("NaT"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_timestamp_invalid_key(self, key): | ||||
|         # GH#20464 | ||||
|         tdi = timedelta_range(0, periods=10) | ||||
|         with pytest.raises(KeyError, match=re.escape(repr(key))): | ||||
|             tdi.get_loc(key) | ||||
|  | ||||
|  | ||||
| class TestGetLoc: | ||||
|     def test_get_loc_key_unit_mismatch(self): | ||||
|         idx = to_timedelta(["0 days", "1 days", "2 days"]) | ||||
|         key = idx[1].as_unit("ms") | ||||
|         loc = idx.get_loc(key) | ||||
|         assert loc == 1 | ||||
|  | ||||
|     def test_get_loc_key_unit_mismatch_not_castable(self): | ||||
|         tdi = to_timedelta(["0 days", "1 days", "2 days"]).astype("m8[s]") | ||||
|         assert tdi.dtype == "m8[s]" | ||||
|         key = tdi[0].as_unit("ns") + Timedelta(1) | ||||
|  | ||||
|         with pytest.raises(KeyError, match=r"Timedelta\('0 days 00:00:00.000000001'\)"): | ||||
|             tdi.get_loc(key) | ||||
|  | ||||
|         assert key not in tdi | ||||
|  | ||||
|     def test_get_loc(self): | ||||
|         idx = to_timedelta(["0 days", "1 days", "2 days"]) | ||||
|  | ||||
|         # GH 16909 | ||||
|         assert idx.get_loc(idx[1].to_timedelta64()) == 1 | ||||
|  | ||||
|         # GH 16896 | ||||
|         assert idx.get_loc("0 days") == 0 | ||||
|  | ||||
|     def test_get_loc_nat(self): | ||||
|         tidx = TimedeltaIndex(["1 days 01:00:00", "NaT", "2 days 01:00:00"]) | ||||
|  | ||||
|         assert tidx.get_loc(NaT) == 1 | ||||
|         assert tidx.get_loc(None) == 1 | ||||
|         assert tidx.get_loc(float("nan")) == 1 | ||||
|         assert tidx.get_loc(np.nan) == 1 | ||||
|  | ||||
|  | ||||
| class TestGetIndexer: | ||||
|     def test_get_indexer(self): | ||||
|         idx = to_timedelta(["0 days", "1 days", "2 days"]) | ||||
|         tm.assert_numpy_array_equal( | ||||
|             idx.get_indexer(idx), np.array([0, 1, 2], dtype=np.intp) | ||||
|         ) | ||||
|  | ||||
|         target = to_timedelta(["-1 hour", "12 hours", "1 day 1 hour"]) | ||||
|         tm.assert_numpy_array_equal( | ||||
|             idx.get_indexer(target, "pad"), np.array([-1, 0, 1], dtype=np.intp) | ||||
|         ) | ||||
|         tm.assert_numpy_array_equal( | ||||
|             idx.get_indexer(target, "backfill"), np.array([0, 1, 2], dtype=np.intp) | ||||
|         ) | ||||
|         tm.assert_numpy_array_equal( | ||||
|             idx.get_indexer(target, "nearest"), np.array([0, 1, 1], dtype=np.intp) | ||||
|         ) | ||||
|  | ||||
|         res = idx.get_indexer(target, "nearest", tolerance=Timedelta("1 hour")) | ||||
|         tm.assert_numpy_array_equal(res, np.array([0, -1, 1], dtype=np.intp)) | ||||
|  | ||||
|  | ||||
| class TestWhere: | ||||
|     def test_where_doesnt_retain_freq(self): | ||||
|         tdi = timedelta_range("1 day", periods=3, freq="D", name="idx") | ||||
|         cond = [True, True, False] | ||||
|         expected = TimedeltaIndex([tdi[0], tdi[1], tdi[0]], freq=None, name="idx") | ||||
|  | ||||
|         result = tdi.where(cond, tdi[::-1]) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_where_invalid_dtypes(self, fixed_now_ts): | ||||
|         tdi = timedelta_range("1 day", periods=3, freq="D", name="idx") | ||||
|  | ||||
|         tail = tdi[2:].tolist() | ||||
|         i2 = Index([NaT, NaT] + tail) | ||||
|         mask = notna(i2) | ||||
|  | ||||
|         expected = Index([NaT._value, NaT._value] + tail, dtype=object, name="idx") | ||||
|         assert isinstance(expected[0], int) | ||||
|         result = tdi.where(mask, i2.asi8) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         ts = i2 + fixed_now_ts | ||||
|         expected = Index([ts[0], ts[1]] + tail, dtype=object, name="idx") | ||||
|         result = tdi.where(mask, ts) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         per = (i2 + fixed_now_ts).to_period("D") | ||||
|         expected = Index([per[0], per[1]] + tail, dtype=object, name="idx") | ||||
|         result = tdi.where(mask, per) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         ts = fixed_now_ts | ||||
|         expected = Index([ts, ts] + tail, dtype=object, name="idx") | ||||
|         result = tdi.where(mask, ts) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_where_mismatched_nat(self): | ||||
|         tdi = timedelta_range("1 day", periods=3, freq="D", name="idx") | ||||
|         cond = np.array([True, False, False]) | ||||
|  | ||||
|         dtnat = np.datetime64("NaT", "ns") | ||||
|         expected = Index([tdi[0], dtnat, dtnat], dtype=object, name="idx") | ||||
|         assert expected[2] is dtnat | ||||
|         result = tdi.where(cond, dtnat) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|  | ||||
| class TestTake: | ||||
|     def test_take(self): | ||||
|         # GH 10295 | ||||
|         idx1 = timedelta_range("1 day", "31 day", freq="D", name="idx") | ||||
|  | ||||
|         for idx in [idx1]: | ||||
|             result = idx.take([0]) | ||||
|             assert result == Timedelta("1 day") | ||||
|  | ||||
|             result = idx.take([-1]) | ||||
|             assert result == Timedelta("31 day") | ||||
|  | ||||
|             result = idx.take([0, 1, 2]) | ||||
|             expected = timedelta_range("1 day", "3 day", freq="D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx.take([0, 2, 4]) | ||||
|             expected = timedelta_range("1 day", "5 day", freq="2D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx.take([7, 4, 1]) | ||||
|             expected = timedelta_range("8 day", "2 day", freq="-3D", name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq == expected.freq | ||||
|  | ||||
|             result = idx.take([3, 2, 5]) | ||||
|             expected = TimedeltaIndex(["4 day", "3 day", "6 day"], name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq is None | ||||
|  | ||||
|             result = idx.take([-3, 2, 5]) | ||||
|             expected = TimedeltaIndex(["29 day", "3 day", "6 day"], name="idx") | ||||
|             tm.assert_index_equal(result, expected) | ||||
|             assert result.freq is None | ||||
|  | ||||
|     def test_take_invalid_kwargs(self): | ||||
|         idx = timedelta_range("1 day", "31 day", freq="D", name="idx") | ||||
|         indices = [1, 6, 5, 9, 10, 13, 15, 3] | ||||
|  | ||||
|         msg = r"take\(\) got an unexpected keyword argument 'foo'" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             idx.take(indices, foo=2) | ||||
|  | ||||
|         msg = "the 'out' parameter is not supported" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx.take(indices, out=indices) | ||||
|  | ||||
|         msg = "the 'mode' parameter is not supported" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx.take(indices, mode="clip") | ||||
|  | ||||
|     def test_take_equiv_getitem(self): | ||||
|         tds = ["1day 02:00:00", "1 day 04:00:00", "1 day 10:00:00"] | ||||
|         idx = timedelta_range(start="1d", end="2d", freq="h", name="idx") | ||||
|         expected = TimedeltaIndex(tds, freq=None, name="idx") | ||||
|  | ||||
|         taken1 = idx.take([2, 4, 10]) | ||||
|         taken2 = idx[[2, 4, 10]] | ||||
|  | ||||
|         for taken in [taken1, taken2]: | ||||
|             tm.assert_index_equal(taken, expected) | ||||
|             assert isinstance(taken, TimedeltaIndex) | ||||
|             assert taken.freq is None | ||||
|             assert taken.name == expected.name | ||||
|  | ||||
|     def test_take_fill_value(self): | ||||
|         # GH 12631 | ||||
|         idx = TimedeltaIndex(["1 days", "2 days", "3 days"], name="xxx") | ||||
|         result = idx.take(np.array([1, 0, -1])) | ||||
|         expected = TimedeltaIndex(["2 days", "1 days", "3 days"], name="xxx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         # fill_value | ||||
|         result = idx.take(np.array([1, 0, -1]), fill_value=True) | ||||
|         expected = TimedeltaIndex(["2 days", "1 days", "NaT"], name="xxx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         # allow_fill=False | ||||
|         result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True) | ||||
|         expected = TimedeltaIndex(["2 days", "1 days", "3 days"], name="xxx") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         msg = ( | ||||
|             "When allow_fill=True and fill_value is not None, " | ||||
|             "all indices must be >= -1" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx.take(np.array([1, 0, -2]), fill_value=True) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             idx.take(np.array([1, 0, -5]), fill_value=True) | ||||
|  | ||||
|         msg = "index -5 is out of bounds for (axis 0 with )?size 3" | ||||
|         with pytest.raises(IndexError, match=msg): | ||||
|             idx.take(np.array([1, -5])) | ||||
|  | ||||
|  | ||||
| class TestMaybeCastSliceBound: | ||||
|     @pytest.fixture(params=["increasing", "decreasing", None]) | ||||
|     def monotonic(self, request): | ||||
|         return request.param | ||||
|  | ||||
|     @pytest.fixture | ||||
|     def tdi(self, monotonic): | ||||
|         tdi = timedelta_range("1 Day", periods=10) | ||||
|         if monotonic == "decreasing": | ||||
|             tdi = tdi[::-1] | ||||
|         elif monotonic is None: | ||||
|             taker = np.arange(10, dtype=np.intp) | ||||
|             np.random.default_rng(2).shuffle(taker) | ||||
|             tdi = tdi.take(taker) | ||||
|         return tdi | ||||
|  | ||||
|     def test_maybe_cast_slice_bound_invalid_str(self, tdi): | ||||
|         # test the low-level _maybe_cast_slice_bound and that we get the | ||||
|         #  expected exception+message all the way up the stack | ||||
|         msg = ( | ||||
|             "cannot do slice indexing on TimedeltaIndex with these " | ||||
|             r"indexers \[foo\] of type str" | ||||
|         ) | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             tdi._maybe_cast_slice_bound("foo", side="left") | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             tdi.get_slice_bound("foo", side="left") | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             tdi.slice_locs("foo", None, None) | ||||
|  | ||||
|     def test_slice_invalid_str_with_timedeltaindex( | ||||
|         self, tdi, frame_or_series, indexer_sl | ||||
|     ): | ||||
|         obj = frame_or_series(range(10), index=tdi) | ||||
|  | ||||
|         msg = ( | ||||
|             "cannot do slice indexing on TimedeltaIndex with these " | ||||
|             r"indexers \[foo\] of type str" | ||||
|         ) | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             indexer_sl(obj)["foo":] | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             indexer_sl(obj)["foo":-1] | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             indexer_sl(obj)[:"foo"] | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             indexer_sl(obj)[tdi[0] : "foo"] | ||||
|  | ||||
|  | ||||
| class TestContains: | ||||
|     def test_contains_nonunique(self): | ||||
|         # GH#9512 | ||||
|         for vals in ( | ||||
|             [0, 1, 0], | ||||
|             [0, 0, -1], | ||||
|             [0, -1, -1], | ||||
|             ["00:01:00", "00:01:00", "00:02:00"], | ||||
|             ["00:01:00", "00:01:00", "00:00:01"], | ||||
|         ): | ||||
|             idx = TimedeltaIndex(vals) | ||||
|             assert idx[0] in idx | ||||
|  | ||||
|     def test_contains(self): | ||||
|         # Checking for any NaT-like objects | ||||
|         # GH#13603 | ||||
|         td = to_timedelta(range(5), unit="d") + offsets.Hour(1) | ||||
|         for v in [NaT, None, float("nan"), np.nan]: | ||||
|             assert v not in td | ||||
|  | ||||
|         td = to_timedelta([NaT]) | ||||
|         for v in [NaT, None, float("nan"), np.nan]: | ||||
|             assert v in td | ||||
| @ -0,0 +1,47 @@ | ||||
| import numpy as np | ||||
|  | ||||
| from pandas import ( | ||||
|     DataFrame, | ||||
|     Index, | ||||
|     Timedelta, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestJoin: | ||||
|     def test_append_join_nondatetimeindex(self): | ||||
|         rng = timedelta_range("1 days", periods=10) | ||||
|         idx = Index(["a", "b", "c", "d"]) | ||||
|  | ||||
|         result = rng.append(idx) | ||||
|         assert isinstance(result[0], Timedelta) | ||||
|  | ||||
|         # it works | ||||
|         rng.join(idx, how="outer") | ||||
|  | ||||
|     def test_join_self(self, join_type): | ||||
|         index = timedelta_range("1 day", periods=10) | ||||
|         joined = index.join(index, how=join_type) | ||||
|         tm.assert_index_equal(index, joined) | ||||
|  | ||||
|     def test_does_not_convert_mixed_integer(self): | ||||
|         df = DataFrame(np.ones((5, 5)), columns=timedelta_range("1 day", periods=5)) | ||||
|  | ||||
|         cols = df.columns.join(df.index, how="outer") | ||||
|         joined = cols.join(df.columns) | ||||
|         assert cols.dtype == np.dtype("O") | ||||
|         assert cols.dtype == joined.dtype | ||||
|         tm.assert_index_equal(cols, joined) | ||||
|  | ||||
|     def test_join_preserves_freq(self): | ||||
|         # GH#32157 | ||||
|         tdi = timedelta_range("1 day", periods=10) | ||||
|         result = tdi[:5].join(tdi[5:], how="outer") | ||||
|         assert result.freq == tdi.freq | ||||
|         tm.assert_index_equal(result, tdi) | ||||
|  | ||||
|         result = tdi[:5].join(tdi[6:], how="outer") | ||||
|         assert result.freq is None | ||||
|         expected = tdi.delete(5) | ||||
|         tm.assert_index_equal(result, expected) | ||||
| @ -0,0 +1,14 @@ | ||||
| from pandas import ( | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexOps: | ||||
|     def test_infer_freq(self, freq_sample): | ||||
|         # GH#11018 | ||||
|         idx = timedelta_range("1", freq=freq_sample, periods=10) | ||||
|         result = TimedeltaIndex(idx.asi8, freq="infer") | ||||
|         tm.assert_index_equal(idx, result) | ||||
|         assert result.freq == freq_sample | ||||
| @ -0,0 +1,11 @@ | ||||
| from pandas import timedelta_range | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestPickle: | ||||
|     def test_pickle_after_set_freq(self): | ||||
|         tdi = timedelta_range("1 day", periods=4, freq="s") | ||||
|         tdi = tdi._with_freq(None) | ||||
|  | ||||
|         res = tm.round_trip_pickle(tdi) | ||||
|         tm.assert_index_equal(res, tdi) | ||||
| @ -0,0 +1,142 @@ | ||||
| """ | ||||
| Tests for TimedeltaIndex methods behaving like their Timedelta counterparts | ||||
| """ | ||||
|  | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas._libs.tslibs.offsets import INVALID_FREQ_ERR_MSG | ||||
|  | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     Series, | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestVectorizedTimedelta: | ||||
|     def test_tdi_total_seconds(self): | ||||
|         # GH#10939 | ||||
|         # test index | ||||
|         rng = timedelta_range("1 days, 10:11:12.100123456", periods=2, freq="s") | ||||
|         expt = [ | ||||
|             1 * 86400 + 10 * 3600 + 11 * 60 + 12 + 100123456.0 / 1e9, | ||||
|             1 * 86400 + 10 * 3600 + 11 * 60 + 13 + 100123456.0 / 1e9, | ||||
|         ] | ||||
|         tm.assert_almost_equal(rng.total_seconds(), Index(expt)) | ||||
|  | ||||
|         # test Series | ||||
|         ser = Series(rng) | ||||
|         s_expt = Series(expt, index=[0, 1]) | ||||
|         tm.assert_series_equal(ser.dt.total_seconds(), s_expt) | ||||
|  | ||||
|         # with nat | ||||
|         ser[1] = np.nan | ||||
|         s_expt = Series( | ||||
|             [1 * 86400 + 10 * 3600 + 11 * 60 + 12 + 100123456.0 / 1e9, np.nan], | ||||
|             index=[0, 1], | ||||
|         ) | ||||
|         tm.assert_series_equal(ser.dt.total_seconds(), s_expt) | ||||
|  | ||||
|     def test_tdi_total_seconds_all_nat(self): | ||||
|         # with both nat | ||||
|         ser = Series([np.nan, np.nan], dtype="timedelta64[ns]") | ||||
|         result = ser.dt.total_seconds() | ||||
|         expected = Series([np.nan, np.nan]) | ||||
|         tm.assert_series_equal(result, expected) | ||||
|  | ||||
|     def test_tdi_round(self): | ||||
|         td = timedelta_range(start="16801 days", periods=5, freq="30Min") | ||||
|         elt = td[1] | ||||
|  | ||||
|         expected_rng = TimedeltaIndex( | ||||
|             [ | ||||
|                 Timedelta("16801 days 00:00:00"), | ||||
|                 Timedelta("16801 days 00:00:00"), | ||||
|                 Timedelta("16801 days 01:00:00"), | ||||
|                 Timedelta("16801 days 02:00:00"), | ||||
|                 Timedelta("16801 days 02:00:00"), | ||||
|             ] | ||||
|         ) | ||||
|         expected_elt = expected_rng[1] | ||||
|  | ||||
|         tm.assert_index_equal(td.round(freq="h"), expected_rng) | ||||
|         assert elt.round(freq="h") == expected_elt | ||||
|  | ||||
|         msg = INVALID_FREQ_ERR_MSG | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             td.round(freq="foo") | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             elt.round(freq="foo") | ||||
|  | ||||
|         msg = "<MonthEnd> is a non-fixed frequency" | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             td.round(freq="ME") | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             elt.round(freq="ME") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "freq,msg", | ||||
|         [ | ||||
|             ("YE", "<YearEnd: month=12> is a non-fixed frequency"), | ||||
|             ("ME", "<MonthEnd> is a non-fixed frequency"), | ||||
|             ("foobar", "Invalid frequency: foobar"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_tdi_round_invalid(self, freq, msg): | ||||
|         t1 = timedelta_range("1 days", periods=3, freq="1 min 2 s 3 us") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             t1.round(freq) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             # Same test for TimedeltaArray | ||||
|             t1._data.round(freq) | ||||
|  | ||||
|     # TODO: de-duplicate with test_tdi_round | ||||
|     def test_round(self): | ||||
|         t1 = timedelta_range("1 days", periods=3, freq="1 min 2 s 3 us") | ||||
|         t2 = -1 * t1 | ||||
|         t1a = timedelta_range("1 days", periods=3, freq="1 min 2 s") | ||||
|         t1c = TimedeltaIndex(np.array([1, 1, 1], "m8[D]")).as_unit("ns") | ||||
|  | ||||
|         # note that negative times round DOWN! so don't give whole numbers | ||||
|         for freq, s1, s2 in [ | ||||
|             ("ns", t1, t2), | ||||
|             ("us", t1, t2), | ||||
|             ( | ||||
|                 "ms", | ||||
|                 t1a, | ||||
|                 TimedeltaIndex( | ||||
|                     ["-1 days +00:00:00", "-2 days +23:58:58", "-2 days +23:57:56"] | ||||
|                 ), | ||||
|             ), | ||||
|             ( | ||||
|                 "s", | ||||
|                 t1a, | ||||
|                 TimedeltaIndex( | ||||
|                     ["-1 days +00:00:00", "-2 days +23:58:58", "-2 days +23:57:56"] | ||||
|                 ), | ||||
|             ), | ||||
|             ("12min", t1c, TimedeltaIndex(["-1 days", "-1 days", "-1 days"])), | ||||
|             ("h", t1c, TimedeltaIndex(["-1 days", "-1 days", "-1 days"])), | ||||
|             ("d", t1c, -1 * t1c), | ||||
|         ]: | ||||
|             r1 = t1.round(freq) | ||||
|             tm.assert_index_equal(r1, s1) | ||||
|             r2 = t2.round(freq) | ||||
|             tm.assert_index_equal(r2, s2) | ||||
|  | ||||
|     def test_components(self): | ||||
|         rng = timedelta_range("1 days, 10:11:12", periods=2, freq="s") | ||||
|         rng.components | ||||
|  | ||||
|         # with nat | ||||
|         s = Series(rng) | ||||
|         s[1] = np.nan | ||||
|  | ||||
|         result = s.dt.components | ||||
|         assert not result.iloc[0].isna().all() | ||||
|         assert result.iloc[1].isna().all() | ||||
| @ -0,0 +1,28 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     TimedeltaIndex, | ||||
|     Timestamp, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestSearchSorted: | ||||
|     def test_searchsorted_different_argument_classes(self, listlike_box): | ||||
|         idx = TimedeltaIndex(["1 day", "2 days", "3 days"]) | ||||
|         result = idx.searchsorted(listlike_box(idx)) | ||||
|         expected = np.arange(len(idx), dtype=result.dtype) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|         result = idx._data.searchsorted(listlike_box(idx)) | ||||
|         tm.assert_numpy_array_equal(result, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "arg", [[1, 2], ["a", "b"], [Timestamp("2020-01-01", tz="Europe/London")] * 2] | ||||
|     ) | ||||
|     def test_searchsorted_invalid_argument_dtype(self, arg): | ||||
|         idx = TimedeltaIndex(["1 day", "2 days", "3 days"]) | ||||
|         msg = "value should be a 'Timedelta', 'NaT', or array of those. Got" | ||||
|         with pytest.raises(TypeError, match=msg): | ||||
|             idx.searchsorted(arg) | ||||
| @ -0,0 +1,254 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| import pandas as pd | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
| from pandas.tseries.offsets import Hour | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndex: | ||||
|     def test_union(self): | ||||
|         i1 = timedelta_range("1day", periods=5) | ||||
|         i2 = timedelta_range("3day", periods=5) | ||||
|         result = i1.union(i2) | ||||
|         expected = timedelta_range("1day", periods=7) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         i1 = Index(np.arange(0, 20, 2, dtype=np.int64)) | ||||
|         i2 = timedelta_range(start="1 day", periods=10, freq="D") | ||||
|         i1.union(i2)  # Works | ||||
|         i2.union(i1)  # Fails with "AttributeError: can't set attribute" | ||||
|  | ||||
|     def test_union_sort_false(self): | ||||
|         tdi = timedelta_range("1day", periods=5) | ||||
|  | ||||
|         left = tdi[3:] | ||||
|         right = tdi[:3] | ||||
|  | ||||
|         # Check that we are testing the desired code path | ||||
|         assert left._can_fast_union(right) | ||||
|  | ||||
|         result = left.union(right) | ||||
|         tm.assert_index_equal(result, tdi) | ||||
|  | ||||
|         result = left.union(right, sort=False) | ||||
|         expected = TimedeltaIndex(["4 Days", "5 Days", "1 Days", "2 Day", "3 Days"]) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_union_coverage(self): | ||||
|         idx = TimedeltaIndex(["3d", "1d", "2d"]) | ||||
|         ordered = TimedeltaIndex(idx.sort_values(), freq="infer") | ||||
|         result = ordered.union(idx) | ||||
|         tm.assert_index_equal(result, ordered) | ||||
|  | ||||
|         result = ordered[:0].union(ordered) | ||||
|         tm.assert_index_equal(result, ordered) | ||||
|         assert result.freq == ordered.freq | ||||
|  | ||||
|     def test_union_bug_1730(self): | ||||
|         rng_a = timedelta_range("1 day", periods=4, freq="3h") | ||||
|         rng_b = timedelta_range("1 day", periods=4, freq="4h") | ||||
|  | ||||
|         result = rng_a.union(rng_b) | ||||
|         exp = TimedeltaIndex(sorted(set(rng_a) | set(rng_b))) | ||||
|         tm.assert_index_equal(result, exp) | ||||
|  | ||||
|     def test_union_bug_1745(self): | ||||
|         left = TimedeltaIndex(["1 day 15:19:49.695000"]) | ||||
|         right = TimedeltaIndex( | ||||
|             ["2 day 13:04:21.322000", "1 day 15:27:24.873000", "1 day 15:31:05.350000"] | ||||
|         ) | ||||
|  | ||||
|         result = left.union(right) | ||||
|         exp = TimedeltaIndex(sorted(set(left) | set(right))) | ||||
|         tm.assert_index_equal(result, exp) | ||||
|  | ||||
|     def test_union_bug_4564(self): | ||||
|         left = timedelta_range("1 day", "30d") | ||||
|         right = left + pd.offsets.Minute(15) | ||||
|  | ||||
|         result = left.union(right) | ||||
|         exp = TimedeltaIndex(sorted(set(left) | set(right))) | ||||
|         tm.assert_index_equal(result, exp) | ||||
|  | ||||
|     def test_union_freq_infer(self): | ||||
|         # When taking the union of two TimedeltaIndexes, we infer | ||||
|         #  a freq even if the arguments don't have freq.  This matches | ||||
|         #  DatetimeIndex behavior. | ||||
|         tdi = timedelta_range("1 Day", periods=5) | ||||
|         left = tdi[[0, 1, 3, 4]] | ||||
|         right = tdi[[2, 3, 1]] | ||||
|  | ||||
|         assert left.freq is None | ||||
|         assert right.freq is None | ||||
|  | ||||
|         result = left.union(right) | ||||
|         tm.assert_index_equal(result, tdi) | ||||
|         assert result.freq == "D" | ||||
|  | ||||
|     def test_intersection_bug_1708(self): | ||||
|         index_1 = timedelta_range("1 day", periods=4, freq="h") | ||||
|         index_2 = index_1 + pd.offsets.Hour(5) | ||||
|  | ||||
|         result = index_1.intersection(index_2) | ||||
|         assert len(result) == 0 | ||||
|  | ||||
|         index_1 = timedelta_range("1 day", periods=4, freq="h") | ||||
|         index_2 = index_1 + pd.offsets.Hour(1) | ||||
|  | ||||
|         result = index_1.intersection(index_2) | ||||
|         expected = timedelta_range("1 day 01:00:00", periods=3, freq="h") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert result.freq == expected.freq | ||||
|  | ||||
|     def test_intersection_equal(self, sort): | ||||
|         # GH 24471 Test intersection outcome given the sort keyword | ||||
|         # for equal indices intersection should return the original index | ||||
|         first = timedelta_range("1 day", periods=4, freq="h") | ||||
|         second = timedelta_range("1 day", periods=4, freq="h") | ||||
|         intersect = first.intersection(second, sort=sort) | ||||
|         if sort is None: | ||||
|             tm.assert_index_equal(intersect, second.sort_values()) | ||||
|         tm.assert_index_equal(intersect, second) | ||||
|  | ||||
|         # Corner cases | ||||
|         inter = first.intersection(first, sort=sort) | ||||
|         assert inter is first | ||||
|  | ||||
|     @pytest.mark.parametrize("period_1, period_2", [(0, 4), (4, 0)]) | ||||
|     def test_intersection_zero_length(self, period_1, period_2, sort): | ||||
|         # GH 24471 test for non overlap the intersection should be zero length | ||||
|         index_1 = timedelta_range("1 day", periods=period_1, freq="h") | ||||
|         index_2 = timedelta_range("1 day", periods=period_2, freq="h") | ||||
|         expected = timedelta_range("1 day", periods=0, freq="h") | ||||
|         result = index_1.intersection(index_2, sort=sort) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_zero_length_input_index(self, sort): | ||||
|         # GH 24966 test for 0-len intersections are copied | ||||
|         index_1 = timedelta_range("1 day", periods=0, freq="h") | ||||
|         index_2 = timedelta_range("1 day", periods=3, freq="h") | ||||
|         result = index_1.intersection(index_2, sort=sort) | ||||
|         assert index_1 is not result | ||||
|         assert index_2 is not result | ||||
|         tm.assert_copy(result, index_1) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "rng, expected", | ||||
|         # if target has the same name, it is preserved | ||||
|         [ | ||||
|             ( | ||||
|                 timedelta_range("1 day", periods=5, freq="h", name="idx"), | ||||
|                 timedelta_range("1 day", periods=4, freq="h", name="idx"), | ||||
|             ), | ||||
|             # if target name is different, it will be reset | ||||
|             ( | ||||
|                 timedelta_range("1 day", periods=5, freq="h", name="other"), | ||||
|                 timedelta_range("1 day", periods=4, freq="h", name=None), | ||||
|             ), | ||||
|             # if no overlap exists return empty index | ||||
|             ( | ||||
|                 timedelta_range("1 day", periods=10, freq="h", name="idx")[5:], | ||||
|                 TimedeltaIndex([], freq="h", name="idx"), | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_intersection(self, rng, expected, sort): | ||||
|         # GH 4690 (with tz) | ||||
|         base = timedelta_range("1 day", periods=4, freq="h", name="idx") | ||||
|         result = base.intersection(rng, sort=sort) | ||||
|         if sort is None: | ||||
|             expected = expected.sort_values() | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert result.name == expected.name | ||||
|         assert result.freq == expected.freq | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "rng, expected", | ||||
|         # part intersection works | ||||
|         [ | ||||
|             ( | ||||
|                 TimedeltaIndex(["5 hour", "2 hour", "4 hour", "9 hour"], name="idx"), | ||||
|                 TimedeltaIndex(["2 hour", "4 hour"], name="idx"), | ||||
|             ), | ||||
|             # reordered part intersection | ||||
|             ( | ||||
|                 TimedeltaIndex(["2 hour", "5 hour", "5 hour", "1 hour"], name="other"), | ||||
|                 TimedeltaIndex(["1 hour", "2 hour"], name=None), | ||||
|             ), | ||||
|             # reversed index | ||||
|             ( | ||||
|                 TimedeltaIndex(["1 hour", "2 hour", "4 hour", "3 hour"], name="idx")[ | ||||
|                     ::-1 | ||||
|                 ], | ||||
|                 TimedeltaIndex(["1 hour", "2 hour", "4 hour", "3 hour"], name="idx"), | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_intersection_non_monotonic(self, rng, expected, sort): | ||||
|         # 24471 non-monotonic | ||||
|         base = TimedeltaIndex(["1 hour", "2 hour", "4 hour", "3 hour"], name="idx") | ||||
|         result = base.intersection(rng, sort=sort) | ||||
|         if sort is None: | ||||
|             expected = expected.sort_values() | ||||
|         tm.assert_index_equal(result, expected) | ||||
|         assert result.name == expected.name | ||||
|  | ||||
|         # if reversed order, frequency is still the same | ||||
|         if all(base == rng[::-1]) and sort is None: | ||||
|             assert isinstance(result.freq, Hour) | ||||
|         else: | ||||
|             assert result.freq is None | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndexDifference: | ||||
|     def test_difference_freq(self, sort): | ||||
|         # GH14323: Difference of TimedeltaIndex should not preserve frequency | ||||
|  | ||||
|         index = timedelta_range("0 days", "5 days", freq="D") | ||||
|  | ||||
|         other = timedelta_range("1 days", "4 days", freq="D") | ||||
|         expected = TimedeltaIndex(["0 days", "5 days"], freq=None) | ||||
|         idx_diff = index.difference(other, sort) | ||||
|         tm.assert_index_equal(idx_diff, expected) | ||||
|         tm.assert_attr_equal("freq", idx_diff, expected) | ||||
|  | ||||
|         # preserve frequency when the difference is a contiguous | ||||
|         # subset of the original range | ||||
|         other = timedelta_range("2 days", "5 days", freq="D") | ||||
|         idx_diff = index.difference(other, sort) | ||||
|         expected = TimedeltaIndex(["0 days", "1 days"], freq="D") | ||||
|         tm.assert_index_equal(idx_diff, expected) | ||||
|         tm.assert_attr_equal("freq", idx_diff, expected) | ||||
|  | ||||
|     def test_difference_sort(self, sort): | ||||
|         index = TimedeltaIndex( | ||||
|             ["5 days", "3 days", "2 days", "4 days", "1 days", "0 days"] | ||||
|         ) | ||||
|  | ||||
|         other = timedelta_range("1 days", "4 days", freq="D") | ||||
|         idx_diff = index.difference(other, sort) | ||||
|  | ||||
|         expected = TimedeltaIndex(["5 days", "0 days"], freq=None) | ||||
|  | ||||
|         if sort is None: | ||||
|             expected = expected.sort_values() | ||||
|  | ||||
|         tm.assert_index_equal(idx_diff, expected) | ||||
|         tm.assert_attr_equal("freq", idx_diff, expected) | ||||
|  | ||||
|         other = timedelta_range("2 days", "5 days", freq="D") | ||||
|         idx_diff = index.difference(other, sort) | ||||
|         expected = TimedeltaIndex(["1 days", "0 days"], freq=None) | ||||
|  | ||||
|         if sort is None: | ||||
|             expected = expected.sort_values() | ||||
|  | ||||
|         tm.assert_index_equal(idx_diff, expected) | ||||
|         tm.assert_attr_equal("freq", idx_diff, expected) | ||||
| @ -0,0 +1,61 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Index, | ||||
|     Series, | ||||
|     Timedelta, | ||||
|     timedelta_range, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
|  | ||||
| class TestTimedeltaIndex: | ||||
|     def test_misc_coverage(self): | ||||
|         rng = timedelta_range("1 day", periods=5) | ||||
|         result = rng.groupby(rng.days) | ||||
|         assert isinstance(next(iter(result.values()))[0], Timedelta) | ||||
|  | ||||
|     def test_map(self): | ||||
|         # test_map_dictlike generally tests | ||||
|  | ||||
|         rng = timedelta_range("1 day", periods=10) | ||||
|  | ||||
|         f = lambda x: x.days | ||||
|         result = rng.map(f) | ||||
|         exp = Index([f(x) for x in rng], dtype=np.int64) | ||||
|         tm.assert_index_equal(result, exp) | ||||
|  | ||||
|     def test_fields(self): | ||||
|         rng = timedelta_range("1 days, 10:11:12.100123456", periods=2, freq="s") | ||||
|         tm.assert_index_equal(rng.days, Index([1, 1], dtype=np.int64)) | ||||
|         tm.assert_index_equal( | ||||
|             rng.seconds, | ||||
|             Index([10 * 3600 + 11 * 60 + 12, 10 * 3600 + 11 * 60 + 13], dtype=np.int32), | ||||
|         ) | ||||
|         tm.assert_index_equal( | ||||
|             rng.microseconds, | ||||
|             Index([100 * 1000 + 123, 100 * 1000 + 123], dtype=np.int32), | ||||
|         ) | ||||
|         tm.assert_index_equal(rng.nanoseconds, Index([456, 456], dtype=np.int32)) | ||||
|  | ||||
|         msg = "'TimedeltaIndex' object has no attribute '{}'" | ||||
|         with pytest.raises(AttributeError, match=msg.format("hours")): | ||||
|             rng.hours | ||||
|         with pytest.raises(AttributeError, match=msg.format("minutes")): | ||||
|             rng.minutes | ||||
|         with pytest.raises(AttributeError, match=msg.format("milliseconds")): | ||||
|             rng.milliseconds | ||||
|  | ||||
|         # with nat | ||||
|         s = Series(rng) | ||||
|         s[1] = np.nan | ||||
|  | ||||
|         tm.assert_series_equal(s.dt.days, Series([1, np.nan], index=[0, 1])) | ||||
|         tm.assert_series_equal( | ||||
|             s.dt.seconds, Series([10 * 3600 + 11 * 60 + 12, np.nan], index=[0, 1]) | ||||
|         ) | ||||
|  | ||||
|         # preserve name (GH15589) | ||||
|         rng.name = "name" | ||||
|         assert rng.days.name == "name" | ||||
| @ -0,0 +1,173 @@ | ||||
| import numpy as np | ||||
| import pytest | ||||
|  | ||||
| from pandas import ( | ||||
|     Timedelta, | ||||
|     TimedeltaIndex, | ||||
|     timedelta_range, | ||||
|     to_timedelta, | ||||
| ) | ||||
| import pandas._testing as tm | ||||
|  | ||||
| from pandas.tseries.offsets import ( | ||||
|     Day, | ||||
|     Second, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class TestTimedeltas: | ||||
|     def test_timedelta_range_unit(self): | ||||
|         # GH#49824 | ||||
|         tdi = timedelta_range("0 Days", periods=10, freq="100000D", unit="s") | ||||
|         exp_arr = (np.arange(10, dtype="i8") * 100_000).view("m8[D]").astype("m8[s]") | ||||
|         tm.assert_numpy_array_equal(tdi.to_numpy(), exp_arr) | ||||
|  | ||||
|     def test_timedelta_range(self): | ||||
|         expected = to_timedelta(np.arange(5), unit="D") | ||||
|         result = timedelta_range("0 days", periods=5, freq="D") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         expected = to_timedelta(np.arange(11), unit="D") | ||||
|         result = timedelta_range("0 days", "10 days", freq="D") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         expected = to_timedelta(np.arange(5), unit="D") + Second(2) + Day() | ||||
|         result = timedelta_range("1 days, 00:00:02", "5 days, 00:00:02", freq="D") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         expected = to_timedelta([1, 3, 5, 7, 9], unit="D") + Second(2) | ||||
|         result = timedelta_range("1 days, 00:00:02", periods=5, freq="2D") | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|         expected = to_timedelta(np.arange(50), unit="min") * 30 | ||||
|         result = timedelta_range("0 days", freq="30min", periods=50) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "depr_unit, unit", | ||||
|         [ | ||||
|             ("H", "hour"), | ||||
|             ("T", "minute"), | ||||
|             ("t", "minute"), | ||||
|             ("S", "second"), | ||||
|             ("L", "millisecond"), | ||||
|             ("l", "millisecond"), | ||||
|             ("U", "microsecond"), | ||||
|             ("u", "microsecond"), | ||||
|             ("N", "nanosecond"), | ||||
|             ("n", "nanosecond"), | ||||
|         ], | ||||
|     ) | ||||
|     def test_timedelta_units_H_T_S_L_U_N_deprecated(self, depr_unit, unit): | ||||
|         # GH#52536 | ||||
|         depr_msg = ( | ||||
|             f"'{depr_unit}' is deprecated and will be removed in a future version." | ||||
|         ) | ||||
|  | ||||
|         expected = to_timedelta(np.arange(5), unit=unit) | ||||
|         with tm.assert_produces_warning(FutureWarning, match=depr_msg): | ||||
|             result = to_timedelta(np.arange(5), unit=depr_unit) | ||||
|             tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "periods, freq", [(3, "2D"), (5, "D"), (6, "19h12min"), (7, "16h"), (9, "12h")] | ||||
|     ) | ||||
|     def test_linspace_behavior(self, periods, freq): | ||||
|         # GH 20976 | ||||
|         result = timedelta_range(start="0 days", end="4 days", periods=periods) | ||||
|         expected = timedelta_range(start="0 days", end="4 days", freq=freq) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     @pytest.mark.parametrize("msg_freq, freq", [("H", "19H12min"), ("T", "19h12T")]) | ||||
|     def test_timedelta_range_H_T_deprecated(self, freq, msg_freq): | ||||
|         # GH#52536 | ||||
|         msg = f"'{msg_freq}' is deprecated and will be removed in a future version." | ||||
|  | ||||
|         result = timedelta_range(start="0 days", end="4 days", periods=6) | ||||
|         with tm.assert_produces_warning(FutureWarning, match=msg): | ||||
|             expected = timedelta_range(start="0 days", end="4 days", freq=freq) | ||||
|         tm.assert_index_equal(result, expected) | ||||
|  | ||||
|     def test_errors(self): | ||||
|         # not enough params | ||||
|         msg = ( | ||||
|             "Of the four parameters: start, end, periods, and freq, " | ||||
|             "exactly three must be specified" | ||||
|         ) | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range(start="0 days") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range(end="5 days") | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range(periods=2) | ||||
|  | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range() | ||||
|  | ||||
|         # too many params | ||||
|         with pytest.raises(ValueError, match=msg): | ||||
|             timedelta_range(start="0 days", end="5 days", periods=10, freq="h") | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "start, end, freq, expected_periods", | ||||
|         [ | ||||
|             ("1D", "10D", "2D", (10 - 1) // 2 + 1), | ||||
|             ("2D", "30D", "3D", (30 - 2) // 3 + 1), | ||||
|             ("2s", "50s", "5s", (50 - 2) // 5 + 1), | ||||
|             # tests that worked before GH 33498: | ||||
|             ("4D", "16D", "3D", (16 - 4) // 3 + 1), | ||||
|             ("8D", "16D", "40s", (16 * 3600 * 24 - 8 * 3600 * 24) // 40 + 1), | ||||
|         ], | ||||
|     ) | ||||
|     def test_timedelta_range_freq_divide_end(self, start, end, freq, expected_periods): | ||||
|         # GH 33498 only the cases where `(end % freq) == 0` used to fail | ||||
|         res = timedelta_range(start=start, end=end, freq=freq) | ||||
|         assert Timedelta(start) == res[0] | ||||
|         assert Timedelta(end) >= res[-1] | ||||
|         assert len(res) == expected_periods | ||||
|  | ||||
|     def test_timedelta_range_infer_freq(self): | ||||
|         # https://github.com/pandas-dev/pandas/issues/35897 | ||||
|         result = timedelta_range("0s", "1s", periods=31) | ||||
|         assert result.freq is None | ||||
|  | ||||
|     @pytest.mark.parametrize( | ||||
|         "freq_depr, start, end, expected_values, expected_freq", | ||||
|         [ | ||||
|             ( | ||||
|                 "3.5S", | ||||
|                 "05:03:01", | ||||
|                 "05:03:10", | ||||
|                 ["0 days 05:03:01", "0 days 05:03:04.500000", "0 days 05:03:08"], | ||||
|                 "3500ms", | ||||
|             ), | ||||
|             ( | ||||
|                 "2.5T", | ||||
|                 "5 hours", | ||||
|                 "5 hours 8 minutes", | ||||
|                 [ | ||||
|                     "0 days 05:00:00", | ||||
|                     "0 days 05:02:30", | ||||
|                     "0 days 05:05:00", | ||||
|                     "0 days 05:07:30", | ||||
|                 ], | ||||
|                 "150s", | ||||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_timedelta_range_deprecated_freq( | ||||
|         self, freq_depr, start, end, expected_values, expected_freq | ||||
|     ): | ||||
|         # GH#52536 | ||||
|         msg = ( | ||||
|             f"'{freq_depr[-1]}' is deprecated and will be removed in a future version." | ||||
|         ) | ||||
|  | ||||
|         with tm.assert_produces_warning(FutureWarning, match=msg): | ||||
|             result = timedelta_range(start=start, end=end, freq=freq_depr) | ||||
|         expected = TimedeltaIndex( | ||||
|             expected_values, dtype="timedelta64[ns]", freq=expected_freq | ||||
|         ) | ||||
|         tm.assert_index_equal(result, expected) | ||||
		Reference in New Issue
	
	Block a user