From fb7ee4ce521077e087ec07ed3393a03ac4f4f74a Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 6 Oct 2020 16:42:00 -0700 Subject: [PATCH] TYP: define Index.any, Index.all non-dynamically --- pandas/core/indexes/base.py | 131 ++++++++++++++---------------- pandas/core/indexes/category.py | 3 - pandas/core/indexes/datetimes.py | 3 - pandas/core/indexes/interval.py | 3 - pandas/core/indexes/multi.py | 1 - pandas/core/indexes/numeric.py | 3 - pandas/core/indexes/period.py | 3 - pandas/core/indexes/range.py | 4 +- pandas/core/indexes/timedeltas.py | 3 - 9 files changed, 63 insertions(+), 91 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 4967e13a9855a..d87b5c40b36fd 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1,7 +1,6 @@ from copy import copy as copy_func from datetime import datetime import operator -from textwrap import dedent from typing import ( TYPE_CHECKING, Any, @@ -28,7 +27,7 @@ from pandas.compat import set_function_name from pandas.compat.numpy import function as nv from pandas.errors import DuplicateLabelError, InvalidIndexError -from pandas.util._decorators import Appender, Substitution, cache_readonly, doc +from pandas.util._decorators import Appender, cache_readonly, doc from pandas.core.dtypes import concat as _concat from pandas.core.dtypes.cast import ( @@ -59,6 +58,7 @@ is_signed_integer_dtype, is_timedelta64_dtype, is_unsigned_integer_dtype, + needs_i8_conversion, pandas_dtype, validate_all_hashable, ) @@ -5456,28 +5456,61 @@ def _add_numeric_methods(cls): cls._add_numeric_methods_unary() cls._add_numeric_methods_binary() - @classmethod - def _add_logical_methods(cls): - """ - Add in logical methods. + def any(self, *args, **kwargs): """ - _doc = """ - %(desc)s + Return whether any element is Truthy. Parameters ---------- *args - These parameters will be passed to numpy.%(outname)s. + These parameters will be passed to numpy.any. **kwargs - These parameters will be passed to numpy.%(outname)s. + These parameters will be passed to numpy.any. Returns ------- - %(outname)s : bool or array_like (if axis is specified) - A single element array_like may be converted to bool.""" + any : bool or array_like (if axis is specified) + A single element array_like may be converted to bool. - _index_shared_docs["index_all"] = dedent( - """ + See Also + -------- + Index.all : Return whether all elements are True. + Series.all : Return whether all elements are True. + + Notes + ----- + Not a Number (NaN), positive infinity and negative infinity + evaluate to True because these are not equal to zero. + + Examples + -------- + >>> index = pd.Index([0, 1, 2]) + >>> index.any() + True + + >>> index = pd.Index([0, 0, 0]) + >>> index.any() + False + """ + # FIXME: docstr inaccurate, args/kwargs not passed + self._maybe_disable_logical_methods("any") + return np.any(self.values) + + def all(self): + """ + Return whether all elements are Truthy. + + Parameters + ---------- + *args + These parameters will be passed to numpy.all. + **kwargs + These parameters will be passed to numpy.all. + + Returns + ------- + all : bool or array_like (if axis is specified) + A single element array_like may be converted to bool. See Also -------- @@ -5516,65 +5549,24 @@ def _add_logical_methods(cls): >>> pd.Index([0, 0, 0]).any() False """ - ) - - _index_shared_docs["index_any"] = dedent( - """ - - See Also - -------- - Index.all : Return whether all elements are True. - Series.all : Return whether all elements are True. + # FIXME: docstr inaccurate, args/kwargs not passed - Notes - ----- - Not a Number (NaN), positive infinity and negative infinity - evaluate to True because these are not equal to zero. + self._maybe_disable_logical_methods("all") + return np.all(self.values) - Examples - -------- - >>> index = pd.Index([0, 1, 2]) - >>> index.any() - True - - >>> index = pd.Index([0, 0, 0]) - >>> index.any() - False + def _maybe_disable_logical_methods(self, opname: str_t): """ - ) - - def _make_logical_function(name: str_t, desc: str_t, f): - @Substitution(outname=name, desc=desc) - @Appender(_index_shared_docs["index_" + name]) - @Appender(_doc) - def logical_func(self, *args, **kwargs): - result = f(self.values) - if ( - isinstance(result, (np.ndarray, ABCSeries, Index)) - and result.ndim == 0 - ): - # return NumPy type - return result.dtype.type(result.item()) - else: # pragma: no cover - return result - - logical_func.__name__ = name - return logical_func - - cls.all = _make_logical_function( - "all", "Return whether all elements are True.", np.all - ) - cls.any = _make_logical_function( - "any", "Return whether any element is True.", np.any - ) - - @classmethod - def _add_logical_methods_disabled(cls): + raise if this Index subclass does not support any or all. """ - Add in logical methods to disable. - """ - cls.all = make_invalid_op("all") - cls.any = make_invalid_op("any") + if ( + isinstance(self, ABCMultiIndex) + or needs_i8_conversion(self.dtype) + or is_interval_dtype(self.dtype) + or is_categorical_dtype(self.dtype) + or is_float_dtype(self.dtype) + ): + # This call will raise + make_invalid_op(opname)(self) @property def shape(self): @@ -5588,7 +5580,6 @@ def shape(self): Index._add_numeric_methods() -Index._add_logical_methods() Index._add_comparison_methods() diff --git a/pandas/core/indexes/category.py b/pandas/core/indexes/category.py index d3167189dbcc6..8038bc6bf1c72 100644 --- a/pandas/core/indexes/category.py +++ b/pandas/core/indexes/category.py @@ -721,6 +721,3 @@ def _wrap_joined_index( name = get_op_result_name(self, other) cat = self._data._from_backing_data(joined) return type(self)._simple_new(cat, name=name) - - -CategoricalIndex._add_logical_methods_disabled() diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 06405995f7685..6bfdf134576bf 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -867,9 +867,6 @@ def indexer_between_time( return mask.nonzero()[0] -DatetimeIndex._add_logical_methods_disabled() - - def date_range( start=None, end=None, diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 4a877621a94c2..b345d0d77bb0a 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -1129,9 +1129,6 @@ def __ge__(self, other): return Index.__ge__(self, other) -IntervalIndex._add_logical_methods_disabled() - - def _is_valid_endpoint(endpoint) -> bool: """ Helper for interval_range to check if start/end are valid types. diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index a157fdfdde447..6b4414c9c8396 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -3717,7 +3717,6 @@ def _add_numeric_methods_disabled(cls): MultiIndex._add_numeric_methods_disabled() MultiIndex._add_numeric_methods_add_sub_disabled() -MultiIndex._add_logical_methods_disabled() def sparsify_labels(label_list, start: int = 0, sentinel=""): diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index 34bbaca06cc08..60a206a5344de 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -276,7 +276,6 @@ def _can_union_without_object_cast(self, other) -> bool: Int64Index._add_numeric_methods() -Int64Index._add_logical_methods() _uint64_descr_args = dict( klass="UInt64Index", ltype="unsigned integer", dtype="uint64", extra="" @@ -323,7 +322,6 @@ def _can_union_without_object_cast(self, other) -> bool: UInt64Index._add_numeric_methods() -UInt64Index._add_logical_methods() _float64_descr_args = dict( klass="Float64Index", dtype="float64", ltype="float", extra="" @@ -430,4 +428,3 @@ def _can_union_without_object_cast(self, other) -> bool: Float64Index._add_numeric_methods() -Float64Index._add_logical_methods_disabled() diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index adf7a75b33b38..ce2839ab9a8e1 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -719,9 +719,6 @@ def memory_usage(self, deep: bool = False) -> int: return result -PeriodIndex._add_logical_methods_disabled() - - def period_range( start=None, end=None, periods=None, freq=None, name=None ) -> PeriodIndex: diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index d5d9a9b5bc0a3..d68213c07a5a1 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -746,10 +746,10 @@ def __floordiv__(self, other): return self._simple_new(new_range, name=self.name) return self._int64index // other - def all(self) -> bool: + def all(self, *args, **kwargs) -> bool: return 0 not in self._range - def any(self) -> bool: + def any(self, *args, **kwargs) -> bool: return any(self._range) @classmethod diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 2a7c624b430ed..302fead8c8b0c 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -261,9 +261,6 @@ def inferred_type(self) -> str: return "timedelta64" -TimedeltaIndex._add_logical_methods_disabled() - - def timedelta_range( start=None, end=None, periods=None, freq=None, name=None, closed=None ) -> TimedeltaIndex: