diff --git a/pandas/tests/arithmetic/conftest.py b/pandas/tests/arithmetic/conftest.py index 844472b8bcf0d..b800b66e8edea 100644 --- a/pandas/tests/arithmetic/conftest.py +++ b/pandas/tests/arithmetic/conftest.py @@ -28,14 +28,32 @@ def zero(request): return request.param +# ------------------------------------------------------------------ +# Vector Fixtures + @pytest.fixture(params=[pd.Float64Index(np.arange(5, dtype='float64')), pd.Int64Index(np.arange(5, dtype='int64')), - pd.UInt64Index(np.arange(5, dtype='uint64'))], + pd.UInt64Index(np.arange(5, dtype='uint64')), + pd.RangeIndex(5)], ids=lambda x: type(x).__name__) -def idx(request): +def numeric_idx(request): + """ + Several types of numeric-dtypes Index objects + """ return request.param +@pytest.fixture +def tdser(): + """ + Return a Series with dtype='timedelta64[ns]', including a NaT. + """ + return pd.Series(['59 Days', '59 Days', 'NaT'], dtype='timedelta64[ns]') + + +# ------------------------------------------------------------------ +# Scalar Fixtures + @pytest.fixture(params=[pd.Timedelta('5m4s').to_pytimedelta(), pd.Timedelta('5m4s'), pd.Timedelta('5m4s').to_timedelta64()], @@ -47,6 +65,72 @@ def scalar_td(request): return request.param +@pytest.fixture(params=[pd.offsets.Day(3), + pd.offsets.Hour(72), + pd.Timedelta(days=3).to_pytimedelta(), + pd.Timedelta('72:00:00'), + np.timedelta64(3, 'D'), + np.timedelta64(72, 'h')]) +def three_days(request): + """ + Several timedelta-like and DateOffset objects that each represent + a 3-day timedelta + """ + return request.param + + +@pytest.fixture(params=[pd.offsets.Hour(2), + pd.offsets.Minute(120), + pd.Timedelta(hours=2).to_pytimedelta(), + pd.Timedelta(seconds=2 * 3600), + np.timedelta64(2, 'h'), + np.timedelta64(120, 'm')]) +def two_hours(request): + """ + Several timedelta-like and DateOffset objects that each represent + a 2-hour timedelta + """ + return request.param + + +_common_mismatch = [pd.offsets.YearBegin(2), + pd.offsets.MonthBegin(1), + pd.offsets.Minute()] + + +@pytest.fixture(params=[pd.Timedelta(minutes=30).to_pytimedelta(), + np.timedelta64(30, 's'), + pd.Timedelta(seconds=30)] + _common_mismatch) +def not_hourly(request): + """ + Several timedelta-like and DateOffset instances that are _not_ + compatible with Hourly frequencies. + """ + return request.param + + +@pytest.fixture(params=[np.timedelta64(4, 'h'), + pd.Timedelta(hours=23).to_pytimedelta(), + pd.Timedelta('23:00:00')] + _common_mismatch) +def not_daily(request): + """ + Several timedelta-like and DateOffset instances that are _not_ + compatible with Daily frequencies. + """ + return request.param + + +@pytest.fixture(params=[np.timedelta64(365, 'D'), + pd.Timedelta(days=365).to_pytimedelta(), + pd.Timedelta(days=365)] + _common_mismatch) +def mismatched_freq(request): + """ + Several timedelta-like and DateOffset instances that are _not_ + compatible with Monthly or Annual frequencies. + """ + return request.param + + # ------------------------------------------------------------------ @pytest.fixture(params=[pd.Index, pd.Series, pd.DataFrame], @@ -59,6 +143,18 @@ def box(request): 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, diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index d597ea834f097..a3fa4e6b88256 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -27,29 +27,6 @@ DatetimeIndex, TimedeltaIndex) -# ------------------------------------------------------------------ -# Fixtures - -@pytest.fixture(params=[pd.offsets.Hour(2), timedelta(hours=2), - np.timedelta64(2, 'h'), Timedelta(hours=2)], - ids=str) -def delta(request): - # Several ways of representing two hours - return request.param - - -@pytest.fixture( - params=[ - datetime(2011, 1, 1), - DatetimeIndex(['2011-01-01', '2011-01-02']), - DatetimeIndex(['2011-01-01', '2011-01-02']).tz_localize('US/Eastern'), - np.datetime64('2011-01-01'), - Timestamp('2011-01-01')], - ids=lambda x: type(x).__name__) -def addend(request): - return request.param - - # ------------------------------------------------------------------ # Comparisons @@ -697,23 +674,20 @@ def test_dt64ser_sub_datetime_dtype(self): # TODO: This next block of tests came from tests.series.test_operators, # needs to be de-duplicated and parametrized over `box` classes - @pytest.mark.parametrize( - 'box, assert_func', - [(Series, tm.assert_series_equal), - (pd.Index, tm.assert_index_equal)]) - def test_sub_datetime64_not_ns(self, box, assert_func): + @pytest.mark.parametrize('klass', [Series, pd.Index]) + def test_sub_datetime64_not_ns(self, klass): # GH#7996 dt64 = np.datetime64('2013-01-01') assert dt64.dtype == 'datetime64[D]' - obj = box(date_range('20130101', periods=3)) + obj = klass(date_range('20130101', periods=3)) res = obj - dt64 - expected = box([Timedelta(days=0), Timedelta(days=1), - Timedelta(days=2)]) - assert_func(res, expected) + expected = klass([Timedelta(days=0), Timedelta(days=1), + Timedelta(days=2)]) + tm.assert_equal(res, expected) res = dt64 - obj - assert_func(res, -expected) + tm.assert_equal(res, -expected) def test_sub_single_tz(self): # GH12290 @@ -1113,40 +1087,40 @@ def test_dti_add_intarray_no_freq(self, box): # ------------------------------------------------------------- # Binary operations DatetimeIndex and timedelta-like - def test_dti_add_timedeltalike(self, tz_naive_fixture, delta, box): + def test_dti_add_timedeltalike(self, tz_naive_fixture, two_hours, box): # GH#22005, GH#22163 check DataFrame doesn't raise TypeError tz = tz_naive_fixture rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz) rng = tm.box_expected(rng, box) - result = rng + delta + result = rng + two_hours expected = pd.date_range('2000-01-01 02:00', '2000-02-01 02:00', tz=tz) expected = tm.box_expected(expected, box) tm.assert_equal(result, expected) - def test_dti_iadd_timedeltalike(self, tz_naive_fixture, delta): + def test_dti_iadd_timedeltalike(self, tz_naive_fixture, two_hours): tz = tz_naive_fixture rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz) expected = pd.date_range('2000-01-01 02:00', '2000-02-01 02:00', tz=tz) - rng += delta + rng += two_hours tm.assert_index_equal(rng, expected) - def test_dti_sub_timedeltalike(self, tz_naive_fixture, delta): + def test_dti_sub_timedeltalike(self, tz_naive_fixture, two_hours): tz = tz_naive_fixture rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz) expected = pd.date_range('1999-12-31 22:00', '2000-01-31 22:00', tz=tz) - result = rng - delta + result = rng - two_hours tm.assert_index_equal(result, expected) - def test_dti_isub_timedeltalike(self, tz_naive_fixture, delta): + def test_dti_isub_timedeltalike(self, tz_naive_fixture, two_hours): tz = tz_naive_fixture rng = pd.date_range('2000-01-01', '2000-02-01', tz=tz) expected = pd.date_range('1999-12-31 22:00', '2000-01-31 22:00', tz=tz) - rng -= delta + rng -= two_hours tm.assert_index_equal(rng, expected) # ------------------------------------------------------------- @@ -1252,27 +1226,23 @@ def test_dti_isub_tdi(self, tz_naive_fixture): # TODO: A couple other tests belong in this section. Move them in # A PR where there isn't already a giant diff. - def test_add_datetimelike_and_dti(self, addend): + @pytest.mark.parametrize('addend', [ + datetime(2011, 1, 1), + DatetimeIndex(['2011-01-01', '2011-01-02']), + DatetimeIndex(['2011-01-01', '2011-01-02']).tz_localize('US/Eastern'), + np.datetime64('2011-01-01'), + Timestamp('2011-01-01') + ], ids=lambda x: type(x).__name__) + @pytest.mark.parametrize('tz', [None, 'US/Eastern']) + def test_add_datetimelike_and_dti(self, addend, tz): # GH#9631 - dti = DatetimeIndex(['2011-01-01', '2011-01-02']) - msg = 'cannot add DatetimeIndex and {0}'.format( - type(addend).__name__) + dti = DatetimeIndex(['2011-01-01', '2011-01-02']).tz_localize(tz) + msg = 'cannot add DatetimeIndex and {0}'.format(type(addend).__name__) with tm.assert_raises_regex(TypeError, msg): dti + addend with tm.assert_raises_regex(TypeError, msg): addend + dti - def test_add_datetimelike_and_dti_tz(self, addend): - # GH#9631 - dti_tz = DatetimeIndex(['2011-01-01', - '2011-01-02']).tz_localize('US/Eastern') - msg = 'cannot add DatetimeIndex and {0}'.format( - type(addend).__name__) - with tm.assert_raises_regex(TypeError, msg): - dti_tz + addend - with tm.assert_raises_regex(TypeError, msg): - addend + dti_tz - # ------------------------------------------------------------- # __add__/__sub__ with ndarray[datetime64] and ndarray[timedelta64] @@ -1391,21 +1361,14 @@ def test_sub_period(self, freq, box): with pytest.raises(TypeError): p - idx - @pytest.mark.parametrize('box', [ - 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__) @pytest.mark.parametrize('op', [operator.add, ops.radd, 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): + def test_dti_sub_pi(self, dti_freq, pi_freq, op, box_df_broadcast_failure): # 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) @@ -1748,31 +1711,30 @@ def test_dti_add_offset_tzaware(self, tz_aware_fixture, box): tm.assert_equal(offset, expected) -@pytest.mark.parametrize('klass,assert_func', [ - (Series, tm.assert_series_equal), - (DatetimeIndex, tm.assert_index_equal)]) -def test_dt64_with_offset_array(klass, assert_func): +@pytest.mark.parametrize('klass', [Series, DatetimeIndex]) +def test_dt64_with_offset_array(klass): # GH#10699 # array of offsets box = Series if klass is Series else pd.Index + dti = DatetimeIndex([Timestamp('2000-1-1'), Timestamp('2000-2-1')]) + + s = klass(dti) + with tm.assert_produces_warning(PerformanceWarning): - s = klass([Timestamp('2000-1-1'), Timestamp('2000-2-1')]) result = s + box([pd.offsets.DateOffset(years=1), pd.offsets.MonthEnd()]) exp = klass([Timestamp('2001-1-1'), Timestamp('2000-2-29')]) - assert_func(result, exp) + tm.assert_equal(result, exp) # same offset result = s + box([pd.offsets.DateOffset(years=1), pd.offsets.DateOffset(years=1)]) exp = klass([Timestamp('2001-1-1'), Timestamp('2001-2-1')]) - assert_func(result, exp) + tm.assert_equal(result, exp) -@pytest.mark.parametrize('klass,assert_func', [ - (Series, tm.assert_series_equal), - (DatetimeIndex, tm.assert_index_equal)]) -def test_dt64_with_DateOffsets_relativedelta(klass, assert_func): +@pytest.mark.parametrize('klass', [Series, DatetimeIndex]) +def test_dt64_with_DateOffsets_relativedelta(klass): # GH#10699 vec = klass([Timestamp('2000-01-05 00:15:00'), Timestamp('2000-01-31 00:23:00'), @@ -1789,11 +1751,11 @@ def test_dt64_with_DateOffsets_relativedelta(klass, assert_func): ('microseconds', 5)] for i, kwd in enumerate(relative_kwargs): op = pd.DateOffset(**dict([kwd])) - assert_func(klass([x + op for x in vec]), vec + op) - assert_func(klass([x - op for x in vec]), vec - op) + tm.assert_equal(klass([x + op for x in vec]), vec + op) + tm.assert_equal(klass([x - op for x in vec]), vec - op) op = pd.DateOffset(**dict(relative_kwargs[:i + 1])) - assert_func(klass([x + op for x in vec]), vec + op) - assert_func(klass([x - op for x in vec]), vec - op) + tm.assert_equal(klass([x + op for x in vec]), vec + op) + tm.assert_equal(klass([x - op for x in vec]), vec - op) @pytest.mark.parametrize('cls_and_kwargs', [ @@ -1816,10 +1778,8 @@ def test_dt64_with_DateOffsets_relativedelta(klass, assert_func): 'Easter', ('DateOffset', {'day': 4}), ('DateOffset', {'month': 5})]) @pytest.mark.parametrize('normalize', [True, False]) -@pytest.mark.parametrize('klass,assert_func', [ - (Series, tm.assert_series_equal), - (DatetimeIndex, tm.assert_index_equal)]) -def test_dt64_with_DateOffsets(klass, assert_func, normalize, cls_and_kwargs): +@pytest.mark.parametrize('klass', [Series, DatetimeIndex]) +def test_dt64_with_DateOffsets(klass, normalize, cls_and_kwargs): # GH#10699 # assert these are equal on a piecewise basis vec = klass([Timestamp('2000-01-05 00:15:00'), @@ -1849,26 +1809,24 @@ def test_dt64_with_DateOffsets(klass, assert_func, normalize, cls_and_kwargs): continue offset = offset_cls(n, normalize=normalize, **kwargs) - assert_func(klass([x + offset for x in vec]), vec + offset) - assert_func(klass([x - offset for x in vec]), vec - offset) - assert_func(klass([offset + x for x in vec]), offset + vec) + tm.assert_equal(klass([x + offset for x in vec]), vec + offset) + tm.assert_equal(klass([x - offset for x in vec]), vec - offset) + tm.assert_equal(klass([offset + x for x in vec]), offset + vec) -@pytest.mark.parametrize('klass,assert_func', zip([Series, DatetimeIndex], - [tm.assert_series_equal, - tm.assert_index_equal])) -def test_datetime64_with_DateOffset(klass, assert_func): +@pytest.mark.parametrize('klass', [Series, DatetimeIndex]) +def test_datetime64_with_DateOffset(klass): # GH#10699 s = klass(date_range('2000-01-01', '2000-01-31'), name='a') result = s + pd.DateOffset(years=1) result2 = pd.DateOffset(years=1) + s exp = klass(date_range('2001-01-01', '2001-01-31'), name='a') - assert_func(result, exp) - assert_func(result2, exp) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) result = s - pd.DateOffset(years=1) exp = klass(date_range('1999-01-01', '1999-01-31'), name='a') - assert_func(result, exp) + tm.assert_equal(result, exp) s = klass([Timestamp('2000-01-15 00:15:00', tz='US/Central'), pd.Timestamp('2000-02-15', tz='US/Central')], name='a') @@ -1876,8 +1834,8 @@ def test_datetime64_with_DateOffset(klass, assert_func): result2 = pd.offsets.Day() + s exp = klass([Timestamp('2000-01-16 00:15:00', tz='US/Central'), Timestamp('2000-02-16', tz='US/Central')], name='a') - assert_func(result, exp) - assert_func(result2, exp) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) s = klass([Timestamp('2000-01-15 00:15:00', tz='US/Central'), pd.Timestamp('2000-02-15', tz='US/Central')], name='a') @@ -1885,8 +1843,8 @@ def test_datetime64_with_DateOffset(klass, assert_func): result2 = pd.offsets.MonthEnd() + s exp = klass([Timestamp('2000-01-31 00:15:00', tz='US/Central'), Timestamp('2000-02-29', tz='US/Central')], name='a') - assert_func(result, exp) - assert_func(result2, exp) + tm.assert_equal(result, exp) + tm.assert_equal(result2, exp) @pytest.mark.parametrize('years', [-1, 0, 1]) diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index d3957330f11e4..fcfc3994a88c8 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -17,15 +17,6 @@ from pandas import Timedelta, Series, Index, TimedeltaIndex -@pytest.fixture(params=[pd.Float64Index(np.arange(5, dtype='float64')), - pd.UInt64Index(np.arange(5, dtype='uint64')), - pd.Int64Index(np.arange(5, dtype='int64')), - pd.RangeIndex(5)], - ids=lambda x: type(x).__name__) -def idx(request): - return request.param - - # ------------------------------------------------------------------ # Comparisons @@ -135,20 +126,18 @@ def test_ops_series(self): tm.assert_series_equal(expected, td * other) tm.assert_series_equal(expected, other * td) - @pytest.mark.parametrize('index', [ - pd.Int64Index(range(1, 11)), - pd.UInt64Index(range(1, 11)), - pd.Float64Index(range(1, 11)), - pd.RangeIndex(1, 11)], - ids=lambda x: type(x).__name__) + # TODO: also test non-nanosecond timedelta64 and Tick objects; + # see test_numeric_arr_rdiv_tdscalar for note on these failing @pytest.mark.parametrize('scalar_td', [ Timedelta(days=1), Timedelta(days=1).to_timedelta64(), Timedelta(days=1).to_pytimedelta()], ids=lambda x: type(x).__name__) - def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): + def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box): # GH#19333 - expected = pd.timedelta_range('1 days', '10 days') + index = numeric_idx + + expected = pd.timedelta_range('0 days', '4 days') index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) @@ -159,28 +148,27 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): commute = scalar_td * index tm.assert_equal(commute, expected) - @pytest.mark.parametrize('index', [ - pd.Int64Index(range(1, 3)), - pd.UInt64Index(range(1, 3)), - pd.Float64Index(range(1, 3)), - pd.RangeIndex(1, 3)], - ids=lambda x: type(x).__name__) - @pytest.mark.parametrize('scalar_td', [ - Timedelta(days=1), - Timedelta(days=1).to_timedelta64(), - Timedelta(days=1).to_pytimedelta()], - ids=lambda x: type(x).__name__) - def test_numeric_arr_rdiv_tdscalar(self, scalar_td, index, box): - expected = TimedeltaIndex(['1 Day', '12 Hours']) + 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 imlpemented") + + expected = TimedeltaIndex(['3 Days', '36 Hours']) index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) - result = scalar_td / index + result = three_days / index tm.assert_equal(result, expected) with pytest.raises(TypeError): - index / scalar_td + index / three_days # ------------------------------------------------------------------ @@ -188,7 +176,9 @@ def test_numeric_arr_rdiv_tdscalar(self, scalar_td, index, box): class TestDivisionByZero(object): - def test_div_zero(self, zero, idx): + def test_div_zero(self, zero, numeric_idx): + idx = numeric_idx + expected = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64) result = idx / zero @@ -196,7 +186,9 @@ def test_div_zero(self, zero, idx): ser_compat = Series(idx).astype('i8') / np.array(zero).astype('i8') tm.assert_series_equal(ser_compat, Series(result)) - def test_floordiv_zero(self, zero, idx): + def test_floordiv_zero(self, zero, numeric_idx): + idx = numeric_idx + expected = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64) @@ -205,7 +197,9 @@ def test_floordiv_zero(self, zero, idx): ser_compat = Series(idx).astype('i8') // np.array(zero).astype('i8') tm.assert_series_equal(ser_compat, Series(result)) - def test_mod_zero(self, zero, idx): + def test_mod_zero(self, zero, numeric_idx): + idx = numeric_idx + expected = pd.Index([np.nan, np.nan, np.nan, np.nan, np.nan], dtype=np.float64) result = idx % zero @@ -213,7 +207,8 @@ def test_mod_zero(self, zero, idx): ser_compat = Series(idx).astype('i8') % np.array(zero).astype('i8') tm.assert_series_equal(ser_compat, Series(result)) - def test_divmod_zero(self, zero, idx): + def test_divmod_zero(self, zero, numeric_idx): + idx = numeric_idx exleft = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64) @@ -430,8 +425,9 @@ def test_div_equiv_binop(self): result = second / first tm.assert_series_equal(result, expected) - def test_div_int(self, idx): + def test_div_int(self, numeric_idx): # truediv under PY3 + idx = numeric_idx result = idx / 1 expected = idx if PY3: @@ -445,13 +441,15 @@ def test_div_int(self, idx): tm.assert_index_equal(result, expected) @pytest.mark.parametrize('op', [operator.mul, ops.rmul, operator.floordiv]) - def test_mul_int_identity(self, op, idx, box): + def test_mul_int_identity(self, op, numeric_idx, box): + idx = numeric_idx idx = tm.box_expected(idx, box) result = op(idx, 1) tm.assert_equal(result, idx) - def test_mul_int_array(self, idx): + def test_mul_int_array(self, numeric_idx): + idx = numeric_idx didx = idx * idx result = idx * np.array(5, dtype='int64') @@ -461,39 +459,45 @@ def test_mul_int_array(self, idx): result = idx * np.arange(5, dtype=arr_dtype) tm.assert_index_equal(result, didx) - def test_mul_int_series(self, idx): + def test_mul_int_series(self, numeric_idx): + idx = numeric_idx didx = idx * idx arr_dtype = 'uint64' if isinstance(idx, pd.UInt64Index) else 'int64' result = idx * Series(np.arange(5, dtype=arr_dtype)) tm.assert_series_equal(result, Series(didx)) - def test_mul_float_series(self, idx): + def test_mul_float_series(self, numeric_idx): + idx = numeric_idx rng5 = np.arange(5, dtype='float64') result = idx * Series(rng5 + 0.1) expected = Series(rng5 * (rng5 + 0.1)) tm.assert_series_equal(result, expected) - def test_mul_index(self, idx): + def test_mul_index(self, numeric_idx): # in general not true for RangeIndex + idx = numeric_idx if not isinstance(idx, pd.RangeIndex): result = idx * idx tm.assert_index_equal(result, idx ** 2) - def test_mul_datelike_raises(self, idx): + def test_mul_datelike_raises(self, numeric_idx): + idx = numeric_idx with pytest.raises(TypeError): idx * pd.date_range('20130101', periods=5) - def test_mul_size_mismatch_raises(self, idx): + def test_mul_size_mismatch_raises(self, numeric_idx): + idx = numeric_idx with pytest.raises(ValueError): idx * idx[0:3] with pytest.raises(ValueError): idx * np.array([1, 2]) @pytest.mark.parametrize('op', [operator.pow, ops.rpow]) - def test_pow_float(self, op, idx, box): + def test_pow_float(self, op, numeric_idx, box): # test power calculations both ways, GH#14973 + idx = numeric_idx expected = pd.Float64Index(op(idx.values, 2.0)) idx = tm.box_expected(idx, box) @@ -502,8 +506,9 @@ def test_pow_float(self, op, idx, box): result = op(idx, 2.0) tm.assert_equal(result, expected) - def test_modulo(self, idx, box): + def test_modulo(self, numeric_idx, box): # GH#9244 + idx = numeric_idx expected = Index(idx.values % 2) idx = tm.box_expected(idx, box) @@ -512,7 +517,8 @@ def test_modulo(self, idx, box): result = idx % 2 tm.assert_equal(result, expected) - def test_divmod(self, idx): + def test_divmod(self, numeric_idx): + idx = numeric_idx result = divmod(idx, 2) with np.errstate(all='ignore'): div, mod = divmod(idx.values, 2) @@ -530,7 +536,8 @@ def test_divmod(self, idx): @pytest.mark.xfail(reason='GH#19252 Series has no __rdivmod__', strict=True) - def test_divmod_series(self, idx): + def test_divmod_series(self, numeric_idx): + idx = numeric_idx other = np.ones(idx.values.shape, dtype=idx.values.dtype) * 2 result = divmod(idx, Series(other)) with np.errstate(all='ignore'): diff --git a/pandas/tests/arithmetic/test_period.py b/pandas/tests/arithmetic/test_period.py index 92123bf48bb47..3210290b9c5c8 100644 --- a/pandas/tests/arithmetic/test_period.py +++ b/pandas/tests/arithmetic/test_period.py @@ -3,7 +3,6 @@ # behave identically. # Specifically for Period dtype import operator -from datetime import timedelta import numpy as np import pytest @@ -17,80 +16,10 @@ import pandas.core.indexes.period as period from pandas.core import ops from pandas import ( - Period, PeriodIndex, period_range, Timedelta, Series, + Period, PeriodIndex, period_range, Series, _np_version_under1p10) -# ------------------------------------------------------------------ -# Fixtures - -_common_mismatch = [pd.offsets.YearBegin(2), - pd.offsets.MonthBegin(1), - pd.offsets.Minute()] - - -@pytest.fixture(params=[timedelta(minutes=30), - np.timedelta64(30, 's'), - Timedelta(seconds=30)] + _common_mismatch) -def not_hourly(request): - """ - Several timedelta-like and DateOffset instances that are _not_ - compatible with Hourly frequencies. - """ - return request.param - - -@pytest.fixture(params=[np.timedelta64(4, 'h'), - timedelta(hours=23), - Timedelta('23:00:00')] + _common_mismatch) -def not_daily(request): - """ - Several timedelta-like and DateOffset instances that are _not_ - compatible with Daily frequencies. - """ - return request.param - - -@pytest.fixture(params=[np.timedelta64(365, 'D'), - timedelta(365), - Timedelta(days=365)] + _common_mismatch) -def mismatched(request): - """ - Several timedelta-like and DateOffset instances that are _not_ - compatible with Monthly or Annual frequencies. - """ - return request.param - - -@pytest.fixture(params=[pd.offsets.Day(3), - timedelta(days=3), - np.timedelta64(3, 'D'), - pd.offsets.Hour(72), - timedelta(minutes=60 * 24 * 3), - np.timedelta64(72, 'h'), - Timedelta('72:00:00')]) -def three_days(request): - """ - Several timedelta-like and DateOffset objects that each represent - a 3-day timedelta - """ - return request.param - - -@pytest.fixture(params=[pd.offsets.Hour(2), - timedelta(hours=2), - np.timedelta64(2, 'h'), - pd.offsets.Minute(120), - timedelta(minutes=120), - np.timedelta64(120, 'm')]) -def two_hours(request): - """ - Several timedelta-like and DateOffset objects that each represent - a 2-hour timedelta - """ - return request.param - - # ------------------------------------------------------------------ # Comparisons @@ -752,8 +681,9 @@ def test_add_iadd_timedeltalike_annual(self): rng += pd.offsets.YearEnd(5) tm.assert_index_equal(rng, expected) - def test_pi_add_iadd_timedeltalike_freq_mismatch_annual(self, mismatched): - other = mismatched + def test_pi_add_iadd_timedeltalike_freq_mismatch_annual(self, + mismatched_freq): + other = mismatched_freq rng = pd.period_range('2014', '2024', freq='A') msg = ('Input has different freq(=.+)? ' 'from PeriodIndex\\(freq=A-DEC\\)') @@ -762,8 +692,9 @@ def test_pi_add_iadd_timedeltalike_freq_mismatch_annual(self, mismatched): with tm.assert_raises_regex(period.IncompatibleFrequency, msg): rng += other - def test_pi_sub_isub_timedeltalike_freq_mismatch_annual(self, mismatched): - other = mismatched + def test_pi_sub_isub_timedeltalike_freq_mismatch_annual(self, + mismatched_freq): + other = mismatched_freq rng = pd.period_range('2014', '2024', freq='A') msg = ('Input has different freq(=.+)? ' 'from PeriodIndex\\(freq=A-DEC\\)') @@ -782,8 +713,9 @@ def test_pi_add_iadd_timedeltalike_M(self): rng += pd.offsets.MonthEnd(5) tm.assert_index_equal(rng, expected) - def test_pi_add_iadd_timedeltalike_freq_mismatch_monthly(self, mismatched): - other = mismatched + def test_pi_add_iadd_timedeltalike_freq_mismatch_monthly(self, + mismatched_freq): + other = mismatched_freq rng = pd.period_range('2014-01', '2016-12', freq='M') msg = 'Input has different freq(=.+)? from PeriodIndex\\(freq=M\\)' with tm.assert_raises_regex(period.IncompatibleFrequency, msg): @@ -791,8 +723,9 @@ def test_pi_add_iadd_timedeltalike_freq_mismatch_monthly(self, mismatched): with tm.assert_raises_regex(period.IncompatibleFrequency, msg): rng += other - def test_pi_sub_isub_timedeltalike_freq_mismatch_monthly(self, mismatched): - other = mismatched + def test_pi_sub_isub_timedeltalike_freq_mismatch_monthly(self, + mismatched_freq): + other = mismatched_freq rng = pd.period_range('2014-01', '2016-12', freq='M') msg = 'Input has different freq(=.+)? from PeriodIndex\\(freq=M\\)' with tm.assert_raises_regex(period.IncompatibleFrequency, msg): diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index def7a8be95fc8..5050922173564 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -18,60 +18,6 @@ DataFrame) -# ------------------------------------------------------------------ -# Fixtures - -@pytest.fixture -def tdser(): - """ - Return a Series with dtype='timedelta64[ns]', including a NaT. - """ - return Series(['59 Days', '59 Days', 'NaT'], dtype='timedelta64[ns]') - - -@pytest.fixture(params=[pd.offsets.Hour(2), timedelta(hours=2), - np.timedelta64(2, 'h'), Timedelta(hours=2)], - ids=lambda x: type(x).__name__) -def delta(request): - """ - Several ways of representing two hours - """ - return request.param - - -@pytest.fixture(params=[timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()], - ids=lambda x: type(x).__name__) -def scalar_td(request): - """ - Several variants of Timedelta scalars representing 5 minutes and 4 seconds - """ - return request.param - - -@pytest.fixture(params=[pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) -def box(request): - """ - Several array-like containers that should have effectively identical - behavior with respect to arithmetic operations. - """ - return request.param - - -@pytest.fixture(params=[pd.Index, - 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 - - # ------------------------------------------------------------------ # Timedelta64[ns] dtype Comparisons @@ -522,8 +468,8 @@ def test_td64arr_add_sub_timestamp(self, box): with pytest.raises(TypeError): tdser - ts - def test_tdi_sub_dt64_array(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + def test_tdi_sub_dt64_array(self, box_df_broadcast_failure): + box = box_df_broadcast_failure dti = pd.date_range('2016-01-01', periods=3) tdi = dti - dti.shift(1) @@ -540,8 +486,8 @@ def test_tdi_sub_dt64_array(self, box_df_fail): result = dtarr - tdi tm.assert_equal(result, expected) - def test_tdi_add_dt64_array(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + def test_tdi_add_dt64_array(self, box_df_broadcast_failure): + box = box_df_broadcast_failure dti = pd.date_range('2016-01-01', periods=3) tdi = dti - dti.shift(1) @@ -559,43 +505,33 @@ def test_tdi_add_dt64_array(self, box_df_fail): # ------------------------------------------------------------------ # Operations with int-like others - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="Attempts to broadcast " - "incorrectly", - strict=True, raises=ValueError)) - ], ids=lambda x: x.__name__) - def test_td64arr_add_int_series_invalid(self, box, tdser): + def test_td64arr_add_int_series_invalid(self, box_df_broadcast_failure, + tdser): + box = box_df_broadcast_failure tdser = tm.box_expected(tdser, box) err = TypeError if box is not pd.Index else NullFrequencyError with pytest.raises(err): tdser + Series([2, 3, 4]) - def test_td64arr_radd_int_series_invalid(self, box_df_fail, tdser): - box = box_df_fail # Tries to broadcast incorrectly + def test_td64arr_radd_int_series_invalid(self, box_df_broadcast_failure, + tdser): + box = box_df_broadcast_failure tdser = tm.box_expected(tdser, box) err = TypeError if box is not pd.Index else NullFrequencyError with pytest.raises(err): Series([2, 3, 4]) + tdser - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="Attempts to broadcast " - "incorrectly", - strict=True, raises=ValueError)) - ], ids=lambda x: x.__name__) - def test_td64arr_sub_int_series_invalid(self, box, tdser): + def test_td64arr_sub_int_series_invalid(self, box_df_broadcast_failure, + tdser): + box = box_df_broadcast_failure tdser = tm.box_expected(tdser, box) err = TypeError if box is not pd.Index else NullFrequencyError with pytest.raises(err): tdser - Series([2, 3, 4]) - def test_td64arr_rsub_int_series_invalid(self, box_df_fail, tdser): - box = box_df_fail # Tries to broadcast incorrectly + def test_td64arr_rsub_int_series_invalid(self, box_df_broadcast_failure, + tdser): + box = box_df_broadcast_failure tdser = tm.box_expected(tdser, box) err = TypeError if box is not pd.Index else NullFrequencyError with pytest.raises(err): @@ -669,9 +605,9 @@ def test_td64arr_add_sub_numeric_scalar_invalid(self, box, scalar, tdser): Series([1, 2, 3]) # TODO: Add DataFrame in here? ], ids=lambda x: type(x).__name__) - def test_td64arr_add_sub_numeric_arr_invalid(self, box_df_fail, vec, - dtype, tdser): - box = box_df_fail # tries to broadcast incorrectly + def test_td64arr_add_sub_numeric_arr_invalid( + self, box_df_broadcast_failure, vec, dtype, tdser): + box = box_df_broadcast_failure tdser = tm.box_expected(tdser, box) err = TypeError if box is pd.Index and not dtype.startswith('float'): @@ -744,8 +680,8 @@ def test_timedelta64_operations_with_timedeltas(self): # roundtrip tm.assert_series_equal(result + td2, td1) - def test_td64arr_add_td64_array(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + def test_td64arr_add_td64_array(self, box_df_broadcast_failure): + box = box_df_broadcast_failure dti = pd.date_range('2016-01-01', periods=3) tdi = dti - dti.shift(1) @@ -760,8 +696,8 @@ def test_td64arr_add_td64_array(self, box_df_fail): result = tdarr + tdi tm.assert_equal(result, expected) - def test_td64arr_sub_td64_array(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + def test_td64arr_sub_td64_array(self, box_df_broadcast_failure): + box = box_df_broadcast_failure dti = pd.date_range('2016-01-01', periods=3) tdi = dti - dti.shift(1) @@ -843,7 +779,7 @@ def test_td64arr_sub_NaT(self, box): res = ser - pd.NaT tm.assert_equal(res, expected) - def test_td64arr_add_timedeltalike(self, delta, box): + def test_td64arr_add_timedeltalike(self, two_hours, box): # only test adding/sub offsets as + is now numeric rng = timedelta_range('1 days', '10 days') expected = timedelta_range('1 days 02:00:00', '10 days 02:00:00', @@ -851,10 +787,10 @@ def test_td64arr_add_timedeltalike(self, delta, box): rng = tm.box_expected(rng, box) expected = tm.box_expected(expected, box) - result = rng + delta + result = rng + two_hours tm.assert_equal(result, expected) - def test_td64arr_sub_timedeltalike(self, delta, box): + def test_td64arr_sub_timedeltalike(self, two_hours, box): # only test adding/sub offsets as - is now numeric rng = timedelta_range('1 days', '10 days') expected = timedelta_range('0 days 22:00:00', '9 days 22:00:00') @@ -862,7 +798,7 @@ def test_td64arr_sub_timedeltalike(self, delta, box): rng = tm.box_expected(rng, box) expected = tm.box_expected(expected, box) - result = rng - delta + result = rng - two_hours tm.assert_equal(result, expected) # ------------------------------------------------------------------ @@ -934,9 +870,9 @@ def test_td64arr_add_offset_index(self, names, box): # TODO: combine with test_td64arr_add_offset_index by parametrizing # over second box? - def test_td64arr_add_offset_array(self, box_df_fail): + def test_td64arr_add_offset_array(self, box_df_broadcast_failure): # GH#18849 - box = box_df_fail # tries to broadcast incorrectly + box = box_df_broadcast_failure tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) other = np.array([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)]) @@ -957,9 +893,9 @@ def test_td64arr_add_offset_array(self, box_df_fail): @pytest.mark.parametrize('names', [(None, None, None), ('foo', 'bar', None), ('foo', 'foo', 'foo')]) - def test_td64arr_sub_offset_index(self, names, box_df_fail): + def test_td64arr_sub_offset_index(self, names, box_df_broadcast_failure): # GH#18824, GH#19744 - box = box_df_fail # tries to broadcast incorrectly + box = box_df_broadcast_failure tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'], name=names[0]) other = pd.Index([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)], @@ -975,9 +911,9 @@ def test_td64arr_sub_offset_index(self, names, box_df_fail): res = tdi - other tm.assert_equal(res, expected) - def test_td64arr_sub_offset_array(self, box_df_fail): + def test_td64arr_sub_offset_array(self, box_df_broadcast_failure): # GH#18824 - box = box_df_fail # tries to broadcast incorrectly + box = box_df_broadcast_failure tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) other = np.array([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)]) @@ -994,9 +930,9 @@ def test_td64arr_sub_offset_array(self, box_df_fail): @pytest.mark.parametrize('names', [(None, None, None), ('foo', 'bar', None), ('foo', 'foo', 'foo')]) - def test_td64arr_with_offset_series(self, names, box_df_fail): + def test_td64arr_with_offset_series(self, names, box_df_broadcast_failure): # GH#18849 - box = box_df_fail # tries to broadcast incorrectly + box = box_df_broadcast_failure box2 = Series if box is pd.Index else box tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'], @@ -1027,9 +963,10 @@ def test_td64arr_with_offset_series(self, names, box_df_fail): tm.assert_equal(res3, expected_sub) @pytest.mark.parametrize('obox', [np.array, pd.Index, pd.Series]) - def test_td64arr_addsub_anchored_offset_arraylike(self, obox, box_df_fail): + def test_td64arr_addsub_anchored_offset_arraylike( + self, obox, box_df_broadcast_failure): # GH#18824 - box = box_df_fail # DataFrame tries to broadcast incorrectly + box = box_df_broadcast_failure tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) tdi = tm.box_expected(tdi, box) @@ -1090,11 +1027,11 @@ def test_td64arr_mul_int(self, box): result = 1 * idx tm.assert_equal(result, idx) - def test_td64arr_mul_tdlike_scalar_raises(self, delta, box): + def test_td64arr_mul_tdlike_scalar_raises(self, two_hours, box): rng = timedelta_range('1 days', '10 days', name='foo') rng = tm.box_expected(rng, box) with pytest.raises(TypeError): - rng * delta + rng * two_hours def test_tdi_mul_int_array_zerodim(self, box): rng5 = np.arange(5, dtype='int64') @@ -1107,8 +1044,8 @@ def test_tdi_mul_int_array_zerodim(self, box): result = idx * np.array(5, dtype='int64') tm.assert_equal(result, expected) - def test_tdi_mul_int_array(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + def test_tdi_mul_int_array(self, box_df_broadcast_failure): + box = box_df_broadcast_failure rng5 = np.arange(5, dtype='int64') idx = TimedeltaIndex(rng5) expected = TimedeltaIndex(rng5 ** 2) @@ -1120,7 +1057,7 @@ def test_tdi_mul_int_array(self, box_df_fail): tm.assert_equal(result, expected) def test_tdi_mul_int_series(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + box = box_df_fail idx = TimedeltaIndex(np.arange(5, dtype='int64')) expected = TimedeltaIndex(np.arange(5, dtype='int64') ** 2) @@ -1133,7 +1070,7 @@ def test_tdi_mul_int_series(self, box_df_fail): tm.assert_equal(result, expected) def test_tdi_mul_float_series(self, box_df_fail): - box = box_df_fail # DataFrame tries to broadcast incorrectly + box = box_df_fail idx = TimedeltaIndex(np.arange(5, dtype='int64')) idx = tm.box_expected(idx, box) @@ -1186,7 +1123,7 @@ def test_td64arr_div_int(self, box): result = idx / 1 tm.assert_equal(result, idx) - def test_tdi_div_tdlike_scalar(self, delta, box): + def test_tdi_div_tdlike_scalar(self, two_hours, box): # GH#20088, GH#22163 ensure DataFrame returns correct dtype rng = timedelta_range('1 days', '10 days', name='foo') expected = pd.Float64Index((np.arange(10) + 1) * 12, name='foo') @@ -1194,17 +1131,17 @@ def test_tdi_div_tdlike_scalar(self, delta, box): rng = tm.box_expected(rng, box) expected = tm.box_expected(expected, box) - result = rng / delta + result = rng / two_hours tm.assert_equal(result, expected) - def test_tdi_div_tdlike_scalar_with_nat(self, delta, box): + def test_tdi_div_tdlike_scalar_with_nat(self, two_hours, box): rng = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') expected = pd.Float64Index([12, np.nan, 24], name='foo') rng = tm.box_expected(rng, box) expected = tm.box_expected(expected, box) - result = rng / delta + result = rng / two_hours tm.assert_equal(result, expected) # ------------------------------------------------------------------ @@ -1260,14 +1197,14 @@ def test_td64arr_floordiv_int(self, box): result = idx // 1 tm.assert_equal(result, idx) - def test_td64arr_floordiv_tdlike_scalar(self, delta, box): + def test_td64arr_floordiv_tdlike_scalar(self, two_hours, box): tdi = timedelta_range('1 days', '10 days', name='foo') expected = pd.Int64Index((np.arange(10) + 1) * 12, name='foo') tdi = tm.box_expected(tdi, box) expected = tm.box_expected(expected, box) - result = tdi // delta + result = tdi // two_hours tm.assert_equal(result, expected) # TODO: Is this redundant with test_td64arr_floordiv_tdlike_scalar? @@ -1364,14 +1301,6 @@ def test_td64arr_div_numeric_scalar(self, box, two, tdser): result = tdser / two tm.assert_equal(result, expected) - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="broadcasts along " - "wrong axis", - strict=True)) - ], ids=lambda x: x.__name__) @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16', 'uint64', 'uint32', 'uint16', 'uint8', 'float64', 'float32', 'float16']) @@ -1380,9 +1309,11 @@ def test_td64arr_div_numeric_scalar(self, box, two, tdser): Series([20, 30, 40])], ids=lambda x: type(x).__name__) @pytest.mark.parametrize('op', [operator.mul, ops.rmul]) - def test_td64arr_rmul_numeric_array(self, op, box, vector, dtype, tdser): + def test_td64arr_rmul_numeric_array(self, op, box_df_fail, + vector, dtype, tdser): # GH#4521 # divide/multiply by integers + box = box_df_fail # broadcasts incorrectly but doesn't raise vector = vector.astype(dtype) expected = Series(['1180 Days', '1770 Days', 'NaT'], @@ -1428,22 +1359,15 @@ def test_td64arr_div_numeric_array(self, box, vector, dtype, tdser): with pytest.raises(TypeError): vector / tdser - # TODO: Should we be parametrizing over types for `ser` too? - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="broadcasts along " - "wrong axis", - strict=True)) - ], ids=lambda x: x.__name__) @pytest.mark.parametrize('names', [(None, None, None), ('Egon', 'Venkman', None), ('NCC1701D', 'NCC1701D', 'NCC1701D')]) - def test_td64arr_mul_int_series(self, box, names): + def test_td64arr_mul_int_series(self, box_df_fail, names): # GH#19042 test for correct name attachment + box = box_df_fail # broadcasts along wrong axis, but doesn't raise tdi = TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'], name=names[0]) + # TODO: Should we be parametrizing over types for `ser` too? ser = Series([0, 1, 2, 3, 4], dtype=np.int64, name=names[1]) expected = Series(['0days', '1day', '4days', '9days', '16days'], @@ -1491,10 +1415,6 @@ def test_float_series_rdiv_td64arr(self, box, names): class TestTimedeltaArraylikeInvalidArithmeticOps(object): - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()]) def test_td64arr_pow_invalid(self, scalar_td, box): td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan