25
25
get_upcast_box ,
26
26
)
27
27
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
+
28
41
# ------------------------------------------------------------------
29
42
# Timedelta64[ns] dtype Comparisons
30
43
@@ -522,19 +535,35 @@ def test_tda_add_sub_index(self):
522
535
# -------------------------------------------------------------
523
536
# Binary operations TimedeltaIndex and timedelta-like
524
537
525
- def test_tdi_iadd_timedeltalike (self , two_hours ):
538
+ def test_tdi_iadd_timedeltalike (self , two_hours , box_with_array ):
526
539
# only test adding/sub offsets as + is now numeric
527
540
rng = timedelta_range ("1 days" , "10 days" )
528
541
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
529
547
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 )
531
552
532
- def test_tdi_isub_timedeltalike (self , two_hours ):
553
+ def test_tdi_isub_timedeltalike (self , two_hours , box_with_array ):
533
554
# only test adding/sub offsets as - is now numeric
534
555
rng = timedelta_range ("1 days" , "10 days" )
535
556
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
536
562
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 )
538
567
539
568
# -------------------------------------------------------------
540
569
@@ -1013,15 +1042,6 @@ def test_td64arr_add_datetime64_nat(self, box_with_array):
1013
1042
# ------------------------------------------------------------------
1014
1043
# Invalid __add__/__sub__ operations
1015
1044
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
-
1025
1045
@pytest .mark .parametrize ("pi_freq" , ["D" , "W" , "Q" , "H" ])
1026
1046
@pytest .mark .parametrize ("tdi_freq" , [None , "H" ])
1027
1047
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):
1100
1120
1101
1121
def test_td64arr_add_sub_integer_array (self , box_with_array ):
1102
1122
# 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
+
1103
1126
rng = timedelta_range ("1 days 09:00:00" , freq = "H" , periods = 3 )
1104
1127
tdarr = tm .box_expected (rng , box_with_array )
1105
1128
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):
1119
1142
# ------------------------------------------------------------------
1120
1143
# Operations with timedelta-like others
1121
1144
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
-
1176
1145
def test_td64arr_add_td64_array (self , box_with_array ):
1177
1146
box = box_with_array
1178
1147
dti = pd .date_range ("2016-01-01" , periods = 3 )
@@ -1203,7 +1172,6 @@ def test_td64arr_sub_td64_array(self, box_with_array):
1203
1172
result = tdarr - tdi
1204
1173
tm .assert_equal (result , expected )
1205
1174
1206
- # TODO: parametrize over [add, sub, radd, rsub]?
1207
1175
@pytest .mark .parametrize (
1208
1176
"names" ,
1209
1177
[
@@ -1232,17 +1200,11 @@ def test_td64arr_add_sub_tdi(self, box, names):
1232
1200
1233
1201
result = tdi + ser
1234
1202
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]" )
1239
1204
1240
1205
result = ser + tdi
1241
1206
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]" )
1246
1208
1247
1209
expected = Series (
1248
1210
[Timedelta (hours = - 3 ), Timedelta (days = 1 , hours = - 4 )], name = names [2 ]
@@ -1251,17 +1213,11 @@ def test_td64arr_add_sub_tdi(self, box, names):
1251
1213
1252
1214
result = tdi - ser
1253
1215
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]" )
1258
1217
1259
1218
result = ser - tdi
1260
1219
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]" )
1265
1221
1266
1222
def test_td64arr_add_sub_td64_nat (self , box_with_array ):
1267
1223
# GH#23320 special handling for timedelta64("NaT")
@@ -1296,6 +1252,7 @@ def test_td64arr_sub_NaT(self, box_with_array):
1296
1252
1297
1253
def test_td64arr_add_timedeltalike (self , two_hours , box_with_array ):
1298
1254
# only test adding/sub offsets as + is now numeric
1255
+ # GH#10699 for Tick cases
1299
1256
box = box_with_array
1300
1257
rng = timedelta_range ("1 days" , "10 days" )
1301
1258
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):
1305
1262
result = rng + two_hours
1306
1263
tm .assert_equal (result , expected )
1307
1264
1265
+ result = two_hours + rng
1266
+ tm .assert_equal (result , expected )
1267
+
1308
1268
def test_td64arr_sub_timedeltalike (self , two_hours , box_with_array ):
1309
1269
# only test adding/sub offsets as - is now numeric
1270
+ # GH#10699 for Tick cases
1310
1271
box = box_with_array
1311
1272
rng = timedelta_range ("1 days" , "10 days" )
1312
1273
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):
1317
1278
result = rng - two_hours
1318
1279
tm .assert_equal (result , expected )
1319
1280
1281
+ result = two_hours - rng
1282
+ tm .assert_equal (result , - expected )
1283
+
1320
1284
# ------------------------------------------------------------------
1321
1285
# __add__/__sub__ with DateOffsets and arrays of DateOffsets
1322
1286
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
-
1360
1287
@pytest .mark .parametrize (
1361
1288
"names" , [(None , None , None ), ("foo" , "bar" , None ), ("foo" , "foo" , "foo" )]
1362
1289
)
@@ -1561,26 +1488,6 @@ class TestTimedeltaArraylikeMulDivOps:
1561
1488
# Tests for timedelta64[ns]
1562
1489
# __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__
1563
1490
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
-
1584
1491
# ------------------------------------------------------------------
1585
1492
# Multiplication
1586
1493
# organized with scalar others first, then array-like
@@ -1734,6 +1641,29 @@ def test_td64arr_div_tdlike_scalar(self, two_hours, box_with_array):
1734
1641
expected = 1 / expected
1735
1642
tm .assert_equal (result , expected )
1736
1643
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
+
1737
1667
def test_td64arr_div_tdlike_scalar_with_nat (self , two_hours , box_with_array ):
1738
1668
rng = TimedeltaIndex (["1 days" , pd .NaT , "2 days" ], name = "foo" )
1739
1669
expected = pd .Float64Index ([12 , np .nan , 24 ], name = "foo" )
0 commit comments