From 25225ae5520ddc49109871c7aad9a55406724865 Mon Sep 17 00:00:00 2001 From: tp Date: Tue, 23 Oct 2018 14:30:52 +0100 Subject: [PATCH 1/2] make hasnans always return python booleans --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/core/arrays/datetimelike.py | 2 +- pandas/core/indexes/base.py | 2 +- pandas/tests/indexes/common.py | 8 ++++---- pandas/tests/indexes/datetimes/test_ops.py | 4 ++-- pandas/tests/indexes/interval/test_interval.py | 4 ++-- pandas/tests/indexes/multi/test_missing.py | 6 +++--- pandas/tests/indexes/period/test_ops.py | 4 ++-- pandas/tests/indexes/timedeltas/test_ops.py | 4 ++-- pandas/tests/series/test_internals.py | 6 +++--- 10 files changed, 21 insertions(+), 20 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 768868d585721..b0ceb5f6f6670 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -910,6 +910,7 @@ Other API Changes has an improved ``KeyError`` message, and will not fail on duplicate column names with ``drop=True``. (:issue:`22484`) - Slicing a single row of a DataFrame with multiple ExtensionArrays of the same type now preserves the dtype, rather than coercing to object (:issue:`22784`) - :class:`DateOffset` attribute `_cacheable` and method `_should_cache` have been removed (:issue:`23118`) +- :meth:`Index.hasnans` now always returns a python boolean. Previously, it could return a python or a numpy boolean, depending on circumstances (:issue:`23294`). .. _whatsnew_0240.deprecations: diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 943c8a94e1e6a..28fe6471efb73 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -219,7 +219,7 @@ def _isnan(self): @property # NB: override with cache_readonly in immutable subclasses def hasnans(self): """ return if I have any nans; enables various perf speedups """ - return self._isnan.any() + return bool(self._isnan.any()) def _maybe_mask_results(self, result, fill_value=None, convert=None): """ diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index e9b0b087179c9..a9edad1fa2e01 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -2221,7 +2221,7 @@ def _nan_idxs(self): def hasnans(self): """ return if I have any nans; enables various perf speedups """ if self._can_hold_na: - return self._isnan.any() + return bool(self._isnan.any()) else: return False diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index dc936af04e045..e8eaca2b61dd7 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -417,7 +417,7 @@ def test_get_unique_index(self, indices): # and doesn't contain nans. assert idx_unique.is_unique is True try: - assert not idx_unique.hasnans + assert idx_unique.hasnans is False except NotImplementedError: pass @@ -916,7 +916,7 @@ def test_hasnans_isnans(self): # cases in indices doesn't include NaN expected = np.array([False] * len(idx), dtype=bool) tm.assert_numpy_array_equal(idx._isnan, expected) - assert not idx.hasnans + assert idx.hasnans is False idx = index.copy() values = np.asarray(idx.values) @@ -938,7 +938,7 @@ def test_hasnans_isnans(self): expected = np.array([False] * len(idx), dtype=bool) expected[1] = True tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans + assert idx.hasnans is True def test_fillna(self): # GH 11343 @@ -978,7 +978,7 @@ def test_fillna(self): expected = np.array([False] * len(idx), dtype=bool) expected[1] = True tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans + assert idx.hasnans is True def test_nulls(self): # this is really a smoke test for the methods diff --git a/pandas/tests/indexes/datetimes/test_ops.py b/pandas/tests/indexes/datetimes/test_ops.py index 9ce77326d37b7..ad44ceab36bc3 100644 --- a/pandas/tests/indexes/datetimes/test_ops.py +++ b/pandas/tests/indexes/datetimes/test_ops.py @@ -356,7 +356,7 @@ def test_nat(self, tz_naive_fixture): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, False])) - assert not idx.hasnans + assert idx.hasnans is False tm.assert_numpy_array_equal(idx._nan_idxs, np.array([], dtype=np.intp)) @@ -364,7 +364,7 @@ def test_nat(self, tz_naive_fixture): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, True])) - assert idx.hasnans + assert idx.hasnans is True tm.assert_numpy_array_equal(idx._nan_idxs, np.array([1], dtype=np.intp)) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index f33106e61662f..f6ed658251dc7 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -93,7 +93,7 @@ def test_length(self, closed, breaks): def test_with_nans(self, closed): index = self.create_index(closed=closed) - assert not index.hasnans + assert index.hasnans is False result = index.isna() expected = np.repeat(False, len(index)) @@ -104,7 +104,7 @@ def test_with_nans(self, closed): tm.assert_numpy_array_equal(result, expected) index = self.create_index_with_nan(closed=closed) - assert index.hasnans + assert index.hasnans is True result = index.isna() expected = np.array([False, True] + [False] * (len(index) - 2)) diff --git a/pandas/tests/indexes/multi/test_missing.py b/pandas/tests/indexes/multi/test_missing.py index bedacf84f4f9a..82c486caf2631 100644 --- a/pandas/tests/indexes/multi/test_missing.py +++ b/pandas/tests/indexes/multi/test_missing.py @@ -49,7 +49,7 @@ def test_fillna(idx): expected = np.array([False] * len(idx), dtype=bool) expected[1] = True tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans + assert idx.hasnans is True def test_dropna(): @@ -91,7 +91,7 @@ def test_hasnans_isnans(idx): # cases in indices doesn't include NaN expected = np.array([False] * len(index), dtype=bool) tm.assert_numpy_array_equal(index._isnan, expected) - assert not index.hasnans + assert index.hasnans is False index = idx.copy() values = index.values @@ -102,7 +102,7 @@ def test_hasnans_isnans(idx): expected = np.array([False] * len(index), dtype=bool) expected[1] = True tm.assert_numpy_array_equal(index._isnan, expected) - assert index.hasnans + assert index.hasnans is True def test_nan_stays_float(): diff --git a/pandas/tests/indexes/period/test_ops.py b/pandas/tests/indexes/period/test_ops.py index 33858a28ec81b..276c919dd1d12 100644 --- a/pandas/tests/indexes/period/test_ops.py +++ b/pandas/tests/indexes/period/test_ops.py @@ -356,7 +356,7 @@ def test_nat(self): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, False])) - assert not idx.hasnans + assert idx.hasnans is False tm.assert_numpy_array_equal(idx._nan_idxs, np.array([], dtype=np.intp)) @@ -364,7 +364,7 @@ def test_nat(self): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, True])) - assert idx.hasnans + assert idx.hasnans is True tm.assert_numpy_array_equal(idx._nan_idxs, np.array([1], dtype=np.intp)) diff --git a/pandas/tests/indexes/timedeltas/test_ops.py b/pandas/tests/indexes/timedeltas/test_ops.py index 9f8a3e893c3de..4b8c37cceb444 100644 --- a/pandas/tests/indexes/timedeltas/test_ops.py +++ b/pandas/tests/indexes/timedeltas/test_ops.py @@ -273,7 +273,7 @@ def test_nat(self): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, False])) - assert not idx.hasnans + assert idx.hasnans is False tm.assert_numpy_array_equal(idx._nan_idxs, np.array([], dtype=np.intp)) @@ -281,7 +281,7 @@ def test_nat(self): assert idx._can_hold_na tm.assert_numpy_array_equal(idx._isnan, np.array([False, True])) - assert idx.hasnans + assert idx.hasnans is True tm.assert_numpy_array_equal(idx._nan_idxs, np.array([1], dtype=np.intp)) diff --git a/pandas/tests/series/test_internals.py b/pandas/tests/series/test_internals.py index 506e7e14ffc4f..882755f6a71c0 100644 --- a/pandas/tests/series/test_internals.py +++ b/pandas/tests/series/test_internals.py @@ -315,11 +315,11 @@ def test_convert_preserve_all_bool(self): def test_hasnans_unchached_for_series(): # GH#19700 idx = pd.Index([0, 1]) - assert not idx.hasnans + assert idx.hasnans is False assert 'hasnans' in idx._cache ser = idx.to_series() - assert not ser.hasnans + assert ser.hasnans is False assert not hasattr(ser, '_cache') ser.iloc[-1] = np.nan - assert ser.hasnans + assert ser.hasnans is True assert pd.Series.hasnans.__doc__ == pd.Index.hasnans.__doc__ From 031e5f7ecb41bd1c030b2c2f42c9994da501b681 Mon Sep 17 00:00:00 2001 From: tp Date: Fri, 26 Oct 2018 18:47:20 +0100 Subject: [PATCH 2/2] make Series.hasnans return python bool --- doc/source/whatsnew/v0.24.0.txt | 2 +- pandas/core/base.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index b0ceb5f6f6670..9a781eda0e397 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -910,7 +910,7 @@ Other API Changes has an improved ``KeyError`` message, and will not fail on duplicate column names with ``drop=True``. (:issue:`22484`) - Slicing a single row of a DataFrame with multiple ExtensionArrays of the same type now preserves the dtype, rather than coercing to object (:issue:`22784`) - :class:`DateOffset` attribute `_cacheable` and method `_should_cache` have been removed (:issue:`23118`) -- :meth:`Index.hasnans` now always returns a python boolean. Previously, it could return a python or a numpy boolean, depending on circumstances (:issue:`23294`). +- :meth:`Index.hasnans` and :meth:`Series.hasnans` now always return a python boolean. Previously, a python or a numpy boolean could be returned, depending on circumstances (:issue:`23294`). .. _whatsnew_0240.deprecations: diff --git a/pandas/core/base.py b/pandas/core/base.py index 91ae8375c233a..88a36b0ecc7c7 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -889,7 +889,7 @@ def __iter__(self): @cache_readonly def hasnans(self): """ return if I have any nans; enables various perf speedups """ - return isna(self).any() + return bool(isna(self).any()) def _reduce(self, op, name, axis=0, skipna=True, numeric_only=None, filter_type=None, **kwds):