From c2a91c1f27d89832f259a12aead5721130bc842e Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 14:19:46 -0700 Subject: [PATCH 1/6] use op instead of opname --- pandas/core/arrays/categorical.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 13058882084ff..a0fa1b5ff6d92 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -1,3 +1,4 @@ +import operator from shutil import get_terminal_size import textwrap from typing import Type, Union, cast @@ -77,7 +78,9 @@ ) -def _cat_compare_op(opname): +def _cat_compare_op(op): + opname = "__{op}__".format(op=op.__name__) + def f(self, other): # On python2, you can usually compare any type to any type, and # Categoricals can be seen as a custom type, but having different @@ -1240,12 +1243,12 @@ def map(self, mapper): new_categories = new_categories.insert(len(new_categories), np.nan) return np.take(new_categories, self._codes) - __eq__ = _cat_compare_op("__eq__") - __ne__ = _cat_compare_op("__ne__") - __lt__ = _cat_compare_op("__lt__") - __gt__ = _cat_compare_op("__gt__") - __le__ = _cat_compare_op("__le__") - __ge__ = _cat_compare_op("__ge__") + __eq__ = _cat_compare_op(operator.eq) + __ne__ = _cat_compare_op(operator.ne) + __lt__ = _cat_compare_op(operator.lt) + __gt__ = _cat_compare_op(operator.gt) + __le__ = _cat_compare_op(operator.le) + __ge__ = _cat_compare_op(operator.ge) # for Series/ndarray like compat @property From 473560eaf8f55383ad8f876338b9329b4faa79f5 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 15:50:16 -0700 Subject: [PATCH 2/6] PERF: simplify checks --- pandas/core/arrays/datetimelike.py | 45 ++++++------------------------ 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 0372b8f0c080a..1988726edc79b 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -22,7 +22,6 @@ is_datetime64tz_dtype, is_datetime_or_timedelta_dtype, is_dtype_equal, - is_extension_array_dtype, is_float_dtype, is_integer_dtype, is_list_like, @@ -1230,29 +1229,17 @@ def __add__(self, other): if not is_period_dtype(self): maybe_integer_op_deprecated(self) result = self._addsub_int_array(other, operator.add) - elif is_float_dtype(other): - # Explicitly catch invalid dtypes - raise TypeError( - "cannot add {dtype}-dtype to {cls}".format( - dtype=other.dtype, cls=type(self).__name__ - ) - ) - elif is_period_dtype(other): - # if self is a TimedeltaArray and other is a PeriodArray with - # a timedelta-like (i.e. Tick) freq, this operation is valid. - # Defer to the PeriodArray implementation. - # In remaining cases, this will end up raising TypeError. - return NotImplemented - elif is_extension_array_dtype(other): - # Categorical op will raise; defer explicitly - return NotImplemented - else: # pragma: no cover + else: + # Includes Categorical, other ExtensionArrays + # For PeriodDtype, if self is a TimedeltaArray and other is a + # PeriodArray with a timedelta-like (i.e. Tick) freq, this + # operation is valid. Defer to the PeriodArray implementation. + # In remaining cases, this will end up raising TypeError. return NotImplemented if is_timedelta64_dtype(result) and isinstance(result, np.ndarray): from pandas.core.arrays import TimedeltaArray - # TODO: infer freq? return TimedeltaArray(result) return result @@ -1302,29 +1289,13 @@ def __sub__(self, other): if not is_period_dtype(self): maybe_integer_op_deprecated(self) result = self._addsub_int_array(other, operator.sub) - elif isinstance(other, ABCIndexClass): - raise TypeError( - "cannot subtract {cls} and {typ}".format( - cls=type(self).__name__, typ=type(other).__name__ - ) - ) - elif is_float_dtype(other): - # Explicitly catch invalid dtypes - raise TypeError( - "cannot subtract {dtype}-dtype from {cls}".format( - dtype=other.dtype, cls=type(self).__name__ - ) - ) - elif is_extension_array_dtype(other): - # Categorical op will raise; defer explicitly - return NotImplemented - else: # pragma: no cover + else: + # Includes ExtensionArrays, float_dtype return NotImplemented if is_timedelta64_dtype(result) and isinstance(result, np.ndarray): from pandas.core.arrays import TimedeltaArray - # TODO: infer freq? return TimedeltaArray(result) return result From 4c34a5165f6509ba1243a2a4b788cd28c4791319 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 15:52:14 -0700 Subject: [PATCH 3/6] CLN: remove unnecessary cast --- pandas/core/arrays/datetimes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 28537124536e7..1aad130d9a3f5 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -223,8 +223,6 @@ def wrapper(self, other): result = op(self.view("i8"), other.view("i8")) o_mask = other._isnan - result = com.values_from_object(result) - if o_mask.any(): result[o_mask] = nat_result From 8614873ed4e676394bb247baef1dcbd49b1f7c40 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 19:14:01 -0700 Subject: [PATCH 4/6] update error message --- pandas/tests/arithmetic/test_datetime64.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 3920cfcc002d7..741ad10ac9493 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -1097,7 +1097,13 @@ def test_dt64arr_add_timestamp_raises(self, box_with_array): def test_dt64arr_add_sub_float(self, other, box_with_array): dti = DatetimeIndex(["2011-01-01", "2011-01-02"], freq="D") dtarr = tm.box_expected(dti, box_with_array) - msg = "|".join(["unsupported operand type", "cannot (add|subtract)"]) + msg = "|".join( + [ + "unsupported operand type", + "cannot (add|subtract)", + "ufunc '(add|subtract)' cannot use operands with types", + ] + ) with pytest.raises(TypeError, match=msg): dtarr + other with pytest.raises(TypeError, match=msg): From 53620d5da3d25b75cb9b41e20915d3b7e5268c01 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 20:40:25 -0700 Subject: [PATCH 5/6] err message compat --- pandas/tests/arithmetic/test_datetime64.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 741ad10ac9493..1fb93a182ba0b 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -1101,7 +1101,7 @@ def test_dt64arr_add_sub_float(self, other, box_with_array): [ "unsupported operand type", "cannot (add|subtract)", - "ufunc '(add|subtract)' cannot use operands with types", + "ufunc '?(add|subtract)'? cannot use operands with types", ] ) with pytest.raises(TypeError, match=msg): From 0cd6b2a42e222b0510e3c487a7235011439f754e Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Aug 2019 21:22:40 -0700 Subject: [PATCH 6/6] dummy to force CI