From cb85bb8d0bd08c6d299fc28cd48db27a89a746ec Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 29 Nov 2020 19:45:22 -0800 Subject: [PATCH 1/5] CI: update tests for numpy 1.20 change to floordiv --- pandas/tests/arrays/integer/test_arithmetic.py | 6 +++++- pandas/tests/arrays/sparse/test_arithmetics.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/pandas/tests/arrays/integer/test_arithmetic.py b/pandas/tests/arrays/integer/test_arithmetic.py index cf382dd5e37e0..ae5538a2a85a2 100644 --- a/pandas/tests/arrays/integer/test_arithmetic.py +++ b/pandas/tests/arrays/integer/test_arithmetic.py @@ -3,6 +3,8 @@ import numpy as np import pytest +from pandas.compat.numpy import _np_version_under1p20 + import pandas as pd import pandas._testing as tm from pandas.core.arrays import integer_array @@ -197,7 +199,9 @@ def test_arith_coerce_scalar(data, all_arithmetic_operators): result = op(s, other) expected = op(s.astype(float), other) # rfloordiv results in nan instead of inf - if all_arithmetic_operators == "__rfloordiv__": + if all_arithmetic_operators == "__rfloordiv__" and _np_version_under1p20: + # for numpy 1.20 https://github.com/numpy/numpy/pull/16161 + # updated floordiv, now matches our behavior defined in core.ops expected[(expected == np.inf) | (expected == -np.inf)] = np.nan tm.assert_series_equal(result, expected) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index c9f1dd7f589fc..908aaa12033c3 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -3,6 +3,8 @@ import numpy as np import pytest +from pandas.compat.numpy import _np_version_under1p20 + import pandas as pd import pandas._testing as tm from pandas.core import ops @@ -44,9 +46,12 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): if op in [operator.floordiv, ops.rfloordiv]: # Series sets 1//0 to np.inf, which SparseArray does not do (yet) - mask = np.isinf(expected) - if mask.any(): - expected[mask] = np.nan + if _np_version_under1p20: + # numpy 1.20 updated floordiv, matching the behavior + # in core.ops. See https://github.com/numpy/numpy/pull/16161 + mask = np.isinf(expected) + if mask.any(): + expected[mask] = np.nan self._assert(result, expected) From dec6413f9bd97ab802c9f058abf41119ecaf8fbb Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 29 Nov 2020 21:14:12 -0800 Subject: [PATCH 2/5] cleanup --- .../tests/arrays/sparse/test_arithmetics.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 908aaa12033c3..370dc9f073082 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -8,7 +8,7 @@ import pandas as pd import pandas._testing as tm from pandas.core import ops -from pandas.core.arrays.sparse import SparseArray, SparseDtype +from pandas.core.arrays.sparse import IntIndex, SparseArray, SparseDtype @pytest.fixture(params=["integer", "block"]) @@ -31,7 +31,7 @@ class TestSparseArrayArithmetics: def _assert(self, a, b): tm.assert_numpy_array_equal(a, b) - def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): + def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op, flag=False): with np.errstate(invalid="ignore", divide="ignore"): if mix: result = op(a, b_dense).to_dense() @@ -46,7 +46,22 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): if op in [operator.floordiv, ops.rfloordiv]: # Series sets 1//0 to np.inf, which SparseArray does not do (yet) - if _np_version_under1p20: + condition = _np_version_under1p20 + if isinstance(a_dense, np.ndarray) and isinstance(b_dense, np.ndarray): + condition = True + if a_dense.dtype == np.float64 and np.isnan(a.fill_value): + # NB: these conditions are just guess-and-check + # to find what passes, no idea why these particular + # conditions are necessary. + if b_dense.dtype == np.int64 and mix: + condition = False + + if a.sp_index.equals(b.sp_index): + if not mix: + condition = False + elif isinstance(a.sp_index, IntIndex): + condition = False + if condition: # numpy 1.20 updated floordiv, matching the behavior # in core.ops. See https://github.com/numpy/numpy/pull/16161 mask = np.isinf(expected) From 075eecbae347ecdb2e3e0d9d6b0d419e9c7ebaa9 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 30 Nov 2020 07:21:00 -0800 Subject: [PATCH 3/5] xfail --- .../tests/arrays/sparse/test_arithmetics.py | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 370dc9f073082..5b4f7efd92d2e 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -8,7 +8,7 @@ import pandas as pd import pandas._testing as tm from pandas.core import ops -from pandas.core.arrays.sparse import IntIndex, SparseArray, SparseDtype +from pandas.core.arrays.sparse import SparseArray, SparseDtype @pytest.fixture(params=["integer", "block"]) @@ -46,27 +46,9 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op, flag=False): if op in [operator.floordiv, ops.rfloordiv]: # Series sets 1//0 to np.inf, which SparseArray does not do (yet) - condition = _np_version_under1p20 - if isinstance(a_dense, np.ndarray) and isinstance(b_dense, np.ndarray): - condition = True - if a_dense.dtype == np.float64 and np.isnan(a.fill_value): - # NB: these conditions are just guess-and-check - # to find what passes, no idea why these particular - # conditions are necessary. - if b_dense.dtype == np.int64 and mix: - condition = False - - if a.sp_index.equals(b.sp_index): - if not mix: - condition = False - elif isinstance(a.sp_index, IntIndex): - condition = False - if condition: - # numpy 1.20 updated floordiv, matching the behavior - # in core.ops. See https://github.com/numpy/numpy/pull/16161 - mask = np.isinf(expected) - if mask.any(): - expected[mask] = np.nan + mask = np.isinf(expected) + if mask.any(): + expected[mask] = np.nan self._assert(result, expected) @@ -136,9 +118,15 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): @pytest.mark.parametrize("scalar", [0, 1, 3]) @pytest.mark.parametrize("fill_value", [None, 0, 2]) def test_float_scalar( - self, kind, mix, all_arithmetic_functions, fill_value, scalar + self, kind, mix, all_arithmetic_functions, fill_value, scalar, request ): op = all_arithmetic_functions + + if not _np_version_under1p20: + if op in [operator.floordiv, ops.rfloordiv]: + mark = pytest.mark.xfail(strict=False, reason="GH#38172") + request.node.add_marker(mark) + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) a = self._klass(values, kind=kind, fill_value=fill_value) @@ -162,9 +150,15 @@ def test_float_scalar_comparison(self, kind): self._check_comparison_ops(a, 0, values, 0) self._check_comparison_ops(a, 3, values, 3) - def test_float_same_index(self, kind, mix, all_arithmetic_functions): + def test_float_same_index(self, kind, mix, all_arithmetic_functions, request): # when sp_index are the same op = all_arithmetic_functions + + if not _np_version_under1p20: + if op in [operator.floordiv, ops.rfloordiv]: + mark = pytest.mark.xfail(strict=False, reason="GH#38172") + request.node.add_marker(mark) + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([np.nan, 2, 3, 4, np.nan, 0, 1, 3, 2, np.nan]) @@ -344,9 +338,14 @@ def test_bool_array_logical(self, kind, fill_value): b = self._klass(rvalues, kind=kind, dtype=np.bool_, fill_value=fill_value) self._check_logical_ops(a, b, values, rvalues) - def test_mixed_array_float_int(self, kind, mix, all_arithmetic_functions): + def test_mixed_array_float_int(self, kind, mix, all_arithmetic_functions, request): op = all_arithmetic_functions + if not _np_version_under1p20: + if op in [operator.floordiv, ops.rfloordiv]: + mark = pytest.mark.xfail(strict=False, reason="GH#38172") + request.node.add_marker(mark) + rdtype = "int64" values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) From e3090df7033972470e15aa553db1361d484517ef Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 30 Nov 2020 07:29:42 -0800 Subject: [PATCH 4/5] Trim down xfails --- .../tests/arrays/sparse/test_arithmetics.py | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 5b4f7efd92d2e..535c66a77956a 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -150,7 +150,22 @@ def test_float_scalar_comparison(self, kind): self._check_comparison_ops(a, 0, values, 0) self._check_comparison_ops(a, 3, values, 3) - def test_float_same_index(self, kind, mix, all_arithmetic_functions, request): + def test_float_same_index_without_nans( + self, kind, mix, all_arithmetic_functions, request + ): + # when sp_index are the same + op = all_arithmetic_functions + + values = self._base([0.0, 1.0, 2.0, 6.0, 0.0, 0.0, 1.0, 2.0, 1.0, 0.0]) + rvalues = self._base([0.0, 2.0, 3.0, 4.0, 0.0, 0.0, 1.0, 3.0, 2.0, 0.0]) + + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind, fill_value=0) + self._check_numeric_ops(a, b, values, rvalues, mix, op) + + def test_float_same_index_with_nans( + self, kind, mix, all_arithmetic_functions, request + ): # when sp_index are the same op = all_arithmetic_functions @@ -166,13 +181,6 @@ def test_float_same_index(self, kind, mix, all_arithmetic_functions, request): b = self._klass(rvalues, kind=kind) self._check_numeric_ops(a, b, values, rvalues, mix, op) - values = self._base([0.0, 1.0, 2.0, 6.0, 0.0, 0.0, 1.0, 2.0, 1.0, 0.0]) - rvalues = self._base([0.0, 2.0, 3.0, 4.0, 0.0, 0.0, 1.0, 3.0, 2.0, 0.0]) - - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind, fill_value=0) - self._check_numeric_ops(a, b, values, rvalues, mix, op) - def test_float_same_index_comparison(self, kind): # when sp_index are the same values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -342,8 +350,8 @@ def test_mixed_array_float_int(self, kind, mix, all_arithmetic_functions, reques op = all_arithmetic_functions if not _np_version_under1p20: - if op in [operator.floordiv, ops.rfloordiv]: - mark = pytest.mark.xfail(strict=False, reason="GH#38172") + if op in [operator.floordiv, ops.rfloordiv] and mix: + mark = pytest.mark.xfail(strict=True, reason="GH#38172") request.node.add_marker(mark) rdtype = "int64" From 9d096b3a4b9601e76c91efd548463cc976f2593e Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 30 Nov 2020 08:03:28 -0800 Subject: [PATCH 5/5] fixup remove leftover --- pandas/tests/arrays/sparse/test_arithmetics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 535c66a77956a..61f4e3e50d09d 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -31,7 +31,7 @@ class TestSparseArrayArithmetics: def _assert(self, a, b): tm.assert_numpy_array_equal(a, b) - def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op, flag=False): + def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): with np.errstate(invalid="ignore", divide="ignore"): if mix: result = op(a, b_dense).to_dense()