Skip to content

Commit 9a02c35

Browse files
authored
TST: parametrize and de-duplicate timedelta64 arithmetic tests (#32091)
1 parent d4293f0 commit 9a02c35

File tree

1 file changed

+71
-141
lines changed

1 file changed

+71
-141
lines changed

pandas/tests/arithmetic/test_timedelta64.py

+71-141
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@
2525
get_upcast_box,
2626
)
2727

28+
29+
def assert_dtype(obj, expected_dtype):
30+
"""
31+
Helper to check the dtype for a Series, Index, or single-column DataFrame.
32+
"""
33+
if isinstance(obj, DataFrame):
34+
dtype = obj.dtypes.iat[0]
35+
else:
36+
dtype = obj.dtype
37+
38+
assert dtype == expected_dtype
39+
40+
2841
# ------------------------------------------------------------------
2942
# Timedelta64[ns] dtype Comparisons
3043

@@ -522,19 +535,35 @@ def test_tda_add_sub_index(self):
522535
# -------------------------------------------------------------
523536
# Binary operations TimedeltaIndex and timedelta-like
524537

525-
def test_tdi_iadd_timedeltalike(self, two_hours):
538+
def test_tdi_iadd_timedeltalike(self, two_hours, box_with_array):
526539
# only test adding/sub offsets as + is now numeric
527540
rng = timedelta_range("1 days", "10 days")
528541
expected = timedelta_range("1 days 02:00:00", "10 days 02:00:00", freq="D")
542+
543+
rng = tm.box_expected(rng, box_with_array)
544+
expected = tm.box_expected(expected, box_with_array)
545+
546+
orig_rng = rng
529547
rng += two_hours
530-
tm.assert_index_equal(rng, expected)
548+
tm.assert_equal(rng, expected)
549+
if box_with_array is not pd.Index:
550+
# Check that operation is actually inplace
551+
tm.assert_equal(orig_rng, expected)
531552

532-
def test_tdi_isub_timedeltalike(self, two_hours):
553+
def test_tdi_isub_timedeltalike(self, two_hours, box_with_array):
533554
# only test adding/sub offsets as - is now numeric
534555
rng = timedelta_range("1 days", "10 days")
535556
expected = timedelta_range("0 days 22:00:00", "9 days 22:00:00")
557+
558+
rng = tm.box_expected(rng, box_with_array)
559+
expected = tm.box_expected(expected, box_with_array)
560+
561+
orig_rng = rng
536562
rng -= two_hours
537-
tm.assert_index_equal(rng, expected)
563+
tm.assert_equal(rng, expected)
564+
if box_with_array is not pd.Index:
565+
# Check that operation is actually inplace
566+
tm.assert_equal(orig_rng, expected)
538567

539568
# -------------------------------------------------------------
540569

@@ -1013,15 +1042,6 @@ def test_td64arr_add_datetime64_nat(self, box_with_array):
10131042
# ------------------------------------------------------------------
10141043
# Invalid __add__/__sub__ operations
10151044

1016-
# TODO: moved from frame tests; needs parametrization/de-duplication
1017-
def test_td64_df_add_int_frame(self):
1018-
# GH#22696 Check that we don't dispatch to numpy implementation,
1019-
# which treats int64 as m8[ns]
1020-
tdi = pd.timedelta_range("1", periods=3)
1021-
df = tdi.to_frame()
1022-
other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df`
1023-
assert_invalid_addsub_type(df, other)
1024-
10251045
@pytest.mark.parametrize("pi_freq", ["D", "W", "Q", "H"])
10261046
@pytest.mark.parametrize("tdi_freq", [None, "H"])
10271047
def test_td64arr_sub_periodlike(self, box_with_array, tdi_freq, pi_freq):
@@ -1100,6 +1120,9 @@ def test_td64arr_add_sub_int(self, box_with_array, one):
11001120

11011121
def test_td64arr_add_sub_integer_array(self, box_with_array):
11021122
# GH#19959, deprecated GH#22535
1123+
# GH#22696 for DataFrame case, check that we don't dispatch to numpy
1124+
# implementation, which treats int64 as m8[ns]
1125+
11031126
rng = timedelta_range("1 days 09:00:00", freq="H", periods=3)
11041127
tdarr = tm.box_expected(rng, box_with_array)
11051128
other = tm.box_expected([4, 3, 2], box_with_array)
@@ -1119,60 +1142,6 @@ def test_td64arr_addsub_integer_array_no_freq(self, box_with_array):
11191142
# ------------------------------------------------------------------
11201143
# Operations with timedelta-like others
11211144

1122-
# TODO: this was taken from tests.series.test_ops; de-duplicate
1123-
def test_operators_timedelta64_with_timedelta(self, scalar_td):
1124-
# smoke tests
1125-
td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
1126-
td1.iloc[2] = np.nan
1127-
1128-
td1 + scalar_td
1129-
scalar_td + td1
1130-
td1 - scalar_td
1131-
scalar_td - td1
1132-
td1 / scalar_td
1133-
scalar_td / td1
1134-
1135-
# TODO: this was taken from tests.series.test_ops; de-duplicate
1136-
def test_timedelta64_operations_with_timedeltas(self):
1137-
# td operate with td
1138-
td1 = Series([timedelta(minutes=5, seconds=3)] * 3)
1139-
td2 = timedelta(minutes=5, seconds=4)
1140-
result = td1 - td2
1141-
expected = Series([timedelta(seconds=0)] * 3) - Series(
1142-
[timedelta(seconds=1)] * 3
1143-
)
1144-
assert result.dtype == "m8[ns]"
1145-
tm.assert_series_equal(result, expected)
1146-
1147-
result2 = td2 - td1
1148-
expected = Series([timedelta(seconds=1)] * 3) - Series(
1149-
[timedelta(seconds=0)] * 3
1150-
)
1151-
tm.assert_series_equal(result2, expected)
1152-
1153-
# roundtrip
1154-
tm.assert_series_equal(result + td2, td1)
1155-
1156-
# Now again, using pd.to_timedelta, which should build
1157-
# a Series or a scalar, depending on input.
1158-
td1 = Series(pd.to_timedelta(["00:05:03"] * 3))
1159-
td2 = pd.to_timedelta("00:05:04")
1160-
result = td1 - td2
1161-
expected = Series([timedelta(seconds=0)] * 3) - Series(
1162-
[timedelta(seconds=1)] * 3
1163-
)
1164-
assert result.dtype == "m8[ns]"
1165-
tm.assert_series_equal(result, expected)
1166-
1167-
result2 = td2 - td1
1168-
expected = Series([timedelta(seconds=1)] * 3) - Series(
1169-
[timedelta(seconds=0)] * 3
1170-
)
1171-
tm.assert_series_equal(result2, expected)
1172-
1173-
# roundtrip
1174-
tm.assert_series_equal(result + td2, td1)
1175-
11761145
def test_td64arr_add_td64_array(self, box_with_array):
11771146
box = box_with_array
11781147
dti = pd.date_range("2016-01-01", periods=3)
@@ -1203,7 +1172,6 @@ def test_td64arr_sub_td64_array(self, box_with_array):
12031172
result = tdarr - tdi
12041173
tm.assert_equal(result, expected)
12051174

1206-
# TODO: parametrize over [add, sub, radd, rsub]?
12071175
@pytest.mark.parametrize(
12081176
"names",
12091177
[
@@ -1232,17 +1200,11 @@ def test_td64arr_add_sub_tdi(self, box, names):
12321200

12331201
result = tdi + ser
12341202
tm.assert_equal(result, expected)
1235-
if box is not pd.DataFrame:
1236-
assert result.dtype == "timedelta64[ns]"
1237-
else:
1238-
assert result.dtypes[0] == "timedelta64[ns]"
1203+
assert_dtype(result, "timedelta64[ns]")
12391204

12401205
result = ser + tdi
12411206
tm.assert_equal(result, expected)
1242-
if box is not pd.DataFrame:
1243-
assert result.dtype == "timedelta64[ns]"
1244-
else:
1245-
assert result.dtypes[0] == "timedelta64[ns]"
1207+
assert_dtype(result, "timedelta64[ns]")
12461208

12471209
expected = Series(
12481210
[Timedelta(hours=-3), Timedelta(days=1, hours=-4)], name=names[2]
@@ -1251,17 +1213,11 @@ def test_td64arr_add_sub_tdi(self, box, names):
12511213

12521214
result = tdi - ser
12531215
tm.assert_equal(result, expected)
1254-
if box is not pd.DataFrame:
1255-
assert result.dtype == "timedelta64[ns]"
1256-
else:
1257-
assert result.dtypes[0] == "timedelta64[ns]"
1216+
assert_dtype(result, "timedelta64[ns]")
12581217

12591218
result = ser - tdi
12601219
tm.assert_equal(result, -expected)
1261-
if box is not pd.DataFrame:
1262-
assert result.dtype == "timedelta64[ns]"
1263-
else:
1264-
assert result.dtypes[0] == "timedelta64[ns]"
1220+
assert_dtype(result, "timedelta64[ns]")
12651221

12661222
def test_td64arr_add_sub_td64_nat(self, box_with_array):
12671223
# GH#23320 special handling for timedelta64("NaT")
@@ -1296,6 +1252,7 @@ def test_td64arr_sub_NaT(self, box_with_array):
12961252

12971253
def test_td64arr_add_timedeltalike(self, two_hours, box_with_array):
12981254
# only test adding/sub offsets as + is now numeric
1255+
# GH#10699 for Tick cases
12991256
box = box_with_array
13001257
rng = timedelta_range("1 days", "10 days")
13011258
expected = timedelta_range("1 days 02:00:00", "10 days 02:00:00", freq="D")
@@ -1305,8 +1262,12 @@ def test_td64arr_add_timedeltalike(self, two_hours, box_with_array):
13051262
result = rng + two_hours
13061263
tm.assert_equal(result, expected)
13071264

1265+
result = two_hours + rng
1266+
tm.assert_equal(result, expected)
1267+
13081268
def test_td64arr_sub_timedeltalike(self, two_hours, box_with_array):
13091269
# only test adding/sub offsets as - is now numeric
1270+
# GH#10699 for Tick cases
13101271
box = box_with_array
13111272
rng = timedelta_range("1 days", "10 days")
13121273
expected = timedelta_range("0 days 22:00:00", "9 days 22:00:00")
@@ -1317,46 +1278,12 @@ def test_td64arr_sub_timedeltalike(self, two_hours, box_with_array):
13171278
result = rng - two_hours
13181279
tm.assert_equal(result, expected)
13191280

1281+
result = two_hours - rng
1282+
tm.assert_equal(result, -expected)
1283+
13201284
# ------------------------------------------------------------------
13211285
# __add__/__sub__ with DateOffsets and arrays of DateOffsets
13221286

1323-
# TODO: this was taken from tests.series.test_operators; de-duplicate
1324-
def test_timedelta64_operations_with_DateOffset(self):
1325-
# GH#10699
1326-
td = Series([timedelta(minutes=5, seconds=3)] * 3)
1327-
result = td + pd.offsets.Minute(1)
1328-
expected = Series([timedelta(minutes=6, seconds=3)] * 3)
1329-
tm.assert_series_equal(result, expected)
1330-
1331-
result = td - pd.offsets.Minute(1)
1332-
expected = Series([timedelta(minutes=4, seconds=3)] * 3)
1333-
tm.assert_series_equal(result, expected)
1334-
1335-
with tm.assert_produces_warning(PerformanceWarning):
1336-
result = td + Series(
1337-
[pd.offsets.Minute(1), pd.offsets.Second(3), pd.offsets.Hour(2)]
1338-
)
1339-
expected = Series(
1340-
[
1341-
timedelta(minutes=6, seconds=3),
1342-
timedelta(minutes=5, seconds=6),
1343-
timedelta(hours=2, minutes=5, seconds=3),
1344-
]
1345-
)
1346-
tm.assert_series_equal(result, expected)
1347-
1348-
result = td + pd.offsets.Minute(1) + pd.offsets.Second(12)
1349-
expected = Series([timedelta(minutes=6, seconds=15)] * 3)
1350-
tm.assert_series_equal(result, expected)
1351-
1352-
# valid DateOffsets
1353-
for do in ["Hour", "Minute", "Second", "Day", "Micro", "Milli", "Nano"]:
1354-
op = getattr(pd.offsets, do)
1355-
td + op(5)
1356-
op(5) + td
1357-
td - op(5)
1358-
op(5) - td
1359-
13601287
@pytest.mark.parametrize(
13611288
"names", [(None, None, None), ("foo", "bar", None), ("foo", "foo", "foo")]
13621289
)
@@ -1561,26 +1488,6 @@ class TestTimedeltaArraylikeMulDivOps:
15611488
# Tests for timedelta64[ns]
15621489
# __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__
15631490

1564-
# TODO: Moved from tests.series.test_operators; needs cleanup
1565-
@pytest.mark.parametrize("m", [1, 3, 10])
1566-
@pytest.mark.parametrize("unit", ["D", "h", "m", "s", "ms", "us", "ns"])
1567-
def test_timedelta64_conversions(self, m, unit):
1568-
startdate = Series(pd.date_range("2013-01-01", "2013-01-03"))
1569-
enddate = Series(pd.date_range("2013-03-01", "2013-03-03"))
1570-
1571-
ser = enddate - startdate
1572-
ser[2] = np.nan
1573-
1574-
# op
1575-
expected = Series([x / np.timedelta64(m, unit) for x in ser])
1576-
result = ser / np.timedelta64(m, unit)
1577-
tm.assert_series_equal(result, expected)
1578-
1579-
# reverse op
1580-
expected = Series([Timedelta(np.timedelta64(m, unit)) / x for x in ser])
1581-
result = np.timedelta64(m, unit) / ser
1582-
tm.assert_series_equal(result, expected)
1583-
15841491
# ------------------------------------------------------------------
15851492
# Multiplication
15861493
# organized with scalar others first, then array-like
@@ -1734,6 +1641,29 @@ def test_td64arr_div_tdlike_scalar(self, two_hours, box_with_array):
17341641
expected = 1 / expected
17351642
tm.assert_equal(result, expected)
17361643

1644+
@pytest.mark.parametrize("m", [1, 3, 10])
1645+
@pytest.mark.parametrize("unit", ["D", "h", "m", "s", "ms", "us", "ns"])
1646+
def test_td64arr_div_td64_scalar(self, m, unit, box_with_array):
1647+
startdate = Series(pd.date_range("2013-01-01", "2013-01-03"))
1648+
enddate = Series(pd.date_range("2013-03-01", "2013-03-03"))
1649+
1650+
ser = enddate - startdate
1651+
ser[2] = np.nan
1652+
flat = ser
1653+
ser = tm.box_expected(ser, box_with_array)
1654+
1655+
# op
1656+
expected = Series([x / np.timedelta64(m, unit) for x in flat])
1657+
expected = tm.box_expected(expected, box_with_array)
1658+
result = ser / np.timedelta64(m, unit)
1659+
tm.assert_equal(result, expected)
1660+
1661+
# reverse op
1662+
expected = Series([Timedelta(np.timedelta64(m, unit)) / x for x in flat])
1663+
expected = tm.box_expected(expected, box_with_array)
1664+
result = np.timedelta64(m, unit) / ser
1665+
tm.assert_equal(result, expected)
1666+
17371667
def test_td64arr_div_tdlike_scalar_with_nat(self, two_hours, box_with_array):
17381668
rng = TimedeltaIndex(["1 days", pd.NaT, "2 days"], name="foo")
17391669
expected = pd.Float64Index([12, np.nan, 24], name="foo")

0 commit comments

Comments
 (0)