From fed3f741e6707e3096292fa4da3bc6592343f311 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 19:43:14 -0700 Subject: [PATCH 01/10] implement box fixture, move a couple tests from timedelta.test_arithmetic, parametrize more --- .../indexes/timedeltas/test_arithmetic.py | 12 --- pandas/tests/test_arithmetic.py | 78 +++++++------------ 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index a5e75de2a267e..ee0b6075f59d9 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -163,18 +163,6 @@ def test_tdi_mul_int_array(self): result = idx * rng5 tm.assert_index_equal(result, didx) - def test_tdi_mul_dti_raises(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - with pytest.raises(TypeError): - idx * idx - - def test_tdi_mul_too_short_raises(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - with pytest.raises(TypeError): - idx * TimedeltaIndex(np.arange(3)) - with pytest.raises(ValueError): - idx * np.array([1, 2]) - def test_tdi_mul_int_series(self): idx = TimedeltaIndex(np.arange(5, dtype='int64')) didx = TimedeltaIndex(np.arange(5, dtype='int64') ** 2) diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 8ee0bf9ec874a..78d7412b924fa 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -28,6 +28,16 @@ def tdser(): return Series(['59 Days', '59 Days', 'NaT'], dtype='timedelta64[ns]') +@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 + + # ------------------------------------------------------------------ # Numeric dtypes Arithmetic with Timedelta Scalar @@ -69,7 +79,6 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): commute = scalar_td * index tm.assert_equal(commute, expected) - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame]) @pytest.mark.parametrize('index', [ pd.Int64Index(range(1, 3)), pd.UInt64Index(range(1, 3)), @@ -109,8 +118,6 @@ class TestTimedeltaArraylikeAddSubOps(object): # ------------------------------------------------------------- # Invalid Operations - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) def test_td64arr_add_str_invalid(self, box): # GH#13624 tdi = TimedeltaIndex(['1 day', '2 days']) @@ -121,8 +128,6 @@ def test_td64arr_add_str_invalid(self, box): with pytest.raises(TypeError): 'a' + tdi - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) @pytest.mark.parametrize('other', [3.14, np.array([2.0, 3.0])]) @pytest.mark.parametrize('op', [operator.add, ops.radd, operator.sub, ops.rsub], @@ -186,8 +191,6 @@ def test_td64arr_sub_pi(self, box, tdi_freq, pi_freq): # ------------------------------------------------------------- # Binary operations td64 arraylike and datetime-like - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) def test_td64arr_sub_timestamp_raises(self, box): idx = TimedeltaIndex(['1 day', '2 day']) idx = tm.box_expected(idx, box) @@ -280,8 +283,6 @@ def test_td64arr_sub_int_series_invalid(self, box, tdser): with pytest.raises(err): tdser - Series([2, 3, 4]) - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) @pytest.mark.xfail(reason='GH#19123 integer interpreted as nanoseconds', strict=True) def test_td64arr_rsub_int_series_invalid(self, box, tdser): @@ -326,8 +327,6 @@ def test_td64arr_add_intlike(self, box): with pytest.raises(err): ser - pd.Index(other) - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) @pytest.mark.parametrize('scalar', [1, 1.5, np.array(2)]) def test_td64arr_add_sub_numeric_scalar_invalid(self, box, scalar, tdser): @@ -579,7 +578,7 @@ def test_td64arr_rfloordiv_tdscalar_explicit(self, box, scalar_td): tm.assert_equal(result, expected) # ------------------------------------------------------------------ - # Operations with timedelta-like others + # Operations with invalid others @pytest.mark.parametrize('box', [ pd.Index, @@ -609,6 +608,20 @@ def test_td64arr_mul_tdscalar_invalid(self, box, scalar_td): with tm.assert_raises_regex(TypeError, pattern): scalar_td * td1 + def test_td64arr_mul_too_short_raises(self, box): + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + with pytest.raises(TypeError): + idx * idx[:3] + with pytest.raises(ValueError): + idx * np.array([1, 2]) + + def test_td64arr_mul_td64arr_raises(self, box): + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + with pytest.raises(TypeError): + idx * idx + # ------------------------------------------------------------------ # Operations with numeric others @@ -662,36 +675,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']) - @pytest.mark.parametrize('vector', [np.array([20, 30, 40]), - pd.Index([20, 30, 40]), - Series([20, 30, 40])]) - def test_td64arr_mul_numeric_array(self, box, vector, dtype, tdser): - # GH#4521 - # divide/multiply by integers - vector = vector.astype(dtype) - - expected = Series(['1180 Days', '1770 Days', 'NaT'], - dtype='timedelta64[ns]') - - tdser = tm.box_expected(tdser, box) - # TODO: Make this up-casting more systematic? - box = Series if (box is pd.Index and type(vector) is Series) else box - expected = tm.box_expected(expected, box) - - result = tdser * vector - tm.assert_equal(result, expected) - @pytest.mark.parametrize('box', [ pd.Index, Series, @@ -707,7 +690,8 @@ def test_td64arr_mul_numeric_array(self, box, vector, dtype, tdser): pd.Index([20, 30, 40]), Series([20, 30, 40])], ids=lambda x: type(x).__name__) - def test_td64arr_rmul_numeric_array(self, box, vector, dtype, tdser): + @pytest.mark.parametrize('op', [operator.mul, ops.rmul]) + def test_td64arr_rmul_numeric_array(self, op, box, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) @@ -716,10 +700,11 @@ def test_td64arr_rmul_numeric_array(self, box, vector, dtype, tdser): dtype='timedelta64[ns]') tdser = tm.box_expected(tdser, box) + # TODO: Make this up-casting more systematic? box = Series if (box is pd.Index and type(vector) is Series) else box expected = tm.box_expected(expected, box) - result = vector * tdser + result = op(vector, tdser) tm.assert_equal(result, expected) @pytest.mark.parametrize('box', [ @@ -787,11 +772,6 @@ def test_td64arr_mul_int_series(self, box, names): tm.assert_equal(result, expected) # TODO: Should we be parametrizing over types for `ser` too? - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pd.DataFrame - ], ids=lambda x: x.__name__) @pytest.mark.parametrize('names', [(None, None, None), ('Egon', 'Venkman', None), ('NCC1701D', 'NCC1701D', 'NCC1701D')]) From 85982fc41ceb1b74bf2321be07cef2c2d9878847 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 19:49:14 -0700 Subject: [PATCH 02/10] port floordiv tests --- .../indexes/timedeltas/test_arithmetic.py | 12 ------- pandas/tests/test_arithmetic.py | 35 +++++++++++++++++++ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index ee0b6075f59d9..4f5e4c720859a 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -223,18 +223,6 @@ def test_tdi_div_nat_raises(self): # ------------------------------------------------------------- # TimedeltaIndex.__floordiv__ - def test_tdi_floordiv_int(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - result = idx // 1 - tm.assert_index_equal(result, idx) - - def test_tdi_floordiv_tdlike_scalar(self, delta): - tdi = timedelta_range('1 days', '10 days', name='foo') - expected = Int64Index((np.arange(10) + 1) * 12, name='foo') - - result = tdi // delta - tm.assert_index_equal(result, expected, exact=False) - @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=10, seconds=7), Timedelta('10m7s'), diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 78d7412b924fa..f4596efbebf94 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -28,6 +28,16 @@ def tdser(): 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=str) +def delta(request): + """ + Several ways of representing two hours + """ + return request.param + + @pytest.fixture(params=[pd.Index, Series, pd.DataFrame], ids=lambda x: x.__name__) def box(request): @@ -37,6 +47,13 @@ def box(request): """ return request.param +@pytest.fixture(params=[ + pd.Index, + Series, + pytest.param(pd.DataFrame, marks=pytest.mark.xfail(strict=True))]) +def box_df_fail(request): + return request.param + # ------------------------------------------------------------------ # Numeric dtypes Arithmetic with Timedelta Scalar @@ -577,6 +594,24 @@ def test_td64arr_rfloordiv_tdscalar_explicit(self, box, scalar_td): result = td1.__rfloordiv__(scalar_td) tm.assert_equal(result, expected) + def test_td64arr_floordiv_int(self, box_df_fail): + box = box_df_fail # DataFrame returns object dtype + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + result = idx // 1 + tm.assert_equal(result, idx) + + def test_td64arr_floordiv_tdlike_scalar(self, delta, box_df_fail): + box = box_df_fail # DataFrame returns m8[ns] instead of int64 dtype + tdi = pd.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 + tm.assert_equal(result, expected) + # ------------------------------------------------------------------ # Operations with invalid others From 9ee6d0f21062b636cf34cd49236672a36974682e Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 19:53:20 -0700 Subject: [PATCH 03/10] port test_td64arr_rfloordiv_tdlike_scalar --- .../indexes/timedeltas/test_arithmetic.py | 20 --------------- pandas/tests/test_arithmetic.py | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 4f5e4c720859a..72a90a845e2ea 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -220,26 +220,6 @@ def test_tdi_div_nat_raises(self): with pytest.raises(TypeError): rng / pd.NaT - # ------------------------------------------------------------- - # TimedeltaIndex.__floordiv__ - - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=10, seconds=7), - Timedelta('10m7s'), - Timedelta('10m7s').to_timedelta64()]) - def test_tdi_floordiv_timedelta_scalar(self, scalar_td): - # GH#19125 - tdi = TimedeltaIndex(['00:05:03', '00:05:03', pd.NaT], freq=None) - expected = pd.Index([2.0, 2.0, np.nan]) - - res = tdi.__rfloordiv__(scalar_td) - tm.assert_index_equal(res, expected) - - expected = pd.Index([0.0, 0.0, np.nan]) - - res = tdi // (scalar_td) - tm.assert_index_equal(res, expected) - class TestTimedeltaIndexArithmetic(object): # Addition and Subtraction Operations diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index f4596efbebf94..7a06a0dc2c4b5 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -47,6 +47,7 @@ def box(request): """ return request.param + @pytest.fixture(params=[ pd.Index, Series, @@ -612,6 +613,30 @@ def test_td64arr_floordiv_tdlike_scalar(self, delta, box_df_fail): result = tdi // delta tm.assert_equal(result, expected) + # TODO: Is this redundant with test_td64arr_floordiv_tdlike_scalar? + @pytest.mark.parametrize('scalar_td', [ + timedelta(minutes=10, seconds=7), + Timedelta('10m7s'), + Timedelta('10m7s').to_timedelta64() + ], ids=lambda x: type(x).__name__) + def test_td64arr_rfloordiv_tdlike_scalar(self, scalar_td, box_df_fail): + # GH#19125 + box = box_df_fail # DataFrame op returns m8[ns] instead of f8 dtype + tdi = TimedeltaIndex(['00:05:03', '00:05:03', pd.NaT], freq=None) + expected = pd.Index([2.0, 2.0, np.nan]) + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + res = tdi.__rfloordiv__(scalar_td) + tm.assert_equal(res, expected) + + expected = pd.Index([0.0, 0.0, np.nan]) + expected = tm.box_expected(expected, box) + + res = tdi // (scalar_td) + tm.assert_equal(res, expected) + # ------------------------------------------------------------------ # Operations with invalid others From 733022a4246c75e8b8d75ee6178a20cc5f429067 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 20:25:38 -0700 Subject: [PATCH 04/10] make fixtures, port last of TimedeltaIndex div/mul tests --- .../indexes/timedeltas/test_arithmetic.py | 97 ---------- pandas/tests/test_arithmetic.py | 179 +++++++++++++++--- 2 files changed, 156 insertions(+), 120 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 72a90a845e2ea..916cb2190d684 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -124,103 +124,6 @@ def test_comparisons_nat(self): tm.assert_numpy_array_equal(result, expected) -class TestTimedeltaIndexMultiplicationDivision(object): - # __mul__, __rmul__, - # __div__, __rdiv__, __floordiv__, __rfloordiv__, - # __mod__, __rmod__, __divmod__, __rdivmod__ - - # ------------------------------------------------------------- - # Multiplication - # organized with scalar others first, then array-like - - def test_tdi_mul_int(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - result = idx * 1 - tm.assert_index_equal(result, idx) - - def test_tdi_rmul_int(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - result = 1 * idx - tm.assert_index_equal(result, idx) - - def test_tdi_mul_tdlike_scalar_raises(self, delta): - rng = timedelta_range('1 days', '10 days', name='foo') - with pytest.raises(TypeError): - rng * delta - - def test_tdi_mul_int_array_zerodim(self): - rng5 = np.arange(5, dtype='int64') - idx = TimedeltaIndex(rng5) - expected = TimedeltaIndex(rng5 * 5) - result = idx * np.array(5, dtype='int64') - tm.assert_index_equal(result, expected) - - def test_tdi_mul_int_array(self): - rng5 = np.arange(5, dtype='int64') - idx = TimedeltaIndex(rng5) - didx = TimedeltaIndex(rng5 ** 2) - - result = idx * rng5 - tm.assert_index_equal(result, didx) - - def test_tdi_mul_int_series(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - didx = TimedeltaIndex(np.arange(5, dtype='int64') ** 2) - - result = idx * Series(np.arange(5, dtype='int64')) - - tm.assert_series_equal(result, Series(didx)) - - def test_tdi_mul_float_series(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - - rng5f = np.arange(5, dtype='float64') - result = idx * Series(rng5f + 0.1) - expected = Series(TimedeltaIndex(rng5f * (rng5f + 0.1))) - tm.assert_series_equal(result, expected) - - @pytest.mark.parametrize('other', [np.arange(1, 11), - pd.Int64Index(range(1, 11)), - pd.UInt64Index(range(1, 11)), - pd.Float64Index(range(1, 11)), - pd.RangeIndex(1, 11)]) - def test_tdi_rmul_arraylike(self, other): - tdi = TimedeltaIndex(['1 Day'] * 10) - expected = timedelta_range('1 days', '10 days') - - result = other * tdi - tm.assert_index_equal(result, expected) - commute = tdi * other - tm.assert_index_equal(commute, expected) - - # ------------------------------------------------------------- - # TimedeltaIndex.__div__ - - def test_tdi_div_int(self): - idx = TimedeltaIndex(np.arange(5, dtype='int64')) - result = idx / 1 - tm.assert_index_equal(result, idx) - - def test_tdi_div_tdlike_scalar(self, delta): - rng = timedelta_range('1 days', '10 days', name='foo') - expected = Int64Index((np.arange(10) + 1) * 12, name='foo') - - result = rng / delta - tm.assert_index_equal(result, expected, exact=False) - - def test_tdi_div_tdlike_scalar_with_nat(self, delta): - rng = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') - expected = Float64Index([12, np.nan, 24], name='foo') - result = rng / delta - tm.assert_index_equal(result, expected) - - def test_tdi_div_nat_raises(self): - # don't allow division by NaT (make could in the future) - rng = timedelta_range('1 days', '10 days', name='foo') - with pytest.raises(TypeError): - rng / pd.NaT - - class TestTimedeltaIndexArithmetic(object): # Addition and Subtraction Operations diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 7a06a0dc2c4b5..883553181f2f6 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -38,6 +38,17 @@ def delta(request): 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): @@ -51,8 +62,13 @@ def box(request): @pytest.fixture(params=[ pd.Index, Series, - pytest.param(pd.DataFrame, marks=pytest.mark.xfail(strict=True))]) + 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 @@ -498,8 +514,6 @@ def test_td64arr_add_sub_tdi(self, box, names): else: assert result.dtypes[0] == 'timedelta64[ns]' - @pytest.mark.parametrize('box', [pd.Index, Series, pd.DataFrame], - ids=lambda x: x.__name__) def test_td64arr_sub_NaT(self, box): # GH#18808 ser = Series([NaT, Timedelta('1s')]) @@ -516,6 +530,145 @@ class TestTimedeltaArraylikeMulDivOps(object): # Tests for timedelta64[ns] # __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__ + # ------------------------------------------------------------------ + # Multiplication + # organized with scalar others first, then array-like + + def test_td64arr_mul_int(self, box_df_fail): + box = box_df_fail # DataFrame op returns object instead of m8[ns] + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + + result = idx * 1 + tm.assert_equal(result, idx) + + result = 1 * idx + tm.assert_equal(result, idx) + + def test_td64arr_mul_tdlike_scalar_raises(self, delta, box): + if box is pd.DataFrame and not isinstance(delta, pd.DateOffset): + pytest.xfail(reason="returns m8[ns] instead of raising") + + rng = pd.timedelta_range('1 days', '10 days', name='foo') + rng = tm.box_expected(rng, box) + with pytest.raises(TypeError): + rng * delta + + def test_tdi_mul_int_array_zerodim(self, box_df_fail): + box = box_df_fail # DataFrame op returns object dtype + rng5 = np.arange(5, dtype='int64') + idx = TimedeltaIndex(rng5) + expected = TimedeltaIndex(rng5 * 5) + + idx = tm.box_expected(idx, box) + expected = tm.box_expected(expected, 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 + rng5 = np.arange(5, dtype='int64') + idx = TimedeltaIndex(rng5) + expected = TimedeltaIndex(rng5 ** 2) + + idx = tm.box_expected(idx, box) + expected = tm.box_expected(expected, box) + + result = idx * rng5 + tm.assert_equal(result, expected) + + def test_tdi_mul_int_series(self, box_df_fail): + box = box_df_fail # DataFrame tries to broadcast incorrectly + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + expected = TimedeltaIndex(np.arange(5, dtype='int64') ** 2) + + idx = tm.box_expected(idx, box) + + box2 = pd.Series if box is pd.Index else box + expected = tm.box_expected(expected, box2) + + result = idx * pd.Series(np.arange(5, dtype='int64')) + tm.assert_equal(result, expected) + + def test_tdi_mul_float_series(self, box_df_fail): + box = box_df_fail # DataFrame tries to broadcast incorrectly + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + + rng5f = np.arange(5, dtype='float64') + expected = TimedeltaIndex(rng5f * (rng5f + 0.1)) + box2 = pd.Series if box is pd.Index else box + expected = tm.box_expected(expected, box2) + + result = idx * Series(rng5f + 0.1) + tm.assert_equal(result, expected) + + # TODO: Put Series/DataFrame in others? + @pytest.mark.parametrize('other', [ + np.arange(1, 11), + 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__) + def test_tdi_rmul_arraylike(self, other, box_df_fail): + # RangeIndex fails to return NotImplemented, for others + # DataFrame tries to broadcast incorrectly + box = box_df_fail + + tdi = TimedeltaIndex(['1 Day'] * 10) + expected = pd.timedelta_range('1 days', '10 days') + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + result = other * tdi + tm.assert_equal(result, expected) + commute = tdi * other + tm.assert_equal(commute, expected) + + # ------------------------------------------------------------------ + # __div__ + + def test_td64arr_div_nat_invalid(self, box_df_fail): + # don't allow division by NaT (maybe could in the future) + box = box_df_fail # DataFrame returns all-NaT instead of raising + rng = pd.timedelta_range('1 days', '10 days', name='foo') + rng = tm.box_expected(rng, box) + with pytest.raises(TypeError): + rng / pd.NaT + + def test_td64arr_div_int(self, box_df_fail): + box = box_df_fail # DataFrame returns object dtype instead of m8[ns] + idx = TimedeltaIndex(np.arange(5, dtype='int64')) + idx = tm.box_expected(idx, box) + + result = idx / 1 + tm.assert_equal(result, idx) + + def test_tdi_div_tdlike_scalar(self, delta, box_df_fail): + box = box_df_fail # DataFrame op returns m8[ns] instead of float64 + rng = pd.timedelta_range('1 days', '10 days', name='foo') + expected = pd.Float64Index((np.arange(10) + 1) * 12, name='foo') + + rng = tm.box_expected(rng, box) + expected = tm.box_expected(expected, box) + + result = rng / delta + tm.assert_equal(result, expected) + + def test_tdi_div_tdlike_scalar_with_nat(self, delta, box_df_fail): + box = box_df_fail # DataFrame op returns m8[ns] instead of float64 + 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 + tm.assert_equal(result, expected) + # ------------------------------------------------------------------ # __floordiv__, __rfloordiv__ @@ -527,10 +680,6 @@ class TestTimedeltaArraylikeMulDivOps(object): "m8[ns] instead of f8", strict=True)) ], ids=lambda x: x.__name__) - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()]) def test_td64arr_floordiv_tdscalar(self, box, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) @@ -551,10 +700,6 @@ def test_td64arr_floordiv_tdscalar(self, box, scalar_td): marks=pytest.mark.xfail(reason="Incorrectly casts to f8", strict=True)) ], ids=lambda x: x.__name__) - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()]) def test_td64arr_rfloordiv_tdscalar(self, box, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) @@ -576,10 +721,6 @@ def test_td64arr_rfloordiv_tdscalar(self, box, scalar_td): "instead of f8", strict=True)) ], ids=lambda x: x.__name__) - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()]) def test_td64arr_rfloordiv_tdscalar_explicit(self, box, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) @@ -649,10 +790,6 @@ def test_td64arr_rfloordiv_tdlike_scalar(self, scalar_td, box_df_fail): "rmul OK", strict=True)) ], ids=lambda x: x.__name__) - @pytest.mark.parametrize('scalar_td', [ - timedelta(minutes=5, seconds=4), - Timedelta('5m4s'), - Timedelta('5m4s').to_timedelta64()]) def test_td64arr_mul_tdscalar_invalid(self, box, scalar_td): td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan @@ -869,10 +1006,6 @@ class TestTimedeltaArraylikeInvalidArithmeticOps(object): "instead of TypeError", strict=True)) ]) - @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 From 4ebd99c46398135e624d36381ef8bd2bc4c89f23 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 20:39:33 -0700 Subject: [PATCH 05/10] port add/sub tests, cleanup imports --- .../indexes/timedeltas/test_arithmetic.py | 18 +-- pandas/tests/test_arithmetic.py | 125 +++++++++++------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 916cb2190d684..fb6c8c18b3833 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -7,7 +7,7 @@ import pandas as pd import pandas.util.testing as tm -from pandas import (DatetimeIndex, TimedeltaIndex, Float64Index, Int64Index, +from pandas import (DatetimeIndex, TimedeltaIndex, Int64Index, to_timedelta, timedelta_range, date_range, Series, Timestamp, Timedelta) @@ -405,14 +405,7 @@ def test_tdi_addsub_integer_array_no_freq(self, box): # ------------------------------------------------------------- # Binary operations TimedeltaIndex and timedelta-like - - def test_tdi_add_timedeltalike(self, delta): - # only test adding/sub offsets as + is now numeric - rng = timedelta_range('1 days', '10 days') - result = rng + delta - expected = timedelta_range('1 days 02:00:00', '10 days 02:00:00', - freq='D') - tm.assert_index_equal(result, expected) + # Note: add and sub are tested in tests.test_arithmetic def test_tdi_iadd_timedeltalike(self, delta): # only test adding/sub offsets as + is now numeric @@ -422,13 +415,6 @@ def test_tdi_iadd_timedeltalike(self, delta): rng += delta tm.assert_index_equal(rng, expected) - def test_tdi_sub_timedeltalike(self, delta): - # only test adding/sub offsets as - is now numeric - rng = timedelta_range('1 days', '10 days') - result = rng - delta - expected = timedelta_range('0 days 22:00:00', '9 days 22:00:00') - tm.assert_index_equal(result, expected) - def test_tdi_isub_timedeltalike(self, delta): # only test adding/sub offsets as - is now numeric rng = timedelta_range('1 days', '10 days') diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 883553181f2f6..d4623dd7d57fe 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -14,6 +14,7 @@ from pandas.errors import NullFrequencyError from pandas._libs.tslibs import IncompatibleFrequency from pandas import ( + timedelta_range, Timedelta, Timestamp, NaT, Series, TimedeltaIndex, DatetimeIndex) @@ -30,7 +31,7 @@ def tdser(): @pytest.fixture(params=[pd.offsets.Hour(2), timedelta(hours=2), np.timedelta64(2, 'h'), Timedelta(hours=2)], - ids=str) + ids=lambda x: type(x).__name__) def delta(request): """ Several ways of representing two hours @@ -59,12 +60,11 @@ def box(request): return request.param -@pytest.fixture(params=[ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(strict=True))] - ids=lambda x: x.__name__) +@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. @@ -102,7 +102,7 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, index, box): type(scalar_td) is timedelta and index.dtype == 'f8'): raise pytest.xfail(reason="Cannot multiply timedelta by float") - expected = pd.timedelta_range('1 days', '10 days') + expected = timedelta_range('1 days', '10 days') index = tm.box_expected(index, box) expected = tm.box_expected(expected, box) @@ -268,6 +268,39 @@ def test_td64_radd_timestamp(self, box): result = Timestamp('2011-01-01') + idx tm.assert_equal(result, expected) + @pytest.mark.parametrize('box', [ + pd.Index, + Series, + pytest.param(pd.DataFrame, + marks=pytest.mark.xfail(reason="Returns object dtype " + "instead of " + "datetime64[ns]", + strict=True)) + ], ids=lambda x: x.__name__) + def test_td64arr_add_sub_timestamp(self, box): + # GH#11925 + ts = Timestamp('2012-01-01') + # TODO: parametrize over types of datetime scalar? + + tdser = Series(timedelta_range('1 day', periods=3)) + expected = Series(pd.date_range('2012-01-02', periods=3)) + + tdser = tm.box_expected(tdser, box) + expected = tm.box_expected(expected, box) + + tm.assert_equal(ts + tdser, expected) + tm.assert_equal(tdser + ts, expected) + + expected2 = Series(pd.date_range('2011-12-31', + periods=3, freq='-1D')) + expected2 = tm.box_expected(expected2, box) + + tm.assert_equal(ts - tdser, expected2) + tm.assert_equal(ts + (-tdser), expected2) + + with pytest.raises(TypeError): + tdser - ts + # ------------------------------------------------------------------ # Operations with int-like others @@ -419,42 +452,6 @@ def test_td64arr_add_sub_numeric_arr_invalid(self, box, vec, dtype, tdser): with pytest.raises(err): vector - tdser - # ------------------------------------------------------------------ - # Operations with datetime-like others - - @pytest.mark.parametrize('box', [ - pd.Index, - Series, - pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="Returns object dtype " - "instead of " - "datetime64[ns]", - strict=True)) - ], ids=lambda x: x.__name__) - def test_td64arr_add_sub_timestamp(self, box): - # GH#11925 - ts = Timestamp('2012-01-01') - # TODO: parametrize over types of datetime scalar? - - tdser = Series(pd.timedelta_range('1 day', periods=3)) - expected = Series(pd.date_range('2012-01-02', periods=3)) - - tdser = tm.box_expected(tdser, box) - expected = tm.box_expected(expected, box) - - tm.assert_equal(ts + tdser, expected) - tm.assert_equal(tdser + ts, expected) - - expected2 = Series(pd.date_range('2011-12-31', - periods=3, freq='-1D')) - expected2 = tm.box_expected(expected2, box) - - tm.assert_equal(ts - tdser, expected2) - tm.assert_equal(ts + (-tdser), expected2) - - with pytest.raises(TypeError): - tdser - ts - # ------------------------------------------------------------------ # Operations with timedelta-like others (including DateOffsets) @@ -522,9 +519,37 @@ def test_td64arr_sub_NaT(self, box): ser = tm.box_expected(ser, box) expected = tm.box_expected(expected, box) - res = ser - NaT + res = ser - pd.NaT tm.assert_equal(res, expected) + def test_td64arr_add_timedeltalike(self, delta, box): + # only test adding/sub offsets as + is now numeric + if box is pd.DataFrame and isinstance(delta, pd.DateOffset): + pytest.xfail(reason="Returns object dtype instead of m8[ns]") + + rng = timedelta_range('1 days', '10 days') + expected = timedelta_range('1 days 02:00:00', '10 days 02:00:00', + freq='D') + rng = tm.box_expected(rng, box) + expected = tm.box_expected(expected, box) + + result = rng + delta + tm.assert_equal(result, expected) + + def test_td64arr_sub_timedeltalike(self, delta, box): + # only test adding/sub offsets as - is now numeric + if box is pd.DataFrame and isinstance(delta, pd.DateOffset): + pytest.xfail(reason="Returns object dtype instead of m8[ns]") + + rng = timedelta_range('1 days', '10 days') + expected = timedelta_range('0 days 22:00:00', '9 days 22:00:00') + + rng = tm.box_expected(rng, box) + expected = tm.box_expected(expected, box) + + result = rng - delta + tm.assert_equal(result, expected) + class TestTimedeltaArraylikeMulDivOps(object): # Tests for timedelta64[ns] @@ -549,7 +574,7 @@ def test_td64arr_mul_tdlike_scalar_raises(self, delta, box): if box is pd.DataFrame and not isinstance(delta, pd.DateOffset): pytest.xfail(reason="returns m8[ns] instead of raising") - rng = pd.timedelta_range('1 days', '10 days', name='foo') + rng = timedelta_range('1 days', '10 days', name='foo') rng = tm.box_expected(rng, box) with pytest.raises(TypeError): rng * delta @@ -618,7 +643,7 @@ def test_tdi_rmul_arraylike(self, other, box_df_fail): box = box_df_fail tdi = TimedeltaIndex(['1 Day'] * 10) - expected = pd.timedelta_range('1 days', '10 days') + expected = timedelta_range('1 days', '10 days') tdi = tm.box_expected(tdi, box) expected = tm.box_expected(expected, box) @@ -634,7 +659,7 @@ def test_tdi_rmul_arraylike(self, other, box_df_fail): def test_td64arr_div_nat_invalid(self, box_df_fail): # don't allow division by NaT (maybe could in the future) box = box_df_fail # DataFrame returns all-NaT instead of raising - rng = pd.timedelta_range('1 days', '10 days', name='foo') + rng = timedelta_range('1 days', '10 days', name='foo') rng = tm.box_expected(rng, box) with pytest.raises(TypeError): rng / pd.NaT @@ -649,7 +674,7 @@ def test_td64arr_div_int(self, box_df_fail): def test_tdi_div_tdlike_scalar(self, delta, box_df_fail): box = box_df_fail # DataFrame op returns m8[ns] instead of float64 - rng = pd.timedelta_range('1 days', '10 days', name='foo') + rng = timedelta_range('1 days', '10 days', name='foo') expected = pd.Float64Index((np.arange(10) + 1) * 12, name='foo') rng = tm.box_expected(rng, box) @@ -745,7 +770,7 @@ def test_td64arr_floordiv_int(self, box_df_fail): def test_td64arr_floordiv_tdlike_scalar(self, delta, box_df_fail): box = box_df_fail # DataFrame returns m8[ns] instead of int64 dtype - tdi = pd.timedelta_range('1 days', '10 days', name='foo') + 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) From 1042c4e30ac434859bdfacfa3b6e8ca62dc11228 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 20:47:38 -0700 Subject: [PATCH 06/10] port test_tdi_add_offset-index --- .../indexes/timedeltas/test_arithmetic.py | 21 ---------- pandas/tests/test_arithmetic.py | 39 ++++++++++++++++++- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index fb6c8c18b3833..814e062febd29 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -183,27 +183,6 @@ def test_shift_no_freq(self): # ------------------------------------------------------------- - @pytest.mark.parametrize('names', [(None, None, None), - ('foo', 'bar', None), - ('foo', 'foo', 'foo')]) - def test_tdi_add_offset_index(self, names): - # GH#18849, GH#19744 - 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)], - name=names[1]) - - expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))], - freq='infer', name=names[2]) - - with tm.assert_produces_warning(PerformanceWarning): - res = tdi + other - tm.assert_index_equal(res, expected) - - with tm.assert_produces_warning(PerformanceWarning): - res2 = other + tdi - tm.assert_index_equal(res2, expected) - def test_tdi_add_offset_array(self): # GH#18849 tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index d4623dd7d57fe..3cd69ee202aac 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -11,7 +11,7 @@ import pandas.util.testing as tm from pandas.core import ops -from pandas.errors import NullFrequencyError +from pandas.errors import NullFrequencyError, PerformanceWarning from pandas._libs.tslibs import IncompatibleFrequency from pandas import ( timedelta_range, @@ -550,6 +550,43 @@ def test_td64arr_sub_timedeltalike(self, delta, box): result = rng - delta tm.assert_equal(result, expected) + # ------------------------------------------------------------------ + # __add__/__sub__ with DateOffsets and arrays of DateOffsets + + @pytest.mark.parametrize('box', [ + pd.Index, + pytest.param(Series, + marks=pytest.mark.xfail(reason="Index fails to return " + "NotImplemented on " + "reverse op", strict=True)), + 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('names', [(None, None, None), + ('foo', 'bar', None), + ('foo', 'foo', 'foo')]) + def test_tdi_add_offset_index(self, names, box): + # GH#18849, GH#19744 + 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)], + name=names[1]) + + expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))], + freq='infer', name=names[2]) + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + with tm.assert_produces_warning(PerformanceWarning): + res = tdi + other + tm.assert_equal(res, expected) + + with tm.assert_produces_warning(PerformanceWarning): + res2 = other + tdi + tm.assert_equal(res2, expected) + class TestTimedeltaArraylikeMulDivOps(object): # Tests for timedelta64[ns] From e27782689e614de1636fdbcc511c4fae781e7deb Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 21:05:17 -0700 Subject: [PATCH 07/10] port offset addsub tests --- .../indexes/timedeltas/test_arithmetic.py | 97 +------------ pandas/tests/test_arithmetic.py | 134 +++++++++++++++++- 2 files changed, 133 insertions(+), 98 deletions(-) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 814e062febd29..2522023d19496 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -11,7 +11,7 @@ to_timedelta, timedelta_range, date_range, Series, Timestamp, Timedelta) -from pandas.errors import PerformanceWarning, NullFrequencyError +from pandas.errors import NullFrequencyError @pytest.fixture(params=[pd.offsets.Hour(2), timedelta(hours=2), @@ -183,101 +183,6 @@ def test_shift_no_freq(self): # ------------------------------------------------------------- - def test_tdi_add_offset_array(self): - # GH#18849 - 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)]) - - expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))], - freq='infer') - - with tm.assert_produces_warning(PerformanceWarning): - res = tdi + other - tm.assert_index_equal(res, expected) - - with tm.assert_produces_warning(PerformanceWarning): - res2 = other + tdi - tm.assert_index_equal(res2, expected) - - @pytest.mark.parametrize('names', [(None, None, None), - ('foo', 'bar', None), - ('foo', 'foo', 'foo')]) - def test_tdi_sub_offset_index(self, names): - # GH#18824, GH#19744 - 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)], - name=names[1]) - - expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))], - freq='infer', name=names[2]) - - with tm.assert_produces_warning(PerformanceWarning): - res = tdi - other - tm.assert_index_equal(res, expected) - - def test_tdi_sub_offset_array(self): - # GH#18824 - 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)]) - - expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))], - freq='infer') - - with tm.assert_produces_warning(PerformanceWarning): - res = tdi - other - tm.assert_index_equal(res, expected) - - @pytest.mark.parametrize('names', [(None, None, None), - ('foo', 'bar', None), - ('foo', 'foo', 'foo')]) - def test_tdi_with_offset_series(self, names): - # GH#18849 - tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'], - name=names[0]) - other = Series([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)], - name=names[1]) - - expected_add = Series([tdi[n] + other[n] for n in range(len(tdi))], - name=names[2]) - - with tm.assert_produces_warning(PerformanceWarning): - res = tdi + other - tm.assert_series_equal(res, expected_add) - - with tm.assert_produces_warning(PerformanceWarning): - res2 = other + tdi - tm.assert_series_equal(res2, expected_add) - - expected_sub = Series([tdi[n] - other[n] for n in range(len(tdi))], - name=names[2]) - - with tm.assert_produces_warning(PerformanceWarning): - res3 = tdi - other - tm.assert_series_equal(res3, expected_sub) - - @pytest.mark.parametrize('box', [np.array, pd.Index, pd.Series]) - def test_tdi_add_sub_anchored_offset_arraylike(self, box): - # GH#18824 - tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) - - anchored = box([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)]) - - # addition/subtraction ops with anchored offsets should issue - # a PerformanceWarning and _then_ raise a TypeError. - with pytest.raises(TypeError): - with tm.assert_produces_warning(PerformanceWarning): - tdi + anchored - with pytest.raises(TypeError): - with tm.assert_produces_warning(PerformanceWarning): - anchored + tdi - with pytest.raises(TypeError): - with tm.assert_produces_warning(PerformanceWarning): - tdi - anchored - with pytest.raises(TypeError): - with tm.assert_produces_warning(PerformanceWarning): - anchored - tdi - def test_ufunc_coercions(self): # normal ops are also tested in tseries/test_timedeltas.py idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'], diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 3cd69ee202aac..87de136bcdf60 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -558,7 +558,8 @@ def test_td64arr_sub_timedeltalike(self, delta, box): pytest.param(Series, marks=pytest.mark.xfail(reason="Index fails to return " "NotImplemented on " - "reverse op", strict=True)), + "reverse op", + strict=True)), pytest.param(pd.DataFrame, marks=pytest.mark.xfail(reason="Tries to broadcast " "incorrectly", @@ -567,7 +568,7 @@ def test_td64arr_sub_timedeltalike(self, delta, box): @pytest.mark.parametrize('names', [(None, None, None), ('foo', 'bar', None), ('foo', 'foo', 'foo')]) - def test_tdi_add_offset_index(self, names, box): + def test_td64arr_add_offset_index(self, names, box): # GH#18849, GH#19744 tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'], name=names[0]) @@ -587,6 +588,135 @@ def test_tdi_add_offset_index(self, names, box): res2 = other + tdi tm.assert_equal(res2, expected) + # TODO: combine with test_td64arr_add_offset_index by parametrizing + # over second box? + def test_td64arr_add_offset_array(self, box_df_fail): + # GH#18849 + box = box_df_fail # tries to broadcast incorrectly + 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)]) + + expected = TimedeltaIndex([tdi[n] + other[n] for n in range(len(tdi))], + freq='infer') + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + with tm.assert_produces_warning(PerformanceWarning): + res = tdi + other + tm.assert_equal(res, expected) + + with tm.assert_produces_warning(PerformanceWarning): + res2 = other + tdi + tm.assert_equal(res2, expected) + + @pytest.mark.parametrize('names', [(None, None, None), + ('foo', 'bar', None), + ('foo', 'foo', 'foo')]) + def test_td64arr_sub_offset_index(self, names, box_df_fail): + # GH#18824, GH#19744 + box = box_df_fail # tries to broadcast incorrectly + 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)], + name=names[1]) + + expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))], + freq='infer', name=names[2]) + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + with tm.assert_produces_warning(PerformanceWarning): + res = tdi - other + tm.assert_equal(res, expected) + + def test_td64arr_sub_offset_array(self, box_df_fail): + # GH#18824 + box = box_df_fail # tries to broadcast incorrectly + 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)]) + + expected = TimedeltaIndex([tdi[n] - other[n] for n in range(len(tdi))], + freq='infer') + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + with tm.assert_produces_warning(PerformanceWarning): + res = tdi - other + tm.assert_equal(res, expected) + + @pytest.mark.parametrize('box', [ + pd.Index, + pytest.param(Series, + marks=pytest.mark.xfail(reason="object dtype Series " + "fails to return " + "NotImplemented", + strict=True, raises=TypeError)), + 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('names', [(None, None, None), + ('foo', 'bar', None), + ('foo', 'foo', 'foo')]) + def test_td64arr_with_offset_series(self, names, box): + # GH#18849 + box2 = Series if box is pd.Index else box + + tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00'], + name=names[0]) + other = Series([pd.offsets.Hour(n=1), pd.offsets.Minute(n=-2)], + name=names[1]) + + expected_add = Series([tdi[n] + other[n] for n in range(len(tdi))], + name=names[2]) + tdi = tm.box_expected(tdi, box) + expected_add = tm.box_expected(expected_add, box2) + + with tm.assert_produces_warning(PerformanceWarning): + res = tdi + other + tm.assert_equal(res, expected_add) + + with tm.assert_produces_warning(PerformanceWarning): + res2 = other + tdi + tm.assert_equal(res2, expected_add) + + # TODO: separate/parametrize add/sub test? + expected_sub = Series([tdi[n] - other[n] for n in range(len(tdi))], + name=names[2]) + expected_sub = tm.box_expected(expected_sub, box2) + + with tm.assert_produces_warning(PerformanceWarning): + res3 = tdi - other + 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): + # GH#18824 + box = box_df_fail # DataFrame tries to broadcast incorrectly + tdi = TimedeltaIndex(['1 days 00:00:00', '3 days 04:00:00']) + tdi = tm.box_expected(tdi, box) + + anchored = obox([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)]) + + # addition/subtraction ops with anchored offsets should issue + # a PerformanceWarning and _then_ raise a TypeError. + with pytest.raises(TypeError): + with tm.assert_produces_warning(PerformanceWarning): + tdi + anchored + with pytest.raises(TypeError): + with tm.assert_produces_warning(PerformanceWarning): + anchored + tdi + with pytest.raises(TypeError): + with tm.assert_produces_warning(PerformanceWarning): + tdi - anchored + with pytest.raises(TypeError): + with tm.assert_produces_warning(PerformanceWarning): + anchored - tdi + class TestTimedeltaArraylikeMulDivOps(object): # Tests for timedelta64[ns] From 96de210613e59a117c30cc623ae67173203fa231 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 31 Jul 2018 21:27:09 -0700 Subject: [PATCH 08/10] start collecting division by zero tests --- pandas/tests/frame/test_arithmetic.py | 110 ------- pandas/tests/indexes/test_numeric.py | 42 --- .../indexes/timedeltas/test_arithmetic.py | 49 --- pandas/tests/series/test_arithmetic.py | 58 ---- pandas/tests/test_arithmetic.py | 297 +++++++++++++++++- 5 files changed, 296 insertions(+), 260 deletions(-) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index fb381a5640519..94661495b604a 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -89,116 +89,6 @@ def test_df_add_flex_filled_mixed_dtypes(self): tm.assert_frame_equal(result, expected) -class TestFrameMulDiv(object): - """Tests for DataFrame multiplication and division""" - # ------------------------------------------------------------------ - # Mod By Zero - - def test_df_mod_zero_df(self): - # GH#3590, modulo as ints - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - - # this is technically wrong, as the integer portion is coerced to float - # ### - first = pd.Series([0, 0, 0, 0], dtype='float64') - second = pd.Series([np.nan, np.nan, np.nan, 0]) - expected = pd.DataFrame({'first': first, 'second': second}) - result = df % df - tm.assert_frame_equal(result, expected) - - def test_df_mod_zero_array(self): - # GH#3590, modulo as ints - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - - # this is technically wrong, as the integer portion is coerced to float - # ### - first = pd.Series([0, 0, 0, 0], dtype='float64') - second = pd.Series([np.nan, np.nan, np.nan, 0]) - expected = pd.DataFrame({'first': first, 'second': second}) - - # numpy has a slightly different (wrong) treatment - with np.errstate(all='ignore'): - arr = df.values % df.values - result2 = pd.DataFrame(arr, index=df.index, - columns=df.columns, dtype='float64') - result2.iloc[0:3, 1] = np.nan - tm.assert_frame_equal(result2, expected) - - def test_df_mod_zero_int(self): - # GH#3590, modulo as ints - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - - result = df % 0 - expected = pd.DataFrame(np.nan, index=df.index, columns=df.columns) - tm.assert_frame_equal(result, expected) - - # numpy has a slightly different (wrong) treatment - with np.errstate(all='ignore'): - arr = df.values.astype('float64') % 0 - result2 = pd.DataFrame(arr, index=df.index, columns=df.columns) - tm.assert_frame_equal(result2, expected) - - def test_df_mod_zero_series_does_not_commute(self): - # GH#3590, modulo as ints - # not commutative with series - df = pd.DataFrame(np.random.randn(10, 5)) - ser = df[0] - res = ser % df - res2 = df % ser - assert not res.fillna(0).equals(res2.fillna(0)) - - # ------------------------------------------------------------------ - # Division By Zero - - def test_df_div_zero_df(self): - # integer div, but deal with the 0's (GH#9144) - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - result = df / df - - first = pd.Series([1.0, 1.0, 1.0, 1.0]) - second = pd.Series([np.nan, np.nan, np.nan, 1]) - expected = pd.DataFrame({'first': first, 'second': second}) - tm.assert_frame_equal(result, expected) - - def test_df_div_zero_array(self): - # integer div, but deal with the 0's (GH#9144) - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - - first = pd.Series([1.0, 1.0, 1.0, 1.0]) - second = pd.Series([np.nan, np.nan, np.nan, 1]) - expected = pd.DataFrame({'first': first, 'second': second}) - - with np.errstate(all='ignore'): - arr = df.values.astype('float') / df.values - result = pd.DataFrame(arr, index=df.index, - columns=df.columns) - tm.assert_frame_equal(result, expected) - - def test_df_div_zero_int(self): - # integer div, but deal with the 0's (GH#9144) - df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) - - result = df / 0 - expected = pd.DataFrame(np.inf, index=df.index, columns=df.columns) - expected.iloc[0:3, 1] = np.nan - tm.assert_frame_equal(result, expected) - - # numpy has a slightly different (wrong) treatment - with np.errstate(all='ignore'): - arr = df.values.astype('float64') / 0 - result2 = pd.DataFrame(arr, index=df.index, - columns=df.columns) - tm.assert_frame_equal(result2, expected) - - def test_df_div_zero_series_does_not_commute(self): - # integer div, but deal with the 0's (GH#9144) - df = pd.DataFrame(np.random.randn(10, 5)) - ser = df[0] - res = ser / df - res2 = df / ser - assert not res.fillna(0).equals(res2.fillna(0)) - - class TestFrameArithmetic(object): @pytest.mark.xfail(reason='GH#7996 datetime64 units not converted to nano') diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index 71b2774a92612..597d8bb686ca8 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -162,48 +162,6 @@ def test_divmod_series(self): for r, e in zip(result, expected): tm.assert_series_equal(r, e) - def test_div_zero(self, zero): - idx = self.create_index() - - expected = Index([np.nan, np.inf, np.inf, np.inf, np.inf], - dtype=np.float64) - result = idx / zero - tm.assert_index_equal(result, expected) - 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 = self.create_index() - expected = Index([np.nan, np.inf, np.inf, np.inf, np.inf], - dtype=np.float64) - - result = idx // zero - tm.assert_index_equal(result, expected) - 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 = self.create_index() - - expected = Index([np.nan, np.nan, np.nan, np.nan, np.nan], - dtype=np.float64) - result = idx % zero - tm.assert_index_equal(result, expected) - 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 = self.create_index() - - exleft = Index([np.nan, np.inf, np.inf, np.inf, np.inf], - dtype=np.float64) - exright = Index([np.nan, np.nan, np.nan, np.nan, np.nan], - dtype=np.float64) - - result = divmod(idx, zero) - tm.assert_index_equal(result[0], exleft) - tm.assert_index_equal(result[1], exright) - def test_explicit_conversions(self): # GH 8608 diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 2522023d19496..e60705075267f 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -306,55 +306,6 @@ def test_tdi_isub_timedeltalike(self, delta): rng -= delta tm.assert_index_equal(rng, expected) - # ------------------------------------------------------------- - # __add__/__sub__ with ndarray[datetime64] and ndarray[timedelta64] - - def test_tdi_sub_dt64_array(self): - dti = pd.date_range('2016-01-01', periods=3) - tdi = dti - dti.shift(1) - dtarr = dti.values - - with pytest.raises(TypeError): - tdi - dtarr - - # TimedeltaIndex.__rsub__ - expected = pd.DatetimeIndex(dtarr) - tdi - result = dtarr - tdi - tm.assert_index_equal(result, expected) - - def test_tdi_add_dt64_array(self): - dti = pd.date_range('2016-01-01', periods=3) - tdi = dti - dti.shift(1) - dtarr = dti.values - - expected = pd.DatetimeIndex(dtarr) + tdi - result = tdi + dtarr - tm.assert_index_equal(result, expected) - result = dtarr + tdi - tm.assert_index_equal(result, expected) - - def test_tdi_add_td64_array(self): - dti = pd.date_range('2016-01-01', periods=3) - tdi = dti - dti.shift(1) - tdarr = tdi.values - - expected = 2 * tdi - result = tdi + tdarr - tm.assert_index_equal(result, expected) - result = tdarr + tdi - tm.assert_index_equal(result, expected) - - def test_tdi_sub_td64_array(self): - dti = pd.date_range('2016-01-01', periods=3) - tdi = dti - dti.shift(1) - tdarr = tdi.values - - expected = 0 * tdi - result = tdi - tdarr - tm.assert_index_equal(result, expected) - result = tdarr - tdi - tm.assert_index_equal(result, expected) - # ------------------------------------------------------------- def test_subtraction_ops(self): diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index c091df63fcfc7..1413e01000ec5 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -355,64 +355,6 @@ def test_div_equiv_binop(self): result = second / first tm.assert_series_equal(result, expected) - @pytest.mark.parametrize('dtype2', [ - np.int64, np.int32, np.int16, np.int8, - np.float64, np.float32, np.float16, - np.uint64, np.uint32, np.uint16, np.uint8]) - @pytest.mark.parametrize('dtype1', [np.int64, np.float64, np.uint64]) - def test_ser_div_ser(self, dtype1, dtype2): - # no longer do integer div for any ops, but deal with the 0's - first = Series([3, 4, 5, 8], name='first').astype(dtype1) - second = Series([0, 0, 0, 3], name='second').astype(dtype2) - - with np.errstate(all='ignore'): - expected = Series(first.values.astype(np.float64) / second.values, - dtype='float64', name=None) - expected.iloc[0:3] = np.inf - - result = first / second - tm.assert_series_equal(result, expected) - assert not result.equals(second / first) - - def test_rdiv_zero_compat(self): - # GH#8674 - zero_array = np.array([0] * 5) - data = np.random.randn(5) - expected = Series([0.] * 5) - - result = zero_array / Series(data) - tm.assert_series_equal(result, expected) - - result = Series(zero_array) / data - tm.assert_series_equal(result, expected) - - result = Series(zero_array) / Series(data) - tm.assert_series_equal(result, expected) - - def test_div_zero_inf_signs(self): - # GH#9144, inf signing - ser = Series([-1, 0, 1], name='first') - expected = Series([-np.inf, np.nan, np.inf], name='first') - - result = ser / 0 - tm.assert_series_equal(result, expected) - - def test_rdiv_zero(self): - # GH#9144 - ser = Series([-1, 0, 1], name='first') - expected = Series([0.0, np.nan, 0.0], name='first') - - result = 0 / ser - tm.assert_series_equal(result, expected) - - def test_floordiv_div(self): - # GH#9144 - ser = Series([-1, 0, 1], name='first') - - result = ser // 0 - expected = Series([-np.inf, np.nan, np.inf], name='first') - tm.assert_series_equal(result, expected) - class TestSeriesArithmetic(object): # Standard, numeric, or otherwise not-Timestamp/Timedelta/Period dtypes diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index 87de136bcdf60..fa1a691ed840d 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -10,6 +10,7 @@ import pandas as pd import pandas.util.testing as tm +from pandas.compat import long from pandas.core import ops from pandas.errors import NullFrequencyError, PerformanceWarning from pandas._libs.tslibs import IncompatibleFrequency @@ -301,6 +302,40 @@ 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 + + dti = pd.date_range('2016-01-01', periods=3) + tdi = dti - dti.shift(1) + dtarr = dti.values + expected = pd.DatetimeIndex(dtarr) - tdi + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + with pytest.raises(TypeError): + tdi - dtarr + + # TimedeltaIndex.__rsub__ + 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 + + dti = pd.date_range('2016-01-01', periods=3) + tdi = dti - dti.shift(1) + dtarr = dti.values + expected = pd.DatetimeIndex(dtarr) + tdi + + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + result = tdi + dtarr + tm.assert_equal(result, expected) + result = dtarr + tdi + tm.assert_equal(result, expected) + # ------------------------------------------------------------------ # Operations with int-like others @@ -453,7 +488,39 @@ def test_td64arr_add_sub_numeric_arr_invalid(self, box, vec, dtype, tdser): vector - tdser # ------------------------------------------------------------------ - # Operations with timedelta-like others (including DateOffsets) + # Operations with timedelta-like others + + def test_td64arr_add_td64_array(self, box_df_fail): + box = box_df_fail # DataFrame tries to broadcast incorrectly + + dti = pd.date_range('2016-01-01', periods=3) + tdi = dti - dti.shift(1) + tdarr = tdi.values + + expected = 2 * tdi + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + result = tdi + tdarr + tm.assert_equal(result, expected) + 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 + + dti = pd.date_range('2016-01-01', periods=3) + tdi = dti - dti.shift(1) + tdarr = tdi.values + + expected = 0 * tdi + tdi = tm.box_expected(tdi, box) + expected = tm.box_expected(expected, box) + + result = tdi - tdarr + tm.assert_equal(result, expected) + result = tdarr - tdi + tm.assert_equal(result, expected) # TODO: parametrize over [add, sub, radd, rsub]? @pytest.mark.parametrize('box', [ @@ -1213,3 +1280,231 @@ def test_td64arr_pow_invalid(self, scalar_td, box): with tm.assert_raises_regex(TypeError, pattern): td1 ** scalar_td + + +# ------------------------------------------------------------------ + +@pytest.fixture(params=[pd.Float64Index(np.arange(5, dtype='float64')), + pd.Int64Index(np.arange(5, dtype='int64')), + pd.UInt64Index(np.arange(5, dtype='uint64'))], + ids=lambda x: type(x).__name__) +def idx(request): + return request.param + + +zeros = [box([0] * 5, dtype=dtype) + for box in [pd.Index, np.array] + for dtype in [np.int64, np.uint64, np.float64]] +zeros.extend([np.array(0, dtype=dtype) + for dtype in [np.int64, np.uint64, np.float64]]) +zeros.extend([0, 0.0, long(0)]) + + +@pytest.fixture(params=zeros) +def zero(request): + # For testing division by (or of) zero for Index with length 5, this + # gives several scalar-zeros and length-5 vector-zeros + return request.param + + +class TestDivisionByZero(object): + + def test_div_zero(self, zero, idx): + expected = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], + dtype=np.float64) + result = idx / zero + tm.assert_index_equal(result, expected) + 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): + expected = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], + dtype=np.float64) + + result = idx // zero + tm.assert_index_equal(result, expected) + 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): + expected = pd.Index([np.nan, np.nan, np.nan, np.nan, np.nan], + dtype=np.float64) + result = idx % zero + tm.assert_index_equal(result, expected) + 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): + + exleft = pd.Index([np.nan, np.inf, np.inf, np.inf, np.inf], + dtype=np.float64) + exright = pd.Index([np.nan, np.nan, np.nan, np.nan, np.nan], + dtype=np.float64) + + result = divmod(idx, zero) + tm.assert_index_equal(result[0], exleft) + tm.assert_index_equal(result[1], exright) + + # ------------------------------------------------------------------ + + @pytest.mark.parametrize('dtype2', [ + np.int64, np.int32, np.int16, np.int8, + np.float64, np.float32, np.float16, + np.uint64, np.uint32, np.uint16, np.uint8]) + @pytest.mark.parametrize('dtype1', [np.int64, np.float64, np.uint64]) + def test_ser_div_ser(self, dtype1, dtype2): + # no longer do integer div for any ops, but deal with the 0's + first = Series([3, 4, 5, 8], name='first').astype(dtype1) + second = Series([0, 0, 0, 3], name='second').astype(dtype2) + + with np.errstate(all='ignore'): + expected = Series(first.values.astype(np.float64) / second.values, + dtype='float64', name=None) + expected.iloc[0:3] = np.inf + + result = first / second + tm.assert_series_equal(result, expected) + assert not result.equals(second / first) + + def test_rdiv_zero_compat(self): + # GH#8674 + zero_array = np.array([0] * 5) + data = np.random.randn(5) + expected = Series([0.] * 5) + + result = zero_array / Series(data) + tm.assert_series_equal(result, expected) + + result = Series(zero_array) / data + tm.assert_series_equal(result, expected) + + result = Series(zero_array) / Series(data) + tm.assert_series_equal(result, expected) + + def test_div_zero_inf_signs(self): + # GH#9144, inf signing + ser = Series([-1, 0, 1], name='first') + expected = Series([-np.inf, np.nan, np.inf], name='first') + + result = ser / 0 + tm.assert_series_equal(result, expected) + + def test_rdiv_zero(self): + # GH#9144 + ser = Series([-1, 0, 1], name='first') + expected = Series([0.0, np.nan, 0.0], name='first') + + result = 0 / ser + tm.assert_series_equal(result, expected) + + def test_floordiv_div(self): + # GH#9144 + ser = Series([-1, 0, 1], name='first') + + result = ser // 0 + expected = Series([-np.inf, np.nan, np.inf], name='first') + tm.assert_series_equal(result, expected) + + def test_df_div_zero_df(self): + # integer div, but deal with the 0's (GH#9144) + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + result = df / df + + first = pd.Series([1.0, 1.0, 1.0, 1.0]) + second = pd.Series([np.nan, np.nan, np.nan, 1]) + expected = pd.DataFrame({'first': first, 'second': second}) + tm.assert_frame_equal(result, expected) + + def test_df_div_zero_array(self): + # integer div, but deal with the 0's (GH#9144) + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + + first = pd.Series([1.0, 1.0, 1.0, 1.0]) + second = pd.Series([np.nan, np.nan, np.nan, 1]) + expected = pd.DataFrame({'first': first, 'second': second}) + + with np.errstate(all='ignore'): + arr = df.values.astype('float') / df.values + result = pd.DataFrame(arr, index=df.index, + columns=df.columns) + tm.assert_frame_equal(result, expected) + + def test_df_div_zero_int(self): + # integer div, but deal with the 0's (GH#9144) + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + + result = df / 0 + expected = pd.DataFrame(np.inf, index=df.index, columns=df.columns) + expected.iloc[0:3, 1] = np.nan + tm.assert_frame_equal(result, expected) + + # numpy has a slightly different (wrong) treatment + with np.errstate(all='ignore'): + arr = df.values.astype('float64') / 0 + result2 = pd.DataFrame(arr, index=df.index, + columns=df.columns) + tm.assert_frame_equal(result2, expected) + + def test_df_div_zero_series_does_not_commute(self): + # integer div, but deal with the 0's (GH#9144) + df = pd.DataFrame(np.random.randn(10, 5)) + ser = df[0] + res = ser / df + res2 = df / ser + assert not res.fillna(0).equals(res2.fillna(0)) + + # ------------------------------------------------------------------ + # Mod By Zero + + def test_df_mod_zero_df(self): + # GH#3590, modulo as ints + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + + # this is technically wrong, as the integer portion is coerced to float + # ### + first = pd.Series([0, 0, 0, 0], dtype='float64') + second = pd.Series([np.nan, np.nan, np.nan, 0]) + expected = pd.DataFrame({'first': first, 'second': second}) + result = df % df + tm.assert_frame_equal(result, expected) + + def test_df_mod_zero_array(self): + # GH#3590, modulo as ints + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + + # this is technically wrong, as the integer portion is coerced to float + # ### + first = pd.Series([0, 0, 0, 0], dtype='float64') + second = pd.Series([np.nan, np.nan, np.nan, 0]) + expected = pd.DataFrame({'first': first, 'second': second}) + + # numpy has a slightly different (wrong) treatment + with np.errstate(all='ignore'): + arr = df.values % df.values + result2 = pd.DataFrame(arr, index=df.index, + columns=df.columns, dtype='float64') + result2.iloc[0:3, 1] = np.nan + tm.assert_frame_equal(result2, expected) + + def test_df_mod_zero_int(self): + # GH#3590, modulo as ints + df = pd.DataFrame({'first': [3, 4, 5, 8], 'second': [0, 0, 0, 3]}) + + result = df % 0 + expected = pd.DataFrame(np.nan, index=df.index, columns=df.columns) + tm.assert_frame_equal(result, expected) + + # numpy has a slightly different (wrong) treatment + with np.errstate(all='ignore'): + arr = df.values.astype('float64') % 0 + result2 = pd.DataFrame(arr, index=df.index, columns=df.columns) + tm.assert_frame_equal(result2, expected) + + def test_df_mod_zero_series_does_not_commute(self): + # GH#3590, modulo as ints + # not commutative with series + df = pd.DataFrame(np.random.randn(10, 5)) + ser = df[0] + res = ser % df + res2 = df % ser + assert not res.fillna(0).equals(res2.fillna(0)) From fcb0cbb6ff72b2cc3832733b97fa7304c3b2695e Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 1 Aug 2018 14:24:47 -0700 Subject: [PATCH 09/10] dummy commit to force CI --- pandas/tests/test_arithmetic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index fa1a691ed840d..b113bd5047822 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -396,7 +396,7 @@ def test_td64arr_rsub_int_series_invalid(self, box, tdser): pd.Index, Series, pytest.param(pd.DataFrame, - marks=pytest.mark.xfail(reason="Tries to broadcast " + marks=pytest.mark.xfail(reason="Attempts to broadcast " "incorrectly", strict=True, raises=ValueError)) ], ids=lambda x: x.__name__) From 2409a5bd0568cca43b4d942532f664268ea85b6d Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 1 Aug 2018 18:52:34 -0700 Subject: [PATCH 10/10] fix dumb name override mistake --- pandas/tests/test_arithmetic.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/tests/test_arithmetic.py b/pandas/tests/test_arithmetic.py index b113bd5047822..0d62a5db581fe 100644 --- a/pandas/tests/test_arithmetic.py +++ b/pandas/tests/test_arithmetic.py @@ -1176,7 +1176,8 @@ def test_td64arr_rmul_numeric_array(self, op, box, vector, dtype, tdser): 'float64', 'float32', 'float16']) @pytest.mark.parametrize('vector', [np.array([20, 30, 40]), pd.Index([20, 30, 40]), - Series([20, 30, 40])]) + Series([20, 30, 40])], + ids=lambda x: type(x).__name__) def test_td64arr_div_numeric_array(self, box, vector, dtype, tdser): # GH#4521 # divide/multiply by integers @@ -1292,8 +1293,8 @@ def idx(request): return request.param -zeros = [box([0] * 5, dtype=dtype) - for box in [pd.Index, np.array] +zeros = [box_cls([0] * 5, dtype=dtype) + for box_cls in [pd.Index, np.array] for dtype in [np.int64, np.uint64, np.float64]] zeros.extend([np.array(0, dtype=dtype) for dtype in [np.int64, np.uint64, np.float64]])