Skip to content

Commit 35a1657

Browse files
Revert: REF: do length-checks in boilerplate decorator (#34137)
1 parent 9f7b9fc commit 35a1657

File tree

15 files changed

+64
-46
lines changed

15 files changed

+64
-46
lines changed

pandas/core/arrays/categorical.py

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def _cat_compare_op(op):
6464

6565
@unpack_zerodim_and_defer(opname)
6666
def func(self, other):
67+
if is_list_like(other) and len(other) != len(self):
68+
# TODO: Could this fail if the categories are listlike objects?
69+
raise ValueError("Lengths must match.")
70+
6771
if not self.ordered:
6872
if opname in ["__lt__", "__gt__", "__le__", "__ge__"]:
6973
raise TypeError(

pandas/core/arrays/datetimelike.py

+6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ def _validate_comparison_value(self, other):
8484
elif not is_list_like(other):
8585
raise InvalidComparison(other)
8686

87+
elif len(other) != len(self):
88+
raise ValueError("Lengths must match")
89+
8790
else:
8891
try:
8992
other = self._validate_listlike(other, opname, allow_object=True)
@@ -1234,6 +1237,9 @@ def _add_timedelta_arraylike(self, other):
12341237
"""
12351238
# overridden by PeriodArray
12361239

1240+
if len(self) != len(other):
1241+
raise ValueError("cannot add indices of unequal length")
1242+
12371243
if isinstance(other, np.ndarray):
12381244
# ndarray[timedelta64]; wrap in TimedeltaIndex for op
12391245
from pandas.core.arrays import TimedeltaArray

pandas/core/arrays/datetimes.py

+3
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,9 @@ def _assert_tzawareness_compat(self, other):
654654

655655
def _sub_datetime_arraylike(self, other):
656656
"""subtract DatetimeArray/Index or ndarray[datetime64]"""
657+
if len(self) != len(other):
658+
raise ValueError("cannot add indices of unequal length")
659+
657660
if isinstance(other, np.ndarray):
658661
assert is_datetime64_dtype(other)
659662
other = type(self)(other)

pandas/core/arrays/integer.py

+4
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ def cmp_method(self, other):
517517
raise NotImplementedError(
518518
"can only perform ops with 1-d structures"
519519
)
520+
if len(self) != len(other):
521+
raise ValueError("Lengths must match to compare")
520522

521523
if other is libmissing.NA:
522524
# numpy does not handle pd.NA well as "other" scalar (it returns
@@ -620,6 +622,8 @@ def integer_arithmetic_method(self, other):
620622
raise NotImplementedError(
621623
"can only perform ops with 1-d structures"
622624
)
625+
if len(self) != len(other):
626+
raise ValueError("Lengths must match")
623627
if not (is_float_dtype(other) or is_integer_dtype(other)):
624628
raise TypeError("can only perform ops with numeric values")
625629

pandas/core/arrays/timedeltas.py

+19-4
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,10 @@ def __mul__(self, other):
471471
if not hasattr(other, "dtype"):
472472
# list, tuple
473473
other = np.array(other)
474+
if len(other) != len(self) and not is_timedelta64_dtype(other.dtype):
475+
# Exclude timedelta64 here so we correctly raise TypeError
476+
# for that instead of ValueError
477+
raise ValueError("Cannot multiply with unequal lengths")
474478

475479
if is_object_dtype(other.dtype):
476480
# this multiplication will succeed only if all elements of other
@@ -514,7 +518,10 @@ def __truediv__(self, other):
514518
# e.g. list, tuple
515519
other = np.array(other)
516520

517-
if is_timedelta64_dtype(other.dtype):
521+
if len(other) != len(self):
522+
raise ValueError("Cannot divide vectors with unequal lengths")
523+
524+
elif is_timedelta64_dtype(other.dtype):
518525
# let numpy handle it
519526
return self._data / other
520527

@@ -564,7 +571,10 @@ def __rtruediv__(self, other):
564571
# e.g. list, tuple
565572
other = np.array(other)
566573

567-
if is_timedelta64_dtype(other.dtype):
574+
if len(other) != len(self):
575+
raise ValueError("Cannot divide vectors with unequal lengths")
576+
577+
elif is_timedelta64_dtype(other.dtype):
568578
# let numpy handle it
569579
return other / self._data
570580

@@ -613,8 +623,10 @@ def __floordiv__(self, other):
613623
if not hasattr(other, "dtype"):
614624
# list, tuple
615625
other = np.array(other)
626+
if len(other) != len(self):
627+
raise ValueError("Cannot divide with unequal lengths")
616628

617-
if is_timedelta64_dtype(other.dtype):
629+
elif is_timedelta64_dtype(other.dtype):
618630
other = type(self)(other)
619631

620632
# numpy timedelta64 does not natively support floordiv, so operate
@@ -666,7 +678,10 @@ def __rfloordiv__(self, other):
666678
# list, tuple
667679
other = np.array(other)
668680

669-
if is_timedelta64_dtype(other.dtype):
681+
if len(other) != len(self):
682+
raise ValueError("Cannot divide with unequal lengths")
683+
684+
elif is_timedelta64_dtype(other.dtype):
670685
other = type(self)(other)
671686

672687
# numpy timedelta64 does not natively support floordiv, so operate

pandas/core/indexes/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
from pandas.core.indexes.frozen import FrozenList
7676
import pandas.core.missing as missing
7777
from pandas.core.ops import get_op_result_name
78-
from pandas.core.ops.common import unpack_zerodim_and_defer
7978
from pandas.core.ops.invalid import make_invalid_op
8079
from pandas.core.sorting import ensure_key_mapped
8180
from pandas.core.strings import StringMethods
@@ -109,8 +108,10 @@
109108

110109

111110
def _make_comparison_op(op, cls):
112-
@unpack_zerodim_and_defer(op.__name__)
113111
def cmp_method(self, other):
112+
if isinstance(other, (np.ndarray, Index, ABCSeries, ExtensionArray)):
113+
if other.ndim > 0 and len(self) != len(other):
114+
raise ValueError("Lengths must match to compare")
114115

115116
if is_object_dtype(self.dtype) and isinstance(other, ABCCategorical):
116117
left = type(other)(self._values, dtype=other.dtype)

pandas/core/ops/common.py

+1-23
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
"""
22
Boilerplate functions used in defining binary operations.
33
"""
4-
from collections import UserDict
54
from functools import wraps
65
from typing import Callable
76

8-
import numpy as np
9-
10-
from pandas._libs.lib import is_list_like, item_from_zerodim
7+
from pandas._libs.lib import item_from_zerodim
118
from pandas._typing import F
129

1310
from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries
@@ -65,25 +62,6 @@ def new_method(self, other):
6562

6663
other = item_from_zerodim(other)
6764

68-
if isinstance(self, (ABCSeries, ABCDataFrame)) and isinstance(
69-
other, (ABCSeries, ABCDataFrame)
70-
):
71-
# we dont require length matches
72-
pass
73-
elif is_list_like(other, allow_sets=False) and not isinstance(
74-
other, (dict, UserDict)
75-
):
76-
if len(other) != len(self):
77-
if len(other) == 1 and not hasattr(other, "dtype"):
78-
# i.e. unpack scalar list, but leave e.g. Categorical,
79-
# for which the scalar behavior doesnt match the
80-
# array behavior
81-
other = other[0]
82-
else:
83-
raise ValueError(
84-
"Lengths must match", self.shape, np.shape(other), type(other)
85-
)
86-
8765
return method(self, other)
8866

8967
return new_method

pandas/tests/arithmetic/test_datetime64.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ def test_sub_dti_dti(self):
22062206
# different length raises ValueError
22072207
dti1 = date_range("20130101", periods=3)
22082208
dti2 = date_range("20130101", periods=4)
2209-
msg = "Lengths must match"
2209+
msg = "cannot add indices of unequal length"
22102210
with pytest.raises(ValueError, match=msg):
22112211
dti1 - dti2
22122212

pandas/tests/arithmetic/test_numeric.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ def test_mul_datelike_raises(self, numeric_idx):
649649

650650
def test_mul_size_mismatch_raises(self, numeric_idx):
651651
idx = numeric_idx
652-
msg = "Lengths must match"
652+
msg = "operands could not be broadcast together"
653653
with pytest.raises(ValueError, match=msg):
654654
idx * idx[0:3]
655655
with pytest.raises(ValueError, match=msg):

pandas/tests/arithmetic/test_timedelta64.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ def test_addition_ops(self):
451451
tm.assert_index_equal(result, expected)
452452

453453
# unequal length
454-
msg = "Lengths must match"
454+
msg = "cannot add indices of unequal length"
455455
with pytest.raises(ValueError, match=msg):
456456
tdi + dti[0:1]
457457
with pytest.raises(ValueError, match=msg):
@@ -1723,7 +1723,7 @@ def test_tdarr_div_length_mismatch(self, box_with_array):
17231723
mismatched = [1, 2, 3, 4]
17241724

17251725
rng = tm.box_expected(rng, box_with_array)
1726-
msg = "Lengths must match|Unable to coerce to Series"
1726+
msg = "Cannot divide vectors|Unable to coerce to Series"
17271727
for obj in [mismatched, mismatched[:2]]:
17281728
# one shorter, one longer
17291729
for other in [obj, np.array(obj), pd.Index(obj)]:
@@ -1905,14 +1905,12 @@ def test_td64arr_mul_tdscalar_invalid(self, box_with_array, scalar_td):
19051905
def test_td64arr_mul_too_short_raises(self, box_with_array):
19061906
idx = TimedeltaIndex(np.arange(5, dtype="int64"))
19071907
idx = tm.box_expected(idx, box_with_array)
1908-
msg = "|".join(
1909-
[
1910-
"Lengths must match", # <- EA, Index, Series
1911-
"cannot use operands with types dtype", # <- DataFrame
1912-
"Unable to coerce to Series", # <- Series
1913-
]
1908+
msg = (
1909+
"cannot use operands with types dtype|"
1910+
"Cannot multiply with unequal lengths|"
1911+
"Unable to coerce to Series"
19141912
)
1915-
with pytest.raises((ValueError, TypeError), match=msg):
1913+
with pytest.raises(TypeError, match=msg):
19161914
# length check before dtype check
19171915
idx * idx[:3]
19181916
with pytest.raises(ValueError, match=msg):

pandas/tests/arrays/boolean/test_logical.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_empty_ok(self, all_logical_operators):
4646
def test_logical_length_mismatch_raises(self, all_logical_operators):
4747
op_name = all_logical_operators
4848
a = pd.array([True, False, None], dtype="boolean")
49-
msg = "Lengths must match"
49+
msg = "Lengths must match to compare"
5050

5151
with pytest.raises(ValueError, match=msg):
5252
getattr(a, op_name)([True, False])

pandas/tests/arrays/integer/test_arithmetic.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,8 @@ def test_error(self, data, all_arithmetic_operators):
232232
result = opa(pd.DataFrame({"A": s}))
233233
assert result is NotImplemented
234234

235-
# msg = r"can only perform ops with 1-d structures"
236-
msg = "Lengths must match"
237-
with pytest.raises(ValueError, match=msg):
235+
msg = r"can only perform ops with 1-d structures"
236+
with pytest.raises(NotImplementedError, match=msg):
238237
opa(np.arange(len(s)).reshape(-1, len(s)))
239238

240239
@pytest.mark.parametrize("zero, negative", [(0, False), (0.0, False), (-0.0, True)])

pandas/tests/arrays/string_/test_string.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_add_2d():
9898
a + b
9999

100100
s = pd.Series(a)
101-
with pytest.raises(ValueError, match="Lengths must match"):
101+
with pytest.raises(ValueError, match="3 != 1"):
102102
s + b
103103

104104

pandas/tests/indexes/interval/test_interval.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ def test_comparison(self):
579579
with pytest.raises(TypeError, match=msg):
580580
self.index > np.arange(2)
581581

582-
msg = "Lengths must match"
582+
msg = "Lengths must match to compare"
583583
with pytest.raises(ValueError, match=msg):
584584
self.index > np.arange(3)
585585

pandas/tests/indexes/test_base.py

+10
Original file line numberDiff line numberDiff line change
@@ -2423,6 +2423,16 @@ def test_index_repr_bool_nan(self):
24232423
out2 = "Index([True, False, nan], dtype='object')"
24242424
assert out2 == exp2
24252425

2426+
@pytest.mark.filterwarnings("ignore:elementwise comparison failed:FutureWarning")
2427+
def test_index_with_tuple_bool(self):
2428+
# GH34123
2429+
# TODO: remove tupleize_cols=False once correct behaviour is restored
2430+
# TODO: also this op right now produces FutureWarning from numpy
2431+
idx = Index([("a", "b"), ("b", "c"), ("c", "a")], tupleize_cols=False)
2432+
result = idx == ("c", "a",)
2433+
expected = np.array([False, False, True])
2434+
tm.assert_numpy_array_equal(result, expected)
2435+
24262436

24272437
class TestIndexUtils:
24282438
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)