-
-
Notifications
You must be signed in to change notification settings - Fork 18.5k
TYP: define Index.any, Index.all non-dynamically #36929
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
Changes from all commits
fb7ee4c
c5d1b6b
fedb8f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ | |
from datetime import datetime | ||
from itertools import zip_longest | ||
import operator | ||
from textwrap import dedent | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Any, | ||
|
@@ -30,7 +29,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 ( | ||
|
@@ -61,6 +60,7 @@ | |
is_signed_integer_dtype, | ||
is_timedelta64_dtype, | ||
is_unsigned_integer_dtype, | ||
needs_i8_conversion, | ||
pandas_dtype, | ||
validate_all_hashable, | ||
) | ||
|
@@ -5447,28 +5447,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 | ||
-------- | ||
|
@@ -5507,65 +5540,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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could this be done on the subclasses. more repetitive but would be easier to follow I think. although, does disabling on subclasses obey LSP? maybe a mixin that classes can opt into, to ensure that the base class or other code does not rely on any/all being available. This would mean a base class for Index, to allow any/all on object Indexes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ATM we disable on subclasses (though by calling I don't think it's that big a deal because I expect to change it before long since, as mentioned in the OP, i think several of the currently-disabled methods should be enabled. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm OK with perhaps revisiting after some of the currently-disabled methods are enabled. |
||
|
||
@property | ||
def shape(self): | ||
|
@@ -5579,7 +5571,6 @@ def shape(self): | |
|
||
|
||
Index._add_numeric_methods() | ||
Index._add_logical_methods() | ||
|
||
|
||
def ensure_index_from_sequences(sequences, names=None): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have a numpy validation routine for this and for all? eg. https://github.com/pandas-dev/pandas/blob/master/pandas/compat/numpy/function.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no