Skip to content

TST: fix _most_ remaining xfails in tests/arithmetic #23308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
2 changes: 1 addition & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -4978,7 +4978,7 @@ def _combine_match_columns(self, other, func, level=None):
assert left.columns.equals(right.index)
return ops.dispatch_to_series(left, right, func, axis="columns")

def _combine_const(self, other, func, errors='raise'):
def _combine_const(self, other, func):
assert lib.is_scalar(other) or np.ndim(other) == 0
return ops.dispatch_to_series(self, other, func)

Expand Down
8 changes: 6 additions & 2 deletions pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from pandas.core.dtypes.common import (
is_int64_dtype, is_integer, is_scalar, is_timedelta64_dtype
)
from pandas.core.dtypes.generic import ABCSeries, ABCTimedeltaIndex
from pandas.core.dtypes.generic import (
ABCSeries, ABCTimedeltaIndex, ABCDataFrame)
from pandas.core.indexes.base import Index, _index_shared_docs
from pandas.core.indexes.numeric import Int64Index
from pandas.util._decorators import Appender, cache_readonly
Expand Down Expand Up @@ -557,6 +558,9 @@ def __getitem__(self, key):
return super_getitem(key)

def __floordiv__(self, other):
if isinstance(other, (ABCSeries, ABCDataFrame)):
return NotImplemented

if is_integer(other) and other != 0:
if (len(self) == 0 or
self._start % other == 0 and
Expand Down Expand Up @@ -588,7 +592,7 @@ def _make_evaluate_binop(op, step=False):
"""

def _evaluate_numeric_binop(self, other):
if isinstance(other, ABCSeries):
if isinstance(other, (ABCSeries, ABCDataFrame)):
return NotImplemented
elif isinstance(other, ABCTimedeltaIndex):
# Defer to TimedeltaIndex implementation
Expand Down
12 changes: 9 additions & 3 deletions pandas/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
ABCIndex, ABCIndexClass,
ABCSparseSeries, ABCSparseArray)

from pandas.tseries.offsets import Tick


# -----------------------------------------------------------------------------
# Ops Wrapping Utilities
Expand Down Expand Up @@ -125,11 +127,16 @@ def maybe_upcast_for_op(obj):
Be careful to call this *after* determining the `name` attribute to be
attached to the result of the arithmetic operation.
"""
if type(obj) is datetime.timedelta:
if type(obj) is datetime.timedelta or isinstance(obj, Tick):
# GH#22390 cast up to Timedelta to rely on Timedelta
# implementation; otherwise operation against numeric-dtype
# raises TypeError
return pd.Timedelta(obj)
elif isinstance(obj, np.timedelta64):
# In particular non-nanosecond timedelta64 needs to be cast to
# nanoseconds, or else we get undesired behavior like
# np.timedelta64(3, 'D') / 2 == np.timedelta64(1, 'D')
return pd.Timedelta(obj)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FIXME: this will screw up on np.timedelta64(“nat”)

elif isinstance(obj, np.ndarray) and is_timedelta64_dtype(obj):
# GH#22390 Unfortunately we need to special-case right-hand
# timedelta64 dtypes because numpy casts integer dtypes to
Expand Down Expand Up @@ -1940,8 +1947,7 @@ def f(self, other):

# straight boolean comparisons we want to allow all columns
# (regardless of dtype to pass thru) See #4537 for discussion.
res = self._combine_const(other, func,
errors='ignore')
res = self._combine_const(other, func)
return res.fillna(True).astype(bool)

f.__name__ = op_name
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/sparse/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ def _combine_match_columns(self, other, func, level=None):
new_data, index=self.index, columns=union,
default_fill_value=self.default_fill_value).__finalize__(self)

def _combine_const(self, other, func, errors='raise'):
def _combine_const(self, other, func):
return self._apply_columns(lambda x: func(x, other))

def _reindex_index(self, index, method, copy, level, fill_value=np.nan,
Expand Down
31 changes: 2 additions & 29 deletions pandas/tests/arithmetic/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ def three_days(request):
pd.Timedelta(hours=2).to_pytimedelta(),
pd.Timedelta(seconds=2 * 3600),
np.timedelta64(2, 'h'),
np.timedelta64(120, 'm')])
np.timedelta64(120, 'm')],
ids=lambda x: str(x))
def two_hours(request):
"""
Several timedelta-like and DateOffset objects that each represent
Expand Down Expand Up @@ -141,31 +142,3 @@ def box(request):
behavior with respect to arithmetic operations.
"""
return request.param


@pytest.fixture(params=[pd.Index,
pd.Series,
pytest.param(pd.DataFrame,
marks=pytest.mark.xfail(strict=True))],
ids=lambda x: x.__name__)
def box_df_fail(request):
"""
Fixture equivalent to `box` fixture but xfailing the DataFrame case.
"""
return request.param


@pytest.fixture(params=[
pd.Index,
pd.Series,
pytest.param(pd.DataFrame,
marks=pytest.mark.xfail(reason="Tries to broadcast "
"incorrectly",
strict=True, raises=ValueError))
], ids=lambda x: x.__name__)
def box_df_broadcast_failure(request):
"""
Fixture equivalent to `box` but with the common failing case where
the DataFrame operation tries to broadcast incorrectly.
"""
return request.param
6 changes: 2 additions & 4 deletions pandas/tests/arithmetic/test_datetime64.py
Original file line number Diff line number Diff line change
Expand Up @@ -1366,14 +1366,12 @@ def test_sub_period(self, freq, box):
operator.sub, ops.rsub])
@pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H'])
@pytest.mark.parametrize('dti_freq', [None, 'D'])
def test_dti_sub_pi(self, dti_freq, pi_freq, op, box_df_broadcast_failure):
def test_dti_sub_pi(self, dti_freq, pi_freq, op, box):
# GH#20049 subtracting PeriodIndex should raise TypeError
box = box_df_broadcast_failure

dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq)
pi = dti.to_period(pi_freq)

dti = tm.box_expected(dti, box)
dti = tm.box_expected(dti, box, transpose=True)
# TODO: Also box pi?
with pytest.raises(TypeError):
op(dti, pi)
Expand Down
8 changes: 0 additions & 8 deletions pandas/tests/arithmetic/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,6 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box):
def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box):
index = numeric_idx[1:3]

broken = (isinstance(three_days, np.timedelta64) and
three_days.dtype != 'm8[ns]')
broken = broken or isinstance(three_days, pd.offsets.Tick)
if box is not pd.Index and broken:
# np.timedelta64(3, 'D') / 2 == np.timedelta64(1, 'D')
raise pytest.xfail("timedelta64 not converted to nanos; "
"Tick division not implemented")

expected = TimedeltaIndex(['3 Days', '36 Hours'])

index = tm.box_expected(index, box)
Expand Down
12 changes: 4 additions & 8 deletions pandas/tests/arithmetic/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,12 @@ class TestPeriodIndexArithmetic(object):
# PeriodIndex - other is defined for integers, timedelta-like others,
# and PeriodIndex (with matching freq)

def test_parr_add_iadd_parr_raises(self, box_df_broadcast_failure):
box = box_df_broadcast_failure

def test_parr_add_iadd_parr_raises(self, box):
rng = pd.period_range('1/1/2000', freq='D', periods=5)
other = pd.period_range('1/6/2000', freq='D', periods=5)
# TODO: parametrize over boxes for other?

rng = tm.box_expected(rng, box)
rng = tm.box_expected(rng, box, transpose=True)
# An earlier implementation of PeriodIndex addition performed
# a set operation (union). This has since been changed to
# raise a TypeError. See GH#14164 and GH#13077 for historical
Expand Down Expand Up @@ -345,14 +343,12 @@ def test_pi_sub_pi_with_nat(self):
expected = pd.Index([pd.NaT, 0 * off, 0 * off, 0 * off, 0 * off])
tm.assert_index_equal(result, expected)

def test_parr_sub_pi_mismatched_freq(self, box_df_broadcast_failure):
box = box_df_broadcast_failure

def test_parr_sub_pi_mismatched_freq(self, box):
rng = pd.period_range('1/1/2000', freq='D', periods=5)
other = pd.period_range('1/6/2000', freq='H', periods=5)
# TODO: parametrize over boxes for other?

rng = tm.box_expected(rng, box)
rng = tm.box_expected(rng, box, transpose=True)
with pytest.raises(period.IncompatibleFrequency):
rng - other

Expand Down
Loading