diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 73eb6a15a1b47..11beb1f7bb12e 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -176,6 +176,7 @@ Performance Improvements Bug Fixes ~~~~~~~~~ + Categorical ^^^^^^^^^^^ @@ -211,6 +212,7 @@ Numeric - Bug in :meth:`to_numeric` in which large negative numbers were being improperly handled (:issue:`24910`) - Bug in :meth:`to_numeric` in which numbers were being coerced to float, even though ``errors`` was not ``coerce`` (:issue:`24910`) - Bug in error messages in :meth:`DataFrame.corr` and :meth:`Series.corr`. Added the possibility of using a callable. (:issue:`25729`) +- Bug in :meth:`Series.divmod` and :meth:`Series.rdivmod` which would raise an (incorrect) ``ValueError`` rather than return a pair of :class:`Series` objects as result (:issue:`25557`) - - - diff --git a/pandas/core/ops.py b/pandas/core/ops.py index 4d88ce6836ca4..bd45003c154a4 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -1660,7 +1660,7 @@ def _construct_result(left, result, index, name, dtype=None): not be enough; we still need to override the name attribute. """ out = left._constructor(result, index=index, dtype=dtype) - + out = out.__finalize__(left) out.name = name return out @@ -1668,10 +1668,11 @@ def _construct_result(left, result, index, name, dtype=None): def _construct_divmod_result(left, result, index, name, dtype=None): """divmod returns a tuple of like indexed series instead of a single series. """ - constructor = left._constructor return ( - constructor(result[0], index=index, name=name, dtype=dtype), - constructor(result[1], index=index, name=name, dtype=dtype), + _construct_result(left, result[0], index=index, name=name, + dtype=dtype), + _construct_result(left, result[1], index=index, name=name, + dtype=dtype), ) diff --git a/pandas/core/series.py b/pandas/core/series.py index 5eb3376621ab0..d4840eae8601b 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2527,6 +2527,7 @@ def _binop(self, other, func, level=None, fill_value=None): ------- Series """ + if not isinstance(other, Series): raise AssertionError('Other operand must be Series') @@ -2543,13 +2544,13 @@ def _binop(self, other, func, level=None, fill_value=None): with np.errstate(all='ignore'): result = func(this_vals, other_vals) + name = ops.get_op_result_name(self, other) - result = self._constructor(result, index=new_index, name=name) - result = result.__finalize__(self) - if name is None: - # When name is None, __finalize__ overwrites current name - result.name = None - return result + if func.__name__ in ['divmod', 'rdivmod']: + ret = ops._construct_divmod_result(self, result, new_index, name) + else: + ret = ops._construct_result(self, result, new_index, name) + return ret def combine(self, other, func, fill_value=None): """ diff --git a/pandas/tests/series/test_operators.py b/pandas/tests/series/test_operators.py index b2aac441db195..2f96fe906d980 100644 --- a/pandas/tests/series/test_operators.py +++ b/pandas/tests/series/test_operators.py @@ -741,6 +741,21 @@ def test_op_duplicate_index(self): expected = pd.Series([11, 12, np.nan], index=[1, 1, 2]) assert_series_equal(result, expected) + def test_divmod(self): + # GH25557 + a = Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) + b = Series([2, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) + + result = a.divmod(b) + expected = divmod(a, b) + assert_series_equal(result[0], expected[0]) + assert_series_equal(result[1], expected[1]) + + result = a.rdivmod(b) + expected = divmod(b, a) + assert_series_equal(result[0], expected[0]) + assert_series_equal(result[1], expected[1]) + class TestSeriesUnaryOps(object): # __neg__, __pos__, __inv__