Skip to content

TYP/REF: use _cmp_method in EAs #36954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 33 additions & 41 deletions pandas/core/arrays/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pandas.core.dtypes.missing import isna

from pandas.core import ops
from pandas.core.arraylike import OpsMixin

from .masked import BaseMaskedArray, BaseMaskedDtype

Expand Down Expand Up @@ -202,7 +203,7 @@ def coerce_to_array(
return values, mask


class BooleanArray(BaseMaskedArray):
class BooleanArray(OpsMixin, BaseMaskedArray):
"""
Array of boolean (True/False) data with missing values.

Expand Down Expand Up @@ -603,52 +604,44 @@ def logical_method(self, other):
name = f"__{op.__name__}__"
return set_function_name(logical_method, name, cls)

@classmethod
def _create_comparison_method(cls, op):
@ops.unpack_zerodim_and_defer(op.__name__)
def cmp_method(self, other):
from pandas.arrays import FloatingArray, IntegerArray
def _cmp_method(self, other, op):
from pandas.arrays import FloatingArray, IntegerArray

if isinstance(other, (IntegerArray, FloatingArray)):
return NotImplemented
if isinstance(other, (IntegerArray, FloatingArray)):
return NotImplemented

mask = None
mask = None

if isinstance(other, BooleanArray):
other, mask = other._data, other._mask
if isinstance(other, BooleanArray):
other, mask = other._data, other._mask

elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
raise NotImplementedError(
"can only perform ops with 1-d structures"
)
if len(self) != len(other):
raise ValueError("Lengths must match to compare")
elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
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
# a scalar False instead of an array)
result = np.zeros_like(self._data)
mask = np.ones_like(self._data)
else:
# numpy will show a DeprecationWarning on invalid elementwise
# comparisons, this will raise in the future
with warnings.catch_warnings():
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
result = op(self._data, other)

# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask
if other is libmissing.NA:
# numpy does not handle pd.NA well as "other" scalar (it returns
# a scalar False instead of an array)
result = np.zeros_like(self._data)
mask = np.ones_like(self._data)
else:
# numpy will show a DeprecationWarning on invalid elementwise
# comparisons, this will raise in the future
with warnings.catch_warnings():
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
result = op(self._data, other)

return BooleanArray(result, mask, copy=False)
# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask

name = f"__{op.__name__}"
return set_function_name(cmp_method, name, cls)
return BooleanArray(result, mask, copy=False)

def _reduce(self, name: str, skipna: bool = True, **kwargs):

Expand Down Expand Up @@ -741,5 +734,4 @@ def boolean_arithmetic_method(self, other):


BooleanArray._add_logical_ops()
BooleanArray._add_comparison_ops()
BooleanArray._add_arithmetic_ops()
84 changes: 37 additions & 47 deletions pandas/core/arrays/floating.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from pandas.core.dtypes.missing import isna

from pandas.core import ops
from pandas.core.arraylike import OpsMixin
from pandas.core.ops import invalid_comparison
from pandas.core.ops.common import unpack_zerodim_and_defer
from pandas.core.tools.numeric import to_numeric
Expand Down Expand Up @@ -201,7 +202,7 @@ def coerce_to_array(
return values, mask


class FloatingArray(BaseMaskedArray):
class FloatingArray(OpsMixin, BaseMaskedArray):
"""
Array of floating (optional missing) values.

Expand Down Expand Up @@ -398,58 +399,48 @@ def astype(self, dtype, copy: bool = True) -> ArrayLike:
def _values_for_argsort(self) -> np.ndarray:
return self._data

@classmethod
def _create_comparison_method(cls, op):
op_name = op.__name__
def _cmp_method(self, other, op):
from pandas.arrays import BooleanArray, IntegerArray

@unpack_zerodim_and_defer(op.__name__)
def cmp_method(self, other):
from pandas.arrays import BooleanArray, IntegerArray
mask = None

mask = None
if isinstance(other, (BooleanArray, IntegerArray, FloatingArray)):
other, mask = other._data, other._mask

if isinstance(other, (BooleanArray, IntegerArray, FloatingArray)):
other, mask = other._data, other._mask
elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
raise NotImplementedError("can only perform ops with 1-d structures")

elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
raise NotImplementedError(
"can only perform ops with 1-d structures"
)
if other is libmissing.NA:
# numpy does not handle pd.NA well as "other" scalar (it returns
# a scalar False instead of an array)
# This may be fixed by NA.__array_ufunc__. Revisit this check
# once that's implemented.
result = np.zeros(self._data.shape, dtype="bool")
mask = np.ones(self._data.shape, dtype="bool")
else:
with warnings.catch_warnings():
# numpy may show a FutureWarning:
# elementwise comparison failed; returning scalar instead,
# but in the future will perform elementwise comparison
# before returning NotImplemented. We fall back to the correct
# behavior today, so that should be fine to ignore.
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
method = getattr(self._data, f"__{op.__name__}__")
result = method(other)

if other is libmissing.NA:
# numpy does not handle pd.NA well as "other" scalar (it returns
# a scalar False instead of an array)
# This may be fixed by NA.__array_ufunc__. Revisit this check
# once that's implemented.
result = np.zeros(self._data.shape, dtype="bool")
mask = np.ones(self._data.shape, dtype="bool")
else:
with warnings.catch_warnings():
# numpy may show a FutureWarning:
# elementwise comparison failed; returning scalar instead,
# but in the future will perform elementwise comparison
# before returning NotImplemented. We fall back to the correct
# behavior today, so that should be fine to ignore.
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
method = getattr(self._data, f"__{op_name}__")
result = method(other)

if result is NotImplemented:
result = invalid_comparison(self._data, other, op)

# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask
if result is NotImplemented:
result = invalid_comparison(self._data, other, op)

return BooleanArray(result, mask)
# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask

name = f"__{op.__name__}__"
return set_function_name(cmp_method, name, cls)
return BooleanArray(result, mask)

def sum(self, skipna=True, min_count=0, **kwargs):
nv.validate_sum((), kwargs)
Expand Down Expand Up @@ -565,7 +556,6 @@ def floating_arithmetic_method(self, other):


FloatingArray._add_arithmetic_ops()
FloatingArray._add_comparison_ops()


_dtype_docstring = """
Expand Down
90 changes: 40 additions & 50 deletions pandas/core/arrays/integer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from pandas.core.dtypes.missing import isna

from pandas.core import ops
from pandas.core.arraylike import OpsMixin
from pandas.core.ops import invalid_comparison
from pandas.core.ops.common import unpack_zerodim_and_defer
from pandas.core.tools.numeric import to_numeric
Expand Down Expand Up @@ -265,7 +266,7 @@ def coerce_to_array(
return values, mask


class IntegerArray(BaseMaskedArray):
class IntegerArray(OpsMixin, BaseMaskedArray):
"""
Array of integer (optional missing) values.

Expand Down Expand Up @@ -493,60 +494,50 @@ def _values_for_argsort(self) -> np.ndarray:
data[self._mask] = data.min() - 1
return data

@classmethod
def _create_comparison_method(cls, op):
op_name = op.__name__
def _cmp_method(self, other, op):
from pandas.core.arrays import BaseMaskedArray, BooleanArray

@unpack_zerodim_and_defer(op.__name__)
def cmp_method(self, other):
from pandas.core.arrays import BaseMaskedArray, BooleanArray
mask = None

mask = None
if isinstance(other, BaseMaskedArray):
other, mask = other._data, other._mask

if isinstance(other, BaseMaskedArray):
other, mask = other._data, other._mask

elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
raise NotImplementedError(
"can only perform ops with 1-d structures"
)
if len(self) != len(other):
raise ValueError("Lengths must match to compare")
elif is_list_like(other):
other = np.asarray(other)
if other.ndim > 1:
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
# a scalar False instead of an array)
# This may be fixed by NA.__array_ufunc__. Revisit this check
# once that's implemented.
result = np.zeros(self._data.shape, dtype="bool")
mask = np.ones(self._data.shape, dtype="bool")
else:
with warnings.catch_warnings():
# numpy may show a FutureWarning:
# elementwise comparison failed; returning scalar instead,
# but in the future will perform elementwise comparison
# before returning NotImplemented. We fall back to the correct
# behavior today, so that should be fine to ignore.
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
method = getattr(self._data, f"__{op.__name__}__")
result = method(other)

if other is libmissing.NA:
# numpy does not handle pd.NA well as "other" scalar (it returns
# a scalar False instead of an array)
# This may be fixed by NA.__array_ufunc__. Revisit this check
# once that's implemented.
result = np.zeros(self._data.shape, dtype="bool")
mask = np.ones(self._data.shape, dtype="bool")
else:
with warnings.catch_warnings():
# numpy may show a FutureWarning:
# elementwise comparison failed; returning scalar instead,
# but in the future will perform elementwise comparison
# before returning NotImplemented. We fall back to the correct
# behavior today, so that should be fine to ignore.
warnings.filterwarnings("ignore", "elementwise", FutureWarning)
with np.errstate(all="ignore"):
method = getattr(self._data, f"__{op_name}__")
result = method(other)

if result is NotImplemented:
result = invalid_comparison(self._data, other, op)

# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask
if result is NotImplemented:
result = invalid_comparison(self._data, other, op)

return BooleanArray(result, mask)
# nans propagate
if mask is None:
mask = self._mask.copy()
else:
mask = self._mask | mask

name = f"__{op.__name__}__"
return set_function_name(cmp_method, name, cls)
return BooleanArray(result, mask)

def sum(self, skipna=True, min_count=0, **kwargs):
nv.validate_sum((), kwargs)
Expand Down Expand Up @@ -669,7 +660,6 @@ def integer_arithmetic_method(self, other):


IntegerArray._add_arithmetic_ops()
IntegerArray._add_comparison_ops()


_dtype_docstring = """
Expand Down
Loading