forked from Alsan/Post_finder
venv
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,176 @@
|
||||
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):
|
||||
# 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)
|
||||
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