Skip to content

Commit

Permalink
BUG: fix DataFrame+DataFrame op with timedelta64 dtype (#22696)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored and jreback committed Oct 2, 2018
1 parent c44bad2 commit 08ecba8
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.24.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ Timedelta
- Bug in :class:`Index` with numeric dtype when multiplying or dividing an array with dtype ``timedelta64`` (:issue:`22390`)
- Bug in :class:`TimedeltaIndex` incorrectly allowing indexing with ``Timestamp`` object (:issue:`20464`)
- Fixed bug where subtracting :class:`Timedelta` from an object-dtyped array would raise ``TypeError`` (:issue:`21980`)
-
- Fixed bug in adding a :class:`DataFrame` with all-`timedelta64[ns]` dtypes to a :class:`DataFrame` with all-integer dtypes returning incorrect results instead of raising ``TypeError`` (:issue:`22696`)
-

Timezones
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -4889,7 +4889,7 @@ def _arith_op(left, right):
left, right = ops.fill_binop(left, right, fill_value)
return func(left, right)

if this._is_mixed_type or other._is_mixed_type:
if ops.should_series_dispatch(this, other, func):
# iterate over columns
return ops.dispatch_to_series(this, other, _arith_op)
else:
Expand Down
42 changes: 40 additions & 2 deletions pandas/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,42 @@ def invalid_comparison(left, right, op):
return res_values


# -----------------------------------------------------------------------------
# Dispatch logic

def should_series_dispatch(left, right, op):
"""
Identify cases where a DataFrame operation should dispatch to its
Series counterpart.
Parameters
----------
left : DataFrame
right : DataFrame
op : binary operator
Returns
-------
override : bool
"""
if left._is_mixed_type or right._is_mixed_type:
return True

if not len(left.columns) or not len(right.columns):
# ensure obj.dtypes[0] exists for each obj
return False

ldtype = left.dtypes.iloc[0]
rdtype = right.dtypes.iloc[0]

if ((is_timedelta64_dtype(ldtype) and is_integer_dtype(rdtype)) or
(is_timedelta64_dtype(rdtype) and is_integer_dtype(ldtype))):
# numpy integer dtypes as timedelta64 dtypes in this scenario
return True

return False


# -----------------------------------------------------------------------------
# Functions that add arithmetic methods to objects, given arithmetic factory
# methods
Expand Down Expand Up @@ -1803,8 +1839,10 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):

other = _align_method_FRAME(self, other, axis)

if isinstance(other, ABCDataFrame): # Another DataFrame
return self._combine_frame(other, na_op, fill_value, level)
if isinstance(other, ABCDataFrame):
# Another DataFrame
pass_op = op if should_series_dispatch(self, other, op) else na_op
return self._combine_frame(other, pass_op, fill_value, level)
elif isinstance(other, ABCSeries):
return _combine_series_frame(self, other, na_op,
fill_value=fill_value, axis=axis,
Expand Down
15 changes: 15 additions & 0 deletions pandas/tests/frame/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,18 @@ def test_df_bool_mul_int(self):
result = 1 * df
kinds = result.dtypes.apply(lambda x: x.kind)
assert (kinds == 'i').all()

def test_td64_df_add_int_frame(self):
# GH#22696 Check that we don't dispatch to numpy implementation,
# which treats int64 as m8[ns]
tdi = pd.timedelta_range('1', periods=3)
df = tdi.to_frame()
other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df`
with pytest.raises(TypeError):
df + other
with pytest.raises(TypeError):
other + df
with pytest.raises(TypeError):
df - other
with pytest.raises(TypeError):
other - df

0 comments on commit 08ecba8

Please sign in to comment.