Repository: pandas-dev/pandas

Issue:
Index * Series returns Index
Holdover from #19042 (see discussion in #19044), the example below applies to regular Index objects too.  Easy fix (tag as good-first-PR?), just need to add a check [here](https://github.com/pandas-dev/pandas/blob/master/pandas/core/indexes/base.py#L4022) that returns `NotImplemented` if `isinstance(other, ABCSeries)`.  Updating the appropriate tests is the labor-intensive part.

```
tdi = pd.TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'])
ser = Series([0, 1, 2, 3, 4], dtype=np.int64)
expected = Series(['0days', '1day', '4days', '9days', '16days'],
                          dtype='timedelta64[ns]')

result = tdi * ser
tm.assert_series_equal(result, expected)   # --> fails

>>> result
TimedeltaIndex(['0 days', '1 days', '4 days', '9 days', '16 days'], dtype='timedelta64[ns]', freq=None)
```
  


Discussion:

Resolving patch:
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -14,7 +14,7 @@
 
 from pandas.core.accessor import CachedAccessor
 from pandas.core.dtypes.generic import (
-    ABCSeries,
+    ABCSeries, ABCDataFrame,
     ABCMultiIndex,
     ABCPeriodIndex,
     ABCDateOffset)
@@ -4019,6 +4019,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
--- 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()


Test patch:
diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py
--- 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,16 +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)
         result = 2.0**idx
@@ -114,6 +104,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
--- 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)