From 8a967d2d14456b651e4bc46f2c089279b5cda829 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 20 Jun 2019 08:55:48 -0500 Subject: [PATCH 1/3] Surface NumPy FutureWarning about comparisons Closes https://github.com/pandas-dev/pandas/issues/22698 Specifically, see https://github.com/pandas-dev/pandas/issues/22698#issuecomment-458968300 --- pandas/core/indexes/base.py | 9 ++------- pandas/tests/indexes/test_numpy_compat.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 68faa3eb3e883..73abd708415a1 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -76,13 +76,8 @@ def cmp_method(self, other): result = ops._comp_method_OBJECT_ARRAY(op, self.values, other) else: - - # numpy will show a DeprecationWarning on invalid elementwise - # comparisons, this will raise in the future - with warnings.catch_warnings(record=True): - warnings.filterwarnings("ignore", "elementwise", FutureWarning) - with np.errstate(all='ignore'): - result = op(self.values, np.asarray(other)) + with np.errstate(all='ignore'): + result = op(self.values, np.asarray(other)) # technically we could support bool dtyped Index # for now just return the indexing array directly diff --git a/pandas/tests/indexes/test_numpy_compat.py b/pandas/tests/indexes/test_numpy_compat.py index 460faaaf092ec..349d10f5079e8 100644 --- a/pandas/tests/indexes/test_numpy_compat.py +++ b/pandas/tests/indexes/test_numpy_compat.py @@ -80,3 +80,16 @@ def test_numpy_ufuncs_other(indices, func): else: with pytest.raises(Exception): func(idx) + + +def test_elementwise_comparison_warning(): + # https://github.com/pandas-dev/pandas/issues/22698#issuecomment-458968300 + # np.array([1, 2]) == 'a' returns False, and produces a + # FutureWarning that it'll be [False, False] in the future. + # We just want to ensure that comes through. + # When NumPy dev actually enforces this change, we'll need to skip + # this test. + idx = Index([1, 2]) + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False): + idx == 'a' From ba5cb55e511ea484bf4a63d4c489767e5bed87a2 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 20 Jun 2019 13:50:41 -0500 Subject: [PATCH 2/3] 32-bit compat --- pandas/tests/series/test_ufunc.py | 186 ++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 pandas/tests/series/test_ufunc.py diff --git a/pandas/tests/series/test_ufunc.py b/pandas/tests/series/test_ufunc.py new file mode 100644 index 0000000000000..5695028a0fad0 --- /dev/null +++ b/pandas/tests/series/test_ufunc.py @@ -0,0 +1,186 @@ +import string + +import numpy as np +import pytest + +import pandas as pd +import pandas.util.testing as tm + +UNARY_UFUNCS = [np.positive, np.floor, np.exp] +BINARY_UFUNCS = [ + np.add, # dunder op + np.logaddexp, +] +SPARSE = [ + pytest.param(True, + marks=pytest.mark.xfail(reason="Series.__array_ufunc__")), + False, +] +SPARSE_IDS = ['sparse', 'dense'] +SHUFFLE = [ + pytest.param(True, marks=pytest.mark.xfail(reason="GH-26945")), + False +] + + +@pytest.fixture +def arrays_for_binary_ufunc(): + """ + A pair of random, length-100 integer-dtype arrays, that are mostly 0. + """ + a1 = np.random.randint(0, 10, 100, dtype='int64') + a2 = np.random.randint(0, 10, 100, dtype='int64') + a1[::3] = 0 + a2[::4] = 0 + return a1, a2 + + +@pytest.mark.parametrize("ufunc", UNARY_UFUNCS) +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +def test_unary_ufunc(ufunc, sparse): + array = np.random.randint(0, 10, 10, dtype='int64') + array[::2] = 0 + if sparse: + array = pd.SparseArray(array, dtype=pd.SparseDtype('int', 0)) + + index = list(string.ascii_letters[:10]) + name = "name" + series = pd.Series(array, index=index, name=name) + + result = ufunc(series) + expected = pd.Series(ufunc(array), index=index, name=name) + tm.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +@pytest.mark.parametrize("shuffle", SHUFFLE) +@pytest.mark.parametrize("box_other", ['series', 'index', 'raw']) +@pytest.mark.parametrize("flip", [True, False], + ids=['flipped', 'straight']) +def test_binary_ufunc(ufunc, sparse, shuffle, box_other, + flip, + arrays_for_binary_ufunc): + # Check the invariant that + # ufunc(Series(a), Series(b)) == Series(ufunc(a, b)) + # with alignment. + a1, a2 = arrays_for_binary_ufunc + if sparse: + a1 = pd.SparseArray(a1, dtype=pd.SparseDtype('int', 0)) + a2 = pd.SparseArray(a2, dtype=pd.SparseDtype('int', 0)) + + name = "name" + s1 = pd.Series(a1, name=name) + if box_other == 'series': + s2 = pd.Series(a2, name=name) + elif box_other == 'index': + # Index should defer to Series + s2 = pd.Index(a2, naame=name) + else: + s2 = a2 + + # handle shufling / alignment + # If boxing -- ufunc(series, series) -- then we don't need to shuffle + # the other array for the expected, since we align. + # If not boxing -- ufunc(series, array) -- then we do need to shuffle + # the other array, since we *dont'* align + idx = np.random.permutation(len(s1)) + if box_other and shuffle: + # ensure we align before applying the ufunc + s2 = s2.take(idx) + elif shuffle: + a2 = a2.take(idx) + + a, b = s1, s2 + c, d = a1, a2 + + if flip: + a, b = b, a + c, d = d, c + + result = ufunc(a, b) + expected = pd.Series(ufunc(c, d), name=name) + if box_other == 'index' and flip: + raise pytest.xfail("Index should defer to Series") + tm.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +@pytest.mark.parametrize("flip", [True, False]) +def test_binary_ufunc_scalar(ufunc, sparse, flip, arrays_for_binary_ufunc): + array, _ = arrays_for_binary_ufunc + if sparse: + array = pd.SparseArray(array) + other = 2 + series = pd.Series(array, name="name") + + a, b = series, other + c, d = array, other + if flip: + c, d = b, c + a, b = b, a + + expected = pd.Series(ufunc(a, b), name="name") + result = pd.Series(ufunc(c, d), name="name") + tm.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("ufunc", [np.divmod]) # any others? +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +@pytest.mark.parametrize("shuffle", SHUFFLE) +@pytest.mark.filterwarnings("ignore:divide by zero:RuntimeWarning") +def test_multiple_ouput_binary_ufuncs(ufunc, sparse, shuffle, + arrays_for_binary_ufunc): + a1, a2 = arrays_for_binary_ufunc + + if sparse: + a1 = pd.SparseArray(a1, dtype=pd.SparseDtype('int', 0)) + a2 = pd.SparseArray(a2, dtype=pd.SparseDtype('int', 0)) + + s1 = pd.Series(a1) + s2 = pd.Series(a2) + + if shuffle: + # ensure we align before applying the ufunc + s2 = s2.sample(frac=1) + + expected = ufunc(a1, a2) + assert isinstance(expected, tuple) + + result = ufunc(s1, s2) + assert isinstance(result, tuple) + tm.assert_series_equal(result[0], pd.Series(expected[0])) + tm.assert_series_equal(result[1], pd.Series(expected[1])) + + +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +def test_multiple_ouput_ufunc(sparse, arrays_for_binary_ufunc): + array, _ = arrays_for_binary_ufunc + + if sparse: + array = pd.SparseArray(array) + + series = pd.Series(array, name="name") + result = np.modf(series) + expected = np.modf(array) + + assert isinstance(result, tuple) + assert isinstance(expected, tuple) + + tm.assert_series_equal(result[0], pd.Series(expected[0], name="name")) + tm.assert_series_equal(result[1], pd.Series(expected[1], name="name")) + + +@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) +@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) +@pytest.mark.xfail(reason="Series.__array_ufunc__") +def test_binary_ufunc_drops_series_name(ufunc, sparse, + arrays_for_binary_ufunc): + # Drop the names when they differ. + a1, a2 = arrays_for_binary_ufunc + s1 = pd.Series(a1, name='a') + s2 = pd.Series(a2, name='b') + + result = ufunc(s1, s2) + assert result.name is None From add926f261c6539b26913980969d73a3a707d8f4 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 20 Jun 2019 13:59:42 -0500 Subject: [PATCH 3/3] Revert "32-bit compat" This reverts commit ba5cb55e511ea484bf4a63d4c489767e5bed87a2. --- pandas/tests/series/test_ufunc.py | 186 ------------------------------ 1 file changed, 186 deletions(-) delete mode 100644 pandas/tests/series/test_ufunc.py diff --git a/pandas/tests/series/test_ufunc.py b/pandas/tests/series/test_ufunc.py deleted file mode 100644 index 5695028a0fad0..0000000000000 --- a/pandas/tests/series/test_ufunc.py +++ /dev/null @@ -1,186 +0,0 @@ -import string - -import numpy as np -import pytest - -import pandas as pd -import pandas.util.testing as tm - -UNARY_UFUNCS = [np.positive, np.floor, np.exp] -BINARY_UFUNCS = [ - np.add, # dunder op - np.logaddexp, -] -SPARSE = [ - pytest.param(True, - marks=pytest.mark.xfail(reason="Series.__array_ufunc__")), - False, -] -SPARSE_IDS = ['sparse', 'dense'] -SHUFFLE = [ - pytest.param(True, marks=pytest.mark.xfail(reason="GH-26945")), - False -] - - -@pytest.fixture -def arrays_for_binary_ufunc(): - """ - A pair of random, length-100 integer-dtype arrays, that are mostly 0. - """ - a1 = np.random.randint(0, 10, 100, dtype='int64') - a2 = np.random.randint(0, 10, 100, dtype='int64') - a1[::3] = 0 - a2[::4] = 0 - return a1, a2 - - -@pytest.mark.parametrize("ufunc", UNARY_UFUNCS) -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -def test_unary_ufunc(ufunc, sparse): - array = np.random.randint(0, 10, 10, dtype='int64') - array[::2] = 0 - if sparse: - array = pd.SparseArray(array, dtype=pd.SparseDtype('int', 0)) - - index = list(string.ascii_letters[:10]) - name = "name" - series = pd.Series(array, index=index, name=name) - - result = ufunc(series) - expected = pd.Series(ufunc(array), index=index, name=name) - tm.assert_series_equal(result, expected) - - -@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -@pytest.mark.parametrize("shuffle", SHUFFLE) -@pytest.mark.parametrize("box_other", ['series', 'index', 'raw']) -@pytest.mark.parametrize("flip", [True, False], - ids=['flipped', 'straight']) -def test_binary_ufunc(ufunc, sparse, shuffle, box_other, - flip, - arrays_for_binary_ufunc): - # Check the invariant that - # ufunc(Series(a), Series(b)) == Series(ufunc(a, b)) - # with alignment. - a1, a2 = arrays_for_binary_ufunc - if sparse: - a1 = pd.SparseArray(a1, dtype=pd.SparseDtype('int', 0)) - a2 = pd.SparseArray(a2, dtype=pd.SparseDtype('int', 0)) - - name = "name" - s1 = pd.Series(a1, name=name) - if box_other == 'series': - s2 = pd.Series(a2, name=name) - elif box_other == 'index': - # Index should defer to Series - s2 = pd.Index(a2, naame=name) - else: - s2 = a2 - - # handle shufling / alignment - # If boxing -- ufunc(series, series) -- then we don't need to shuffle - # the other array for the expected, since we align. - # If not boxing -- ufunc(series, array) -- then we do need to shuffle - # the other array, since we *dont'* align - idx = np.random.permutation(len(s1)) - if box_other and shuffle: - # ensure we align before applying the ufunc - s2 = s2.take(idx) - elif shuffle: - a2 = a2.take(idx) - - a, b = s1, s2 - c, d = a1, a2 - - if flip: - a, b = b, a - c, d = d, c - - result = ufunc(a, b) - expected = pd.Series(ufunc(c, d), name=name) - if box_other == 'index' and flip: - raise pytest.xfail("Index should defer to Series") - tm.assert_series_equal(result, expected) - - -@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -@pytest.mark.parametrize("flip", [True, False]) -def test_binary_ufunc_scalar(ufunc, sparse, flip, arrays_for_binary_ufunc): - array, _ = arrays_for_binary_ufunc - if sparse: - array = pd.SparseArray(array) - other = 2 - series = pd.Series(array, name="name") - - a, b = series, other - c, d = array, other - if flip: - c, d = b, c - a, b = b, a - - expected = pd.Series(ufunc(a, b), name="name") - result = pd.Series(ufunc(c, d), name="name") - tm.assert_series_equal(result, expected) - - -@pytest.mark.parametrize("ufunc", [np.divmod]) # any others? -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -@pytest.mark.parametrize("shuffle", SHUFFLE) -@pytest.mark.filterwarnings("ignore:divide by zero:RuntimeWarning") -def test_multiple_ouput_binary_ufuncs(ufunc, sparse, shuffle, - arrays_for_binary_ufunc): - a1, a2 = arrays_for_binary_ufunc - - if sparse: - a1 = pd.SparseArray(a1, dtype=pd.SparseDtype('int', 0)) - a2 = pd.SparseArray(a2, dtype=pd.SparseDtype('int', 0)) - - s1 = pd.Series(a1) - s2 = pd.Series(a2) - - if shuffle: - # ensure we align before applying the ufunc - s2 = s2.sample(frac=1) - - expected = ufunc(a1, a2) - assert isinstance(expected, tuple) - - result = ufunc(s1, s2) - assert isinstance(result, tuple) - tm.assert_series_equal(result[0], pd.Series(expected[0])) - tm.assert_series_equal(result[1], pd.Series(expected[1])) - - -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -def test_multiple_ouput_ufunc(sparse, arrays_for_binary_ufunc): - array, _ = arrays_for_binary_ufunc - - if sparse: - array = pd.SparseArray(array) - - series = pd.Series(array, name="name") - result = np.modf(series) - expected = np.modf(array) - - assert isinstance(result, tuple) - assert isinstance(expected, tuple) - - tm.assert_series_equal(result[0], pd.Series(expected[0], name="name")) - tm.assert_series_equal(result[1], pd.Series(expected[1], name="name")) - - -@pytest.mark.parametrize("sparse", SPARSE, ids=SPARSE_IDS) -@pytest.mark.parametrize("ufunc", BINARY_UFUNCS) -@pytest.mark.xfail(reason="Series.__array_ufunc__") -def test_binary_ufunc_drops_series_name(ufunc, sparse, - arrays_for_binary_ufunc): - # Drop the names when they differ. - a1, a2 = arrays_for_binary_ufunc - s1 = pd.Series(a1, name='a') - s2 = pd.Series(a2, name='b') - - result = ufunc(s1, s2) - assert result.name is None