Skip to content

Commit d64c5c2

Browse files
jbrockmendelPingviinituutti
authored andcommitted
TST: Extend timedelta64 arithmetic tests to TimedeltaArray (pandas-dev#23642)
1 parent 2898656 commit d64c5c2

File tree

5 files changed

+214
-100
lines changed

5 files changed

+214
-100
lines changed

pandas/core/arrays/timedeltas.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# -*- coding: utf-8 -*-
2+
from __future__ import division
3+
24
from datetime import timedelta
5+
import operator
36
import warnings
47

58
import numpy as np
@@ -16,9 +19,11 @@
1619
_TD_DTYPE, ensure_int64, is_datetime64_dtype, is_float_dtype,
1720
is_integer_dtype, is_list_like, is_object_dtype, is_string_dtype,
1821
is_timedelta64_dtype)
19-
from pandas.core.dtypes.generic import ABCSeries, ABCTimedeltaIndex
22+
from pandas.core.dtypes.generic import (
23+
ABCDataFrame, ABCIndexClass, ABCSeries, ABCTimedeltaIndex)
2024
from pandas.core.dtypes.missing import isna
2125

26+
from pandas.core import ops
2227
from pandas.core.algorithms import checked_add_with_arr
2328
import pandas.core.common as com
2429

@@ -101,8 +106,32 @@ def wrapper(self, other):
101106
return compat.set_function_name(wrapper, opname, cls)
102107

103108

109+
def _wrap_tdi_op(op):
110+
"""
111+
Instead of re-implementing multiplication/division etc operations
112+
in the Array class, for now we dispatch to the TimedeltaIndex
113+
implementations.
114+
"""
115+
# TODO: implement directly here and wrap in TimedeltaIndex, instead of
116+
# the other way around
117+
def method(self, other):
118+
if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)):
119+
return NotImplemented
120+
121+
from pandas import TimedeltaIndex
122+
obj = TimedeltaIndex(self)
123+
result = op(obj, other)
124+
if is_timedelta64_dtype(result):
125+
return type(self)(result)
126+
return np.array(result)
127+
128+
method.__name__ = '__{name}__'.format(name=op.__name__)
129+
return method
130+
131+
104132
class TimedeltaArrayMixin(dtl.DatetimeLikeArrayMixin):
105133
_typ = "timedeltaarray"
134+
__array_priority__ = 1000
106135

107136
@property
108137
def _box_func(self):
@@ -293,11 +322,25 @@ def _evaluate_with_timedelta_like(self, other, op):
293322

294323
return NotImplemented
295324

325+
__mul__ = _wrap_tdi_op(operator.mul)
326+
__rmul__ = __mul__
327+
__truediv__ = _wrap_tdi_op(operator.truediv)
328+
__floordiv__ = _wrap_tdi_op(operator.floordiv)
329+
__rfloordiv__ = _wrap_tdi_op(ops.rfloordiv)
330+
331+
if compat.PY2:
332+
__div__ = __truediv__
333+
334+
# Note: TimedeltaIndex overrides this in call to cls._add_numeric_methods
296335
def __neg__(self):
297336
if self.freq is not None:
298337
return type(self)(-self._data, freq=-self.freq)
299338
return type(self)(-self._data)
300339

340+
def __abs__(self):
341+
# Note: freq is not preserved
342+
return type(self)(np.abs(self._data))
343+
301344
# ----------------------------------------------------------------
302345
# Conversion Methods - Vectorized analogues of Timedelta methods
303346

pandas/core/indexes/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
ABCSeries, ABCDataFrame,
2020
ABCMultiIndex,
2121
ABCPeriodIndex, ABCTimedeltaIndex, ABCDatetimeIndex,
22-
ABCDateOffset, ABCIndexClass)
22+
ABCDateOffset, ABCIndexClass, ABCTimedeltaArray)
2323
from pandas.core.dtypes.missing import isna, array_equivalent
2424
from pandas.core.dtypes.cast import maybe_cast_to_integer_array
2525
from pandas.core.dtypes.common import (
@@ -123,7 +123,8 @@ def index_arithmetic_method(self, other):
123123
elif isinstance(other, ABCTimedeltaIndex):
124124
# Defer to subclass implementation
125125
return NotImplemented
126-
elif isinstance(other, np.ndarray) and is_timedelta64_dtype(other):
126+
elif (isinstance(other, (np.ndarray, ABCTimedeltaArray)) and
127+
is_timedelta64_dtype(other)):
127128
# GH#22390; wrap in Series for op, this will in turn wrap in
128129
# TimedeltaIndex, but will correctly raise TypeError instead of
129130
# NullFrequencyError for add/sub ops

pandas/core/indexes/timedeltas.py

+8
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,14 @@ def _format_native_types(self, na_rep=u'NaT', date_format=None, **kwargs):
227227
# -------------------------------------------------------------------
228228
# Wrapping TimedeltaArray
229229

230+
__mul__ = Index.__mul__
231+
__rmul__ = Index.__rmul__
232+
__truediv__ = Index.__truediv__
233+
__floordiv__ = Index.__floordiv__
234+
__rfloordiv__ = Index.__rfloordiv__
235+
if compat.PY2:
236+
__div__ = Index.__div__
237+
230238
days = wrap_field_accessor(TimedeltaArray.days)
231239
seconds = wrap_field_accessor(TimedeltaArray.seconds)
232240
microseconds = wrap_field_accessor(TimedeltaArray.microseconds)

0 commit comments

Comments
 (0)