From 7e461a18d9f6928132afec6f48ce968b3e989ba6 Mon Sep 17 00:00:00 2001 From: Kaiqi Dong Date: Mon, 3 Dec 2018 17:43:52 +0100 Subject: [PATCH 01/12] remove \n from docstring --- pandas/core/arrays/datetimes.py | 26 +++++++++++++------------- pandas/core/arrays/timedeltas.py | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index cfe3afcf3730a..b3df505d56d78 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -82,7 +82,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -1072,19 +1072,19 @@ def date(self): return tslib.ints_to_pydatetime(timestamps, box="date") - year = _field_accessor('year', 'Y', "\n The year of the datetime\n") + year = _field_accessor('year', 'Y', "The year of the datetime") month = _field_accessor('month', 'M', - "\n The month as January=1, December=12 \n") - day = _field_accessor('day', 'D', "\nThe days of the datetime\n") - hour = _field_accessor('hour', 'h', "\nThe hours of the datetime\n") - minute = _field_accessor('minute', 'm', "\nThe minutes of the datetime\n") - second = _field_accessor('second', 's', "\nThe seconds of the datetime\n") + "The month as January=1, December=12") + day = _field_accessor('day', 'D', "The days of the datetime") + hour = _field_accessor('hour', 'h', "The hours of the datetime") + minute = _field_accessor('minute', 'm', "The minutes of the datetime") + second = _field_accessor('second', 's', "The seconds of the datetime") microsecond = _field_accessor('microsecond', 'us', - "\nThe microseconds of the datetime\n") + "The microseconds of the datetime") nanosecond = _field_accessor('nanosecond', 'ns', - "\nThe nanoseconds of the datetime\n") + "The nanoseconds of the datetime") weekofyear = _field_accessor('weekofyear', 'woy', - "\nThe week ordinal of the year\n") + "The week ordinal of the year") week = weekofyear _dayofweek_doc = """ The day of the week with Monday=0, Sunday=6. @@ -1129,12 +1129,12 @@ def date(self): "The name of day in a week (ex: Friday)\n\n.. deprecated:: 0.23.0") dayofyear = _field_accessor('dayofyear', 'doy', - "\nThe ordinal day of the year\n") - quarter = _field_accessor('quarter', 'q', "\nThe quarter of the date\n") + "The ordinal day of the year") + quarter = _field_accessor('quarter', 'q', "The quarter of the date") days_in_month = _field_accessor( 'days_in_month', 'dim', - "\nThe number of days in the month\n") + "The number of days in the month") daysinmonth = days_in_month _is_month_doc = """ Indicates whether the date is the {first_or_last} day of the month. diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 830283d31a929..4afc9f5483c2a 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -59,7 +59,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -684,16 +684,16 @@ def to_pytimedelta(self): return tslibs.ints_to_pytimedelta(self.asi8) days = _field_accessor("days", "days", - "\nNumber of days for each element.\n") + "Number of days for each element.") seconds = _field_accessor("seconds", "seconds", - "\nNumber of seconds (>= 0 and less than 1 day) " - "for each element.\n") + "Number of seconds (>= 0 and less than 1 day) " + "for each element.") microseconds = _field_accessor("microseconds", "microseconds", - "\nNumber of microseconds (>= 0 and less " - "than 1 second) for each element.\n") + "Number of microseconds (>= 0 and less " + "than 1 second) for each element.") nanoseconds = _field_accessor("nanoseconds", "nanoseconds", - "\nNumber of nanoseconds (>= 0 and less " - "than 1 microsecond) for each element.\n") + "Number of nanoseconds (>= 0 and less " + "than 1 microsecond) for each element.") @property def components(self): From dea38f24c0067ae3fe9484b837c9649714213bba Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:26:31 +0100 Subject: [PATCH 02/12] fix issue 17038 --- pandas/core/reshape/pivot.py | 4 +++- pandas/tests/reshape/test_pivot.py | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index b443ba142369c..9743d90f4dd04 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,9 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: + + # GH 17038, this check should only happen if index is specified + if table.index.nlevels > 1 and index: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 743fc50c87e96..46a05123c9fdd 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,12 +896,6 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() - # no rows - rtable = self.data.pivot_table( - columns=["AA", "BB"], margins=True, aggfunc=np.mean - ) - assert isinstance(rtable, Series) - table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -972,6 +966,20 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) + @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) + def test_pivot_table_multiindex_only(self, cols): + # GH 17038 + df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) + + result = df2.pivot_table(values="v", columns=cols) + expected = DataFrame( + [[4, 5, 6]], + columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), + index=Index(["v"]), + ) + + tm.assert_frame_equal(result, expected) + def test_pivot_no_level_overlap(self): # GH #1181 From cd9e7ac3f31ffaf95cd628863df911dea9fa1248 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:29:43 +0100 Subject: [PATCH 03/12] revert change --- pandas/core/reshape/pivot.py | 3 +-- pandas/tests/reshape/test_pivot.py | 20 ++++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index 9743d90f4dd04..a7cdbb0da7a4e 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -118,8 +118,7 @@ def pivot_table( table = agged - # GH 17038, this check should only happen if index is specified - if table.index.nlevels > 1 and index: + if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 46a05123c9fdd..743fc50c87e96 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,6 +896,12 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() + # no rows + rtable = self.data.pivot_table( + columns=["AA", "BB"], margins=True, aggfunc=np.mean + ) + assert isinstance(rtable, Series) + table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -966,20 +972,6 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) - @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) - def test_pivot_table_multiindex_only(self, cols): - # GH 17038 - df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) - - result = df2.pivot_table(values="v", columns=cols) - expected = DataFrame( - [[4, 5, 6]], - columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), - index=Index(["v"]), - ) - - tm.assert_frame_equal(result, expected) - def test_pivot_no_level_overlap(self): # GH #1181 From e5e912be0f596943067a7df812442764d311a086 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:30:16 +0100 Subject: [PATCH 04/12] revert change --- pandas/core/reshape/pivot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index a7cdbb0da7a4e..b443ba142369c 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,6 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer From 0e370f36509c6040d1a8da11235efa075ef11035 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 12 May 2020 18:03:38 +0200 Subject: [PATCH 05/12] revert j change --- pandas/core/arrays/categorical.py | 4 ++++ pandas/core/arrays/datetimelike.py | 6 +++++ pandas/core/arrays/datetimes.py | 3 +++ pandas/core/arrays/integer.py | 4 ++++ pandas/core/arrays/timedeltas.py | 23 ++++++++++++++---- pandas/core/indexes/base.py | 5 ++-- pandas/core/ops/common.py | 24 +------------------ pandas/tests/arithmetic/test_datetime64.py | 2 +- pandas/tests/arithmetic/test_numeric.py | 2 +- pandas/tests/arithmetic/test_timedelta64.py | 16 ++++++------- pandas/tests/arrays/boolean/test_logical.py | 2 +- .../tests/arrays/integer/test_arithmetic.py | 5 ++-- pandas/tests/arrays/string_/test_string.py | 2 +- .../tests/indexes/interval/test_interval.py | 2 +- 14 files changed, 54 insertions(+), 46 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index dd5ff7781e463..7c8af1089bb86 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -66,6 +66,10 @@ def _cat_compare_op(op): @unpack_zerodim_and_defer(opname) def func(self, other): + if is_list_like(other) and len(other) != len(self): + # TODO: Could this fail if the categories are listlike objects? + raise ValueError("Lengths must match.") + if not self.ordered: if opname in ["__lt__", "__gt__", "__le__", "__ge__"]: raise TypeError( diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 06f1b18741bdb..65f8d09758dac 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -85,6 +85,9 @@ def _validate_comparison_value(self, other): elif not is_list_like(other): raise InvalidComparison(other) + elif len(other) != len(self): + raise ValueError("Lengths must match") + else: try: other = self._validate_listlike(other, opname, allow_object=True) @@ -1231,6 +1234,9 @@ def _add_timedelta_arraylike(self, other): """ # overridden by PeriodArray + if len(self) != len(other): + raise ValueError("cannot add indices of unequal length") + if isinstance(other, np.ndarray): # ndarray[timedelta64]; wrap in TimedeltaIndex for op from pandas.core.arrays import TimedeltaArray diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index dc17f13da068b..7bcd43ec07314 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -654,6 +654,9 @@ def _assert_tzawareness_compat(self, other): def _sub_datetime_arraylike(self, other): """subtract DatetimeArray/Index or ndarray[datetime64]""" + if len(self) != len(other): + raise ValueError("cannot add indices of unequal length") + if isinstance(other, np.ndarray): assert is_datetime64_dtype(other) other = type(self)(other) diff --git a/pandas/core/arrays/integer.py b/pandas/core/arrays/integer.py index 3ca7e028913c6..5a90ea4a36a21 100644 --- a/pandas/core/arrays/integer.py +++ b/pandas/core/arrays/integer.py @@ -517,6 +517,8 @@ def cmp_method(self, other): raise NotImplementedError( "can only perform ops with 1-d structures" ) + if len(self) != len(other): + raise ValueError("Lengths must match to compare") if other is libmissing.NA: # numpy does not handle pd.NA well as "other" scalar (it returns @@ -620,6 +622,8 @@ def integer_arithmetic_method(self, other): raise NotImplementedError( "can only perform ops with 1-d structures" ) + if len(self) != len(other): + raise ValueError("Lengths must match") if not (is_float_dtype(other) or is_integer_dtype(other)): raise TypeError("can only perform ops with numeric values") diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 164d45334033e..73b8353b220c5 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -460,6 +460,10 @@ def __mul__(self, other): if not hasattr(other, "dtype"): # list, tuple other = np.array(other) + if len(other) != len(self) and not is_timedelta64_dtype(other): + # Exclude timedelta64 here so we correctly raise TypeError + # for that instead of ValueError + raise ValueError("Cannot multiply with unequal lengths") if is_object_dtype(other.dtype): # this multiplication will succeed only if all elements of other @@ -503,7 +507,10 @@ def __truediv__(self, other): # e.g. list, tuple other = np.array(other) - if is_timedelta64_dtype(other.dtype): + if len(other) != len(self): + raise ValueError("Cannot divide vectors with unequal lengths") + + elif is_timedelta64_dtype(other.dtype): # let numpy handle it return self._data / other @@ -553,7 +560,10 @@ def __rtruediv__(self, other): # e.g. list, tuple other = np.array(other) - if is_timedelta64_dtype(other.dtype): + if len(other) != len(self): + raise ValueError("Cannot divide vectors with unequal lengths") + + elif is_timedelta64_dtype(other.dtype): # let numpy handle it return other / self._data @@ -602,8 +612,10 @@ def __floordiv__(self, other): if not hasattr(other, "dtype"): # list, tuple other = np.array(other) + if len(other) != len(self): + raise ValueError("Cannot divide with unequal lengths") - if is_timedelta64_dtype(other.dtype): + elif is_timedelta64_dtype(other.dtype): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate @@ -655,7 +667,10 @@ def __rfloordiv__(self, other): # list, tuple other = np.array(other) - if is_timedelta64_dtype(other.dtype): + if len(other) != len(self): + raise ValueError("Cannot divide with unequal lengths") + + elif is_timedelta64_dtype(other.dtype): other = type(self)(other) # numpy timedelta64 does not natively support floordiv, so operate diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index b8a9827b5effd..0f170738f92d9 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -75,7 +75,6 @@ from pandas.core.indexes.frozen import FrozenList import pandas.core.missing as missing from pandas.core.ops import get_op_result_name -from pandas.core.ops.common import unpack_zerodim_and_defer from pandas.core.ops.invalid import make_invalid_op from pandas.core.sorting import ensure_key_mapped from pandas.core.strings import StringMethods @@ -109,8 +108,10 @@ def _make_comparison_op(op, cls): - @unpack_zerodim_and_defer(op.__name__) def cmp_method(self, other): + if isinstance(other, (np.ndarray, Index, ABCSeries, ExtensionArray)): + if other.ndim > 0 and len(self) != len(other): + raise ValueError("Lengths must match to compare") if is_object_dtype(self.dtype) and isinstance(other, ABCCategorical): left = type(other)(self._values, dtype=other.dtype) diff --git a/pandas/core/ops/common.py b/pandas/core/ops/common.py index 1fb9398083884..515a0a5198d74 100644 --- a/pandas/core/ops/common.py +++ b/pandas/core/ops/common.py @@ -1,13 +1,10 @@ """ Boilerplate functions used in defining binary operations. """ -from collections import UserDict from functools import wraps from typing import Callable -import numpy as np - -from pandas._libs.lib import is_list_like, item_from_zerodim +from pandas._libs.lib import item_from_zerodim from pandas._typing import F from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries @@ -65,25 +62,6 @@ def new_method(self, other): other = item_from_zerodim(other) - if isinstance(self, (ABCSeries, ABCDataFrame)) and isinstance( - other, (ABCSeries, ABCDataFrame) - ): - # we dont require length matches - pass - elif is_list_like(other, allow_sets=False) and not isinstance( - other, (dict, UserDict) - ): - if len(other) != len(self): - if len(other) == 1 and not hasattr(other, "dtype"): - # i.e. unpack scalar list, but leave e.g. Categorical, - # for which the scalar behavior doesnt match the - # array behavior - other = other[0] - else: - raise ValueError( - "Lengths must match", self.shape, np.shape(other), type(other) - ) - return method(self, other) return new_method diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 0fb3cb1025639..8c480faa4ee81 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -2206,7 +2206,7 @@ def test_sub_dti_dti(self): # different length raises ValueError dti1 = date_range("20130101", periods=3) dti2 = date_range("20130101", periods=4) - msg = "Lengths must match" + msg = "cannot add indices of unequal length" with pytest.raises(ValueError, match=msg): dti1 - dti2 diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index 269235b943e46..b085ee968dadb 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -647,7 +647,7 @@ def test_mul_datelike_raises(self, numeric_idx): def test_mul_size_mismatch_raises(self, numeric_idx): idx = numeric_idx - msg = "Lengths must match" + msg = "operands could not be broadcast together" with pytest.raises(ValueError, match=msg): idx * idx[0:3] with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index d540ff923c929..3aaafa0fb33cd 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -451,7 +451,7 @@ def test_addition_ops(self): tm.assert_index_equal(result, expected) # unequal length - msg = "Lengths must match" + msg = "cannot add indices of unequal length" with pytest.raises(ValueError, match=msg): tdi + dti[0:1] with pytest.raises(ValueError, match=msg): @@ -1730,7 +1730,7 @@ def test_tdarr_div_length_mismatch(self, box_with_array): mismatched = [1, 2, 3, 4] rng = tm.box_expected(rng, box_with_array) - msg = "Lengths must match|Unable to coerce to Series" + msg = "Cannot divide vectors|Unable to coerce to Series" for obj in [mismatched, mismatched[:2]]: # one shorter, one longer for other in [obj, np.array(obj), pd.Index(obj)]: @@ -1912,14 +1912,12 @@ def test_td64arr_mul_tdscalar_invalid(self, box_with_array, scalar_td): def test_td64arr_mul_too_short_raises(self, box_with_array): idx = TimedeltaIndex(np.arange(5, dtype="int64")) idx = tm.box_expected(idx, box_with_array) - msg = "|".join( - [ - "Lengths must match", # <- EA, Index, Series - "cannot use operands with types dtype", # <- DataFrame - "Unable to coerce to Series", # <- Series - ] + msg = ( + "cannot use operands with types dtype|" + "Cannot multiply with unequal lengths|" + "Unable to coerce to Series" ) - with pytest.raises((ValueError, TypeError), match=msg): + with pytest.raises(TypeError, match=msg): # length check before dtype check idx * idx[:3] with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/arrays/boolean/test_logical.py b/pandas/tests/arrays/boolean/test_logical.py index a61746d46daeb..bf4775bbd7b32 100644 --- a/pandas/tests/arrays/boolean/test_logical.py +++ b/pandas/tests/arrays/boolean/test_logical.py @@ -46,7 +46,7 @@ def test_empty_ok(self, all_logical_operators): def test_logical_length_mismatch_raises(self, all_logical_operators): op_name = all_logical_operators a = pd.array([True, False, None], dtype="boolean") - msg = "Lengths must match" + msg = "Lengths must match to compare" with pytest.raises(ValueError, match=msg): getattr(a, op_name)([True, False]) diff --git a/pandas/tests/arrays/integer/test_arithmetic.py b/pandas/tests/arrays/integer/test_arithmetic.py index b7fdd8581101b..18f1dac3c13b2 100644 --- a/pandas/tests/arrays/integer/test_arithmetic.py +++ b/pandas/tests/arrays/integer/test_arithmetic.py @@ -232,9 +232,8 @@ def test_error(self, data, all_arithmetic_operators): result = opa(pd.DataFrame({"A": s})) assert result is NotImplemented - # msg = r"can only perform ops with 1-d structures" - msg = "Lengths must match" - with pytest.raises(ValueError, match=msg): + msg = r"can only perform ops with 1-d structures" + with pytest.raises(NotImplementedError, match=msg): opa(np.arange(len(s)).reshape(-1, len(s))) @pytest.mark.parametrize("zero, negative", [(0, False), (0.0, False), (-0.0, True)]) diff --git a/pandas/tests/arrays/string_/test_string.py b/pandas/tests/arrays/string_/test_string.py index 2e047b5c4eb60..6f9a1a5be4c43 100644 --- a/pandas/tests/arrays/string_/test_string.py +++ b/pandas/tests/arrays/string_/test_string.py @@ -98,7 +98,7 @@ def test_add_2d(): a + b s = pd.Series(a) - with pytest.raises(ValueError, match="Lengths must match"): + with pytest.raises(ValueError, match="3 != 1"): s + b diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index fac9eb1c34dbf..997887cc18d61 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -579,7 +579,7 @@ def test_comparison(self): with pytest.raises(TypeError, match=msg): self.index > np.arange(2) - msg = "Lengths must match" + msg = "Lengths must match to compare" with pytest.raises(ValueError, match=msg): self.index > np.arange(3) From 0b9db3648cda51a3fadadef3c7b1b2ff59828d9d Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 12 May 2020 18:08:43 +0200 Subject: [PATCH 06/12] black --- pandas/tests/arithmetic/test_timedelta64.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 3aaafa0fb33cd..1b430d02653a8 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1913,9 +1913,9 @@ def test_td64arr_mul_too_short_raises(self, box_with_array): idx = TimedeltaIndex(np.arange(5, dtype="int64")) idx = tm.box_expected(idx, box_with_array) msg = ( - "cannot use operands with types dtype|" - "Cannot multiply with unequal lengths|" - "Unable to coerce to Series" + "cannot use operands with types dtype|" + "Cannot multiply with unequal lengths|" + "Unable to coerce to Series" ) with pytest.raises(TypeError, match=msg): # length check before dtype check From 4d4deb68a075178e6f633c4a8ef42871d96680e3 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 12 May 2020 18:38:12 +0200 Subject: [PATCH 07/12] use dtype --- pandas/core/arrays/timedeltas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 73b8353b220c5..f0e2039b16196 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -460,7 +460,7 @@ def __mul__(self, other): if not hasattr(other, "dtype"): # list, tuple other = np.array(other) - if len(other) != len(self) and not is_timedelta64_dtype(other): + if len(other) != len(self) and not is_timedelta64_dtype(other.dtype): # Exclude timedelta64 here so we correctly raise TypeError # for that instead of ValueError raise ValueError("Cannot multiply with unequal lengths") From 360eb899ee4ead4a36e40013a8ee752b0ef154d3 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Wed, 13 May 2020 20:31:10 +0200 Subject: [PATCH 08/12] add test and todo --- pandas/tests/indexes/test_base.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 9f235dcdbb295..692565a2d5262 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -2423,6 +2423,15 @@ def test_index_repr_bool_nan(self): out2 = "Index([True, False, nan], dtype='object')" assert out2 == exp2 + def test_index_with_tuple_bool(self): + # GH34123 + # TODO: the result seems wrong to me, should be [False, False, True] + # TODO: also this op right now produces FutureWarning from numpy + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + result = Index([("a", "b"), ("b", "c"), ("c", "a")]) == ("c", "a") + expected = np.array([False, False, False]) + tm.assert_numpy_array_equal(result, expected) + class TestIndexUtils: @pytest.mark.parametrize( From 32f344f616c7286c37c3c3a57972cff996a509fc Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Wed, 13 May 2020 21:16:01 +0200 Subject: [PATCH 09/12] rerun --- pandas/tests/indexes/test_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 692565a2d5262..470512e0d4fe8 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -2427,8 +2427,7 @@ def test_index_with_tuple_bool(self): # GH34123 # TODO: the result seems wrong to me, should be [False, False, True] # TODO: also this op right now produces FutureWarning from numpy - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - result = Index([("a", "b"), ("b", "c"), ("c", "a")]) == ("c", "a") + result = Index([("a", "b"), ("b", "c"), ("c", "a")]) == ("c", "a") expected = np.array([False, False, False]) tm.assert_numpy_array_equal(result, expected) From d9f78487123ecb334227aff4134ad024546ba551 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Thu, 14 May 2020 19:36:35 +0200 Subject: [PATCH 10/12] filter warning --- pandas/tests/indexes/test_base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 470512e0d4fe8..32b6259903f09 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -4,6 +4,7 @@ import math import operator import re +from distutils.version import LooseVersion import numpy as np import pytest @@ -2423,6 +2424,7 @@ def test_index_repr_bool_nan(self): out2 = "Index([True, False, nan], dtype='object')" assert out2 == exp2 + @pytest.mark.filterwarnings("ignore:elementwise comparison failed:FutureWarning") def test_index_with_tuple_bool(self): # GH34123 # TODO: the result seems wrong to me, should be [False, False, True] From 040c3c17db08bc47ffde349f774a6589aa6510e5 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Thu, 14 May 2020 21:12:55 +0200 Subject: [PATCH 11/12] remove unused import --- pandas/tests/indexes/test_base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 32b6259903f09..ba130f6a5e2ce 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -4,7 +4,6 @@ import math import operator import re -from distutils.version import LooseVersion import numpy as np import pytest From 40b900e78d63a3ad5f5981f7c328d01f04bfcfd7 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Thu, 14 May 2020 21:39:30 +0200 Subject: [PATCH 12/12] restore correct behaviour --- pandas/tests/indexes/test_base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index ba130f6a5e2ce..466b491eb7a2c 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -2426,10 +2426,11 @@ def test_index_repr_bool_nan(self): @pytest.mark.filterwarnings("ignore:elementwise comparison failed:FutureWarning") def test_index_with_tuple_bool(self): # GH34123 - # TODO: the result seems wrong to me, should be [False, False, True] + # TODO: remove tupleize_cols=False once correct behaviour is restored # TODO: also this op right now produces FutureWarning from numpy - result = Index([("a", "b"), ("b", "c"), ("c", "a")]) == ("c", "a") - expected = np.array([False, False, False]) + idx = Index([("a", "b"), ("b", "c"), ("c", "a")], tupleize_cols=False) + result = idx == ("c", "a",) + expected = np.array([False, False, True]) tm.assert_numpy_array_equal(result, expected)