From e884a69b1aa9edcb72a6f6a3ff6dc1d8e17816cd Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 15 Jan 2018 11:35:27 -0800 Subject: [PATCH 1/3] Fix Index mul/div ops with Series, closes #19080, #19042 --- pandas/core/indexes/base.py | 5 ++- pandas/core/indexes/range.py | 3 ++ pandas/tests/indexes/test_numeric.py | 31 ++++++++++--------- .../indexes/timedeltas/test_arithmetic.py | 9 +++--- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index f634d809560ee..48260c68d30f3 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -13,7 +13,7 @@ from pandas import compat from pandas.core.dtypes.generic import ( - ABCSeries, + ABCSeries, ABCDataFrame, ABCMultiIndex, ABCPeriodIndex, ABCDateOffset) @@ -4020,6 +4020,9 @@ def _add_numeric_methods_binary(cls): def _make_evaluate_binop(op, opstr, reversed=False, constructor=Index): def _evaluate_numeric_binop(self, other): + if isinstance(other, (ABCSeries, ABCDataFrame)): + return NotImplemented + other = self._validate_for_numeric_binop(other, op, opstr) # handle time-based others diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index 741dca6be0630..10a923c056be2 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -8,6 +8,7 @@ is_integer, is_scalar, is_int64_dtype) +from pandas.core.dtypes.generic import ABCSeries from pandas import compat from pandas.compat import lrange, range, get_range_parameters @@ -583,6 +584,8 @@ def _make_evaluate_binop(op, opstr, reversed=False, step=False): """ def _evaluate_numeric_binop(self, other): + if isinstance(other, ABCSeries): + return NotImplemented other = self._validate_for_numeric_binop(other, op, opstr) attrs = self._get_attributes_dict() diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index dcd592345b91c..320ec3bd76987 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -68,12 +68,12 @@ def test_numeric_compat(self): tm.assert_index_equal(result, didx) result = idx * Series(np.arange(5, dtype=arr_dtype)) - tm.assert_index_equal(result, didx) + tm.assert_series_equal(result, Series(didx)) - result = idx * Series(np.arange(5, dtype='float64') + 0.1) - expected = Float64Index(np.arange(5, dtype='float64') * - (np.arange(5, dtype='float64') + 0.1)) - tm.assert_index_equal(result, expected) + rng5 = np.arange(5, dtype='float64') + result = idx * Series(rng5 + 0.1) + expected = Series(rng5 * (rng5 + 0.1)) + tm.assert_series_equal(result, expected) # invalid pytest.raises(TypeError, @@ -95,15 +95,6 @@ def test_numeric_compat(self): for r, e in zip(result, expected): tm.assert_index_equal(r, e) - result = divmod(idx, Series(full_like(idx.values, 2))) - with np.errstate(all='ignore'): - div, mod = divmod( - idx.values, - full_like(idx.values, 2), - ) - expected = Index(div), Index(mod) - for r, e in zip(result, expected): - tm.assert_index_equal(r, e) # test power calculations both ways, GH 14973 expected = pd.Float64Index(2.0**idx.values) @@ -114,6 +105,18 @@ def test_numeric_compat(self): result = idx**2.0 tm.assert_index_equal(result, expected) + @pytest.mark.xfail(reason='GH#19252 Series has no __rdivmod__') + def test_divmod_series(self): + idx = self.create_index() + + result = divmod(idx, Series(full_like(idx.values, 2))) + with np.errstate(all='ignore'): + div, mod = divmod(idx.values, full_like(idx.values, 2)) + expected = Series(div), Series(mod) + + for r, e in zip(result, expected): + tm.assert_series_equal(r, e) + 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 3ec918e391860..962de91ed0581 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -152,11 +152,12 @@ def test_numeric_compat(self): tm.assert_index_equal(result, didx) result = idx * Series(np.arange(5, dtype='int64')) - tm.assert_index_equal(result, didx) + tm.assert_series_equal(result, Series(didx)) - result = idx * Series(np.arange(5, dtype='float64') + 0.1) - tm.assert_index_equal(result, self._holder(np.arange( - 5, dtype='float64') * (np.arange(5, dtype='float64') + 0.1))) + rng5 = np.arange(5, dtype='float64') + result = idx * Series(rng5 + 0.1) + tm.assert_series_equal(result, + Series(self._holder(rng5 * (rng5 + 0.1)))) # invalid pytest.raises(TypeError, lambda: idx * idx) From f1917a6195fb937534887dbc5a4e7d791877fe45 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 15 Jan 2018 11:36:47 -0800 Subject: [PATCH 2/3] flake8 whitespce fixup --- pandas/tests/indexes/test_numeric.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index 320ec3bd76987..1ce8ade50c071 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -95,7 +95,6 @@ def test_numeric_compat(self): for r, e in zip(result, expected): tm.assert_index_equal(r, e) - # test power calculations both ways, GH 14973 expected = pd.Float64Index(2.0**idx.values) result = 2.0**idx From 06ab12b4d3ad4f87d9274205e6dfa096925b307e Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 15 Jan 2018 20:59:02 -0800 Subject: [PATCH 3/3] whatsnew note --- doc/source/whatsnew/v0.23.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index e40318bd65db2..06e35bff0c565 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -423,7 +423,7 @@ Conversion - Bug in :class:`WeekOfMonth` and :class:`LastWeekOfMonth` where default keyword arguments for constructor raised ``ValueError`` (:issue:`19142`) - Bug in localization of a naive, datetime string in a ``Series`` constructor with a ``datetime64[ns, tz]`` dtype (:issue:`174151`) - :func:`Timestamp.replace` will now handle Daylight Savings transitions gracefully (:issue:`18319`) - +- Bug in :class:`Index` multiplication and division methods where operating with a ``Series`` would return an ``Index`` object instead of a ``Series`` object (:issue:`19042`) - Bug in ``.astype()`` to non-ns timedelta units would hold the incorrect dtype (:issue:`19176`, :issue:`19223`, :issue:`12425`)