Skip to content

Commit c84fb05

Browse files
authored
BUG: Series.__rfloordiv__ with list/tuple (#44674)
1 parent a17ca3a commit c84fb05

File tree

4 files changed

+16
-18
lines changed

4 files changed

+16
-18
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ Timezones
621621

622622
Numeric
623623
^^^^^^^
624+
- Bug in floor-dividing a list or tuple of integers by a :class:`Series` incorrectly raising (:issue:`44674`)
624625
- Bug in :meth:`DataFrame.rank` raising ``ValueError`` with ``object`` columns and ``method="first"`` (:issue:`41931`)
625626
- Bug in :meth:`DataFrame.rank` treating missing values and extreme values as equal (for example ``np.nan`` and ``np.inf``), causing incorrect results when ``na_option="bottom"`` or ``na_option="top`` used (:issue:`41931`)
626627
- Bug in ``numexpr`` engine still being used when the option ``compute.use_numexpr`` is set to ``False`` (:issue:`32556`)

pandas/core/ops/array_ops.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def _masked_arith_op(x: np.ndarray, y, op):
136136
return result
137137

138138

139-
def _na_arithmetic_op(left, right, op, is_cmp: bool = False):
139+
def _na_arithmetic_op(left: np.ndarray, right, op, is_cmp: bool = False):
140140
"""
141141
Return the result of evaluating op on the passed in values.
142142
@@ -146,6 +146,7 @@ def _na_arithmetic_op(left, right, op, is_cmp: bool = False):
146146
----------
147147
left : np.ndarray
148148
right : np.ndarray or scalar
149+
Excludes DataFrame, Series, Index, ExtensionArray.
149150
is_cmp : bool, default False
150151
If this a comparison operation.
151152
@@ -166,7 +167,7 @@ def _na_arithmetic_op(left, right, op, is_cmp: bool = False):
166167
try:
167168
result = func(left, right)
168169
except TypeError:
169-
if is_object_dtype(left) or is_object_dtype(right) and not is_cmp:
170+
if not is_cmp and (is_object_dtype(left.dtype) or is_object_dtype(right)):
170171
# For object dtype, fallback to a masked operation (only operating
171172
# on the non-missing values)
172173
# Don't do this for comparisons, as that will handle complex numbers
@@ -178,6 +179,7 @@ def _na_arithmetic_op(left, right, op, is_cmp: bool = False):
178179
if is_cmp and (is_scalar(result) or result is NotImplemented):
179180
# numpy returned a scalar instead of operating element-wise
180181
# e.g. numeric array vs str
182+
# TODO: can remove this after dropping some future numpy version?
181183
return invalid_comparison(left, right, op)
182184

183185
return missing.dispatch_fill_zeros(op, left, right, result)
@@ -251,7 +253,8 @@ def comparison_op(left: ArrayLike, right: Any, op) -> ArrayLike:
251253

252254
rvalues = lib.item_from_zerodim(rvalues)
253255
if isinstance(rvalues, list):
254-
# TODO: same for tuples?
256+
# We don't catch tuple here bc we may be comparing e.g. MultiIndex
257+
# to a tuple that represents a single entry, see test_compare_tuple_strs
255258
rvalues = np.asarray(rvalues)
256259

257260
if isinstance(rvalues, (np.ndarray, ABCExtensionArray)):
@@ -270,7 +273,7 @@ def comparison_op(left: ArrayLike, right: Any, op) -> ArrayLike:
270273
# Call the method on lvalues
271274
res_values = op(lvalues, rvalues)
272275

273-
elif is_scalar(rvalues) and isna(rvalues):
276+
elif is_scalar(rvalues) and isna(rvalues): # TODO: but not pd.NA?
274277
# numpy does not like comparisons vs None
275278
if op is operator.ne:
276279
res_values = np.ones(lvalues.shape, dtype=bool)
@@ -412,12 +415,13 @@ def get_array_op(op):
412415
"""
413416
if isinstance(op, partial):
414417
# We get here via dispatch_to_series in DataFrame case
415-
# TODO: avoid getting here
418+
# e.g. test_rolling_consistency_var_debiasing_factors
416419
return op
417420

418421
op_name = op.__name__.strip("_").lstrip("r")
419422
if op_name == "arith_op":
420-
# Reached via DataFrame._combine_frame
423+
# Reached via DataFrame._combine_frame i.e. flex methods
424+
# e.g. test_df_add_flex_filled_mixed_dtypes
421425
return op
422426

423427
if op_name in {"eq", "ne", "lt", "le", "gt", "ge"}:

pandas/core/ops/missing.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ def mask_zero_div_zero(x, y, result: np.ndarray) -> np.ndarray:
103103
array([ inf, nan, -inf])
104104
"""
105105

106-
if is_scalar(y):
106+
if not hasattr(y, "dtype"):
107+
# e.g. scalar, tuple
107108
y = np.array(y)
109+
if not hasattr(x, "dtype"):
110+
# e.g scalar, tuple
111+
x = np.array(x)
108112

109113
zmask = y == 0
110114

111-
if isinstance(zmask, bool):
112-
# FIXME: numpy did not evaluate pointwise, seen in docs build
113-
return result
114-
115115
if zmask.any():
116116

117117
# Flip sign if necessary for -0.0

pandas/tests/series/test_arithmetic.py

-7
Original file line numberDiff line numberDiff line change
@@ -729,13 +729,6 @@ def test_series_ops_name_retention(
729729
# GH#33930 consistent name renteiton
730730
op = all_binary_operators
731731

732-
if op is ops.rfloordiv and box in [list, tuple] and not flex:
733-
request.node.add_marker(
734-
pytest.mark.xfail(
735-
reason="op fails because of inconsistent ndarray-wrapping GH#28759"
736-
)
737-
)
738-
739732
left = Series(range(10), name=names[0])
740733
right = Series(range(10), name=names[1])
741734

0 commit comments

Comments
 (0)