From 6bd4fb10cedf95113ed5813462d3467670e69e4d Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 20:51:30 -0700 Subject: [PATCH 01/11] TST: parametrize tests --- .../tests/arrays/sparse/test_arithmetics.py | 381 +++++++++--------- 1 file changed, 185 insertions(+), 196 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 7bfedff217719..ae752e95e693a 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -8,6 +8,11 @@ import pandas.util.testing as tm +@pytest.fixture(params=["integer", "block"]) +def kind(request): + return request.param + + @pytest.mark.filterwarnings("ignore:Sparse:FutureWarning") @pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning") class TestSparseArrayArithmetics: @@ -136,99 +141,94 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): self._check_bool_result(a | b_dense) self._assert((a | b_dense).to_dense(), a_dense | b_dense) - def test_float_scalar(self): + def test_float_scalar(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + a = self._klass(values, kind=kind) + self._check_numeric_ops(a, 1, values, 1) + self._check_numeric_ops(a, 0, values, 0) + self._check_numeric_ops(a, 3, values, 3) - a = self._klass(values, kind=kind, fill_value=0) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + a = self._klass(values, kind=kind, fill_value=0) + self._check_numeric_ops(a, 1, values, 1) + self._check_numeric_ops(a, 0, values, 0) + self._check_numeric_ops(a, 3, values, 3) - a = self._klass(values, kind=kind, fill_value=2) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + a = self._klass(values, kind=kind, fill_value=2) + self._check_numeric_ops(a, 1, values, 1) + self._check_numeric_ops(a, 0, values, 0) + self._check_numeric_ops(a, 3, values, 3) - def test_float_scalar_comparison(self): + def test_float_scalar_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - self._check_comparison_ops(a, 1, values, 1) - self._check_comparison_ops(a, 0, values, 0) - self._check_comparison_ops(a, 3, values, 3) + a = self._klass(values, kind=kind) + self._check_comparison_ops(a, 1, values, 1) + self._check_comparison_ops(a, 0, values, 0) + self._check_comparison_ops(a, 3, values, 3) - a = self._klass(values, kind=kind, fill_value=0) - self._check_comparison_ops(a, 1, values, 1) - self._check_comparison_ops(a, 0, values, 0) - self._check_comparison_ops(a, 3, values, 3) + a = self._klass(values, kind=kind, fill_value=0) + self._check_comparison_ops(a, 1, values, 1) + self._check_comparison_ops(a, 0, values, 0) + self._check_comparison_ops(a, 3, values, 3) - a = self._klass(values, kind=kind, fill_value=2) - self._check_comparison_ops(a, 1, values, 1) - self._check_comparison_ops(a, 0, values, 0) - self._check_comparison_ops(a, 3, values, 3) + a = self._klass(values, kind=kind, fill_value=2) + self._check_comparison_ops(a, 1, values, 1) + self._check_comparison_ops(a, 0, values, 0) + self._check_comparison_ops(a, 3, values, 3) - def test_float_same_index(self): + def test_float_same_index(self, kind): # when sp_index are the same - for kind in ["integer", "block"]: - 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]) + 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]) - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + self._check_numeric_ops(a, b, values, rvalues) - 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]) + 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) + 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) - def test_float_same_index_comparison(self): + def test_float_same_index_comparison(self, kind): # when sp_index are the same - for kind in ["integer", "block"]: - 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]) + 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]) - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + self._check_comparison_ops(a, b, values, rvalues) - 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]) + 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_comparison_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind, fill_value=0) + self._check_comparison_ops(a, b, values, rvalues) - def test_float_array(self): + def test_float_array(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b * 0, values, rvalues * 0) - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind) + self._check_numeric_ops(a, b, values, rvalues) - 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) + 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) - a = self._klass(values, kind=kind, fill_value=1) - b = self._klass(rvalues, kind=kind, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=1) + b = self._klass(rvalues, kind=kind, fill_value=2) + self._check_numeric_ops(a, b, values, rvalues) def test_float_array_different_kind(self): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -251,174 +251,163 @@ def test_float_array_different_kind(self): b = self._klass(rvalues, kind="block", fill_value=2) self._check_numeric_ops(a, b, values, rvalues) - def test_float_array_comparison(self): + def test_float_array_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - self._check_comparison_ops(a, b, values, rvalues) - self._check_comparison_ops(a, b * 0, values, rvalues * 0) + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + self._check_comparison_ops(a, b, values, rvalues) + self._check_comparison_ops(a, b * 0, values, rvalues * 0) - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind) + self._check_comparison_ops(a, b, values, rvalues) - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind, fill_value=0) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind, fill_value=0) + self._check_comparison_ops(a, b, values, rvalues) - a = self._klass(values, kind=kind, fill_value=1) - b = self._klass(rvalues, kind=kind, fill_value=2) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=1) + b = self._klass(rvalues, kind=kind, fill_value=2) + self._check_comparison_ops(a, b, values, rvalues) - def test_int_array(self): + def test_int_array(self, kind): # have to specify dtype explicitly until fixing GH 667 dtype = np.int64 values = self._base([0, 1, 2, 0, 0, 0, 1, 2, 1, 0], dtype=dtype) rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=dtype) - for kind in ["integer", "block"]: - a = self._klass(values, dtype=dtype, kind=kind) - assert a.dtype == SparseDtype(dtype) - b = self._klass(rvalues, dtype=dtype, kind=kind) - assert b.dtype == SparseDtype(dtype) - - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + a = self._klass(values, dtype=dtype, kind=kind) + assert a.dtype == SparseDtype(dtype) + b = self._klass(rvalues, dtype=dtype, kind=kind) + assert b.dtype == SparseDtype(dtype) - a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) - assert a.dtype == SparseDtype(dtype) - b = self._klass(rvalues, dtype=dtype, kind=kind) - assert b.dtype == SparseDtype(dtype) + self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b * 0, values, rvalues * 0) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) + assert a.dtype == SparseDtype(dtype) + b = self._klass(rvalues, dtype=dtype, kind=kind) + assert b.dtype == SparseDtype(dtype) - a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) - assert a.dtype == SparseDtype(dtype) - b = self._klass(rvalues, fill_value=0, dtype=dtype, kind=kind) - assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues) - a = self._klass(values, fill_value=1, dtype=dtype, kind=kind) - assert a.dtype == SparseDtype(dtype, fill_value=1) - b = self._klass(rvalues, fill_value=2, dtype=dtype, kind=kind) - assert b.dtype == SparseDtype(dtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) + assert a.dtype == SparseDtype(dtype) + b = self._klass(rvalues, fill_value=0, dtype=dtype, kind=kind) + assert b.dtype == SparseDtype(dtype) + self._check_numeric_ops(a, b, values, rvalues) - def test_int_array_comparison(self): + a = self._klass(values, fill_value=1, dtype=dtype, kind=kind) + assert a.dtype == SparseDtype(dtype, fill_value=1) + b = self._klass(rvalues, fill_value=2, dtype=dtype, kind=kind) + assert b.dtype == SparseDtype(dtype, fill_value=2) + self._check_numeric_ops(a, b, values, rvalues) + def test_int_array_comparison(self, kind): + dtype = "int64" # int32 NI ATM - for dtype in ["int64"]: - values = self._base([0, 1, 2, 0, 0, 0, 1, 2, 1, 0], dtype=dtype) - rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=dtype) - for kind in ["integer", "block"]: - a = self._klass(values, dtype=dtype, kind=kind) - b = self._klass(rvalues, dtype=dtype, kind=kind) - self._check_comparison_ops(a, b, values, rvalues) - self._check_comparison_ops(a, b * 0, values, rvalues * 0) + values = self._base([0, 1, 2, 0, 0, 0, 1, 2, 1, 0], dtype=dtype) + rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=dtype) + + a = self._klass(values, dtype=dtype, kind=kind) + b = self._klass(rvalues, dtype=dtype, kind=kind) + self._check_comparison_ops(a, b, values, rvalues) + self._check_comparison_ops(a, b * 0, values, rvalues * 0) - a = self._klass(values, dtype=dtype, kind=kind, fill_value=0) - b = self._klass(rvalues, dtype=dtype, kind=kind) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, dtype=dtype, kind=kind, fill_value=0) + b = self._klass(rvalues, dtype=dtype, kind=kind) + self._check_comparison_ops(a, b, values, rvalues) - a = self._klass(values, dtype=dtype, kind=kind, fill_value=0) - b = self._klass(rvalues, dtype=dtype, kind=kind, fill_value=0) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, dtype=dtype, kind=kind, fill_value=0) + b = self._klass(rvalues, dtype=dtype, kind=kind, fill_value=0) + self._check_comparison_ops(a, b, values, rvalues) - a = self._klass(values, dtype=dtype, kind=kind, fill_value=1) - b = self._klass(rvalues, dtype=dtype, kind=kind, fill_value=2) - self._check_comparison_ops(a, b, values, rvalues) + a = self._klass(values, dtype=dtype, kind=kind, fill_value=1) + b = self._klass(rvalues, dtype=dtype, kind=kind, fill_value=2) + self._check_comparison_ops(a, b, values, rvalues) - def test_bool_same_index(self): + @pytest.mark.parametrize("fill_value", [True, False, np.nan]) + def test_bool_same_index(self, kind, fill_value): # GH 14000 # when sp_index are the same - for kind in ["integer", "block"]: - values = self._base([True, False, True, True], dtype=np.bool) - rvalues = self._base([True, False, True, True], dtype=np.bool) - - for fill_value in [True, False, np.nan]: - a = self._klass(values, kind=kind, dtype=np.bool, fill_value=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_bool_array_logical(self): + values = self._base([True, False, True, True], dtype=np.bool) + rvalues = self._base([True, False, True, True], dtype=np.bool) + + a = self._klass(values, kind=kind, dtype=np.bool, fill_value=fill_value) + b = self._klass(rvalues, kind=kind, dtype=np.bool, fill_value=fill_value) + self._check_logical_ops(a, b, values, rvalues) + + @pytest.mark.parametrize("fill_value", [True, False, np.nan]) + def test_bool_array_logical(self, kind, fill_value): # GH 14000 # when sp_index are the same - for kind in ["integer", "block"]: - values = self._base([True, False, True, False, True, True], dtype=np.bool) - rvalues = self._base([True, False, False, True, False, True], dtype=np.bool) - - for fill_value in [True, False, np.nan]: - a = self._klass(values, kind=kind, dtype=np.bool, fill_value=fill_value) - b = self._klass( - rvalues, kind=kind, dtype=np.bool, fill_value=fill_value - ) - self._check_logical_ops(a, b, values, rvalues) + values = self._base([True, False, True, False, True, True], dtype=np.bool) + rvalues = self._base([True, False, False, True, False, True], dtype=np.bool) - def test_mixed_array_float_int(self): + a = self._klass(values, kind=kind, dtype=np.bool, fill_value=fill_value) + b = self._klass(rvalues, kind=kind, dtype=np.bool, fill_value=fill_value) + self._check_logical_ops(a, b, values, rvalues) - for rdtype in ["int64"]: - values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) - rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype) + def test_mixed_array_float_int(self, kind): + rdtype = "int64" - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - assert b.dtype == SparseDtype(rdtype) + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) + rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype) - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + assert b.dtype == SparseDtype(rdtype) - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind) - assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b * 0, values, rvalues * 0) - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind, fill_value=0) - assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind) + assert b.dtype == SparseDtype(rdtype) + self._check_numeric_ops(a, b, values, rvalues) - a = self._klass(values, kind=kind, fill_value=1) - b = self._klass(rvalues, kind=kind, fill_value=2) - assert b.dtype == SparseDtype(rdtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind, fill_value=0) + assert b.dtype == SparseDtype(rdtype) + self._check_numeric_ops(a, b, values, rvalues) - def test_mixed_array_comparison(self): + a = self._klass(values, kind=kind, fill_value=1) + b = self._klass(rvalues, kind=kind, fill_value=2) + assert b.dtype == SparseDtype(rdtype, fill_value=2) + self._check_numeric_ops(a, b, values, rvalues) + def test_mixed_array_comparison(self, kind): + rdtype = "int64" # int32 NI ATM - for rdtype in ["int64"]: - values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) - rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype) - - for kind in ["integer", "block"]: - a = self._klass(values, kind=kind) - b = self._klass(rvalues, kind=kind) - assert b.dtype == SparseDtype(rdtype) - - self._check_comparison_ops(a, b, values, rvalues) - self._check_comparison_ops(a, b * 0, values, rvalues * 0) - - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind) - assert b.dtype == SparseDtype(rdtype) - self._check_comparison_ops(a, b, values, rvalues) - - a = self._klass(values, kind=kind, fill_value=0) - b = self._klass(rvalues, kind=kind, fill_value=0) - assert b.dtype == SparseDtype(rdtype) - self._check_comparison_ops(a, b, values, rvalues) - - a = self._klass(values, kind=kind, fill_value=1) - b = self._klass(rvalues, kind=kind, fill_value=2) - assert b.dtype == SparseDtype(rdtype, fill_value=2) - self._check_comparison_ops(a, b, values, rvalues) + + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) + rvalues = self._base([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype) + + a = self._klass(values, kind=kind) + b = self._klass(rvalues, kind=kind) + assert b.dtype == SparseDtype(rdtype) + + self._check_comparison_ops(a, b, values, rvalues) + self._check_comparison_ops(a, b * 0, values, rvalues * 0) + + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind) + assert b.dtype == SparseDtype(rdtype) + self._check_comparison_ops(a, b, values, rvalues) + + a = self._klass(values, kind=kind, fill_value=0) + b = self._klass(rvalues, kind=kind, fill_value=0) + assert b.dtype == SparseDtype(rdtype) + self._check_comparison_ops(a, b, values, rvalues) + + a = self._klass(values, kind=kind, fill_value=1) + b = self._klass(rvalues, kind=kind, fill_value=2) + assert b.dtype == SparseDtype(rdtype, fill_value=2) + self._check_comparison_ops(a, b, values, rvalues) class TestSparseSeriesArithmetic(TestSparseArrayArithmetics): From d9943be389e412f93ed3cb35f5766430174cda32 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:03:50 -0700 Subject: [PATCH 02/11] for loop, preparing to parametrize --- .../tests/arrays/sparse/test_arithmetics.py | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index ae752e95e693a..57f9f83c09d66 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -4,6 +4,7 @@ import pytest import pandas as pd +from pandas.core import ops from pandas.core.sparse.api import SparseDtype import pandas.util.testing as tm @@ -28,55 +29,36 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense): # Unfortunately, trying to wrap the computation of each expected # value is with np.errstate() is too tedious. - # sparse & sparse - self._assert((a + b).to_dense(), a_dense + b_dense) - self._assert((b + a).to_dense(), b_dense + a_dense) - - self._assert((a - b).to_dense(), a_dense - b_dense) - self._assert((b - a).to_dense(), b_dense - a_dense) - - self._assert((a * b).to_dense(), a_dense * b_dense) - self._assert((b * a).to_dense(), b_dense * a_dense) - - # pandas uses future division - self._assert((a / b).to_dense(), a_dense * 1.0 / b_dense) - self._assert((b / a).to_dense(), b_dense * 1.0 / a_dense) - - # ToDo: FIXME in GH 13843 - if not (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): - self._assert((a // b).to_dense(), a_dense // b_dense) - self._assert((b // a).to_dense(), b_dense // a_dense) - - self._assert((a % b).to_dense(), a_dense % b_dense) - self._assert((b % a).to_dense(), b_dense % a_dense) - - self._assert((a ** b).to_dense(), a_dense ** b_dense) - self._assert((b ** a).to_dense(), b_dense ** a_dense) - - # sparse & dense - self._assert((a + b_dense).to_dense(), a_dense + b_dense) - self._assert((b_dense + a).to_dense(), b_dense + a_dense) - - self._assert((a - b_dense).to_dense(), a_dense - b_dense) - self._assert((b_dense - a).to_dense(), b_dense - a_dense) - - self._assert((a * b_dense).to_dense(), a_dense * b_dense) - self._assert((b_dense * a).to_dense(), b_dense * a_dense) - - # pandas uses future division - self._assert((a / b_dense).to_dense(), a_dense * 1.0 / b_dense) - self._assert((b_dense / a).to_dense(), b_dense * 1.0 / a_dense) - - # ToDo: FIXME in GH 13843 - if not (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): - self._assert((a // b_dense).to_dense(), a_dense // b_dense) - self._assert((b_dense // a).to_dense(), b_dense // a_dense) - - self._assert((a % b_dense).to_dense(), a_dense % b_dense) - self._assert((b_dense % a).to_dense(), b_dense % a_dense) - - self._assert((a ** b_dense).to_dense(), a_dense ** b_dense) - self._assert((b_dense ** a).to_dense(), b_dense ** a_dense) + for mix in [True, False]: + # True --> sparse & dense + # False --> sparse & sparse + + # sparse & sparse + for op in [operator.add, ops.radd, + operator.sub, ops.rsub, + operator.mul, ops.rmul, + operator.truediv, ops.rtruediv, + operator.floordiv, ops.rfloordiv, + operator.mod, ops.rmod, + operator.pow, ops.rpow]: + + if op in [operator.floordiv, ops.rfloordiv]: + # FIXME: GH#13843 + if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): + continue + + if mix: + result = op(a, b_dense).to_dense() + else: + result = op(a, b).to_dense() + + if op in [operator.truediv, ops.rtruediv]: + # pandas uses future division + expected = op(a_dense * 1.0, b_dense) + else: + expected = op(a_dense, b_dense) + + self._assert(result, expected) def _check_bool_result(self, res): assert isinstance(res, self._klass) From eb8b6d750be1d269294a7f4431e5b72756b817da Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:07:26 -0700 Subject: [PATCH 03/11] parametrize/fixturize mix --- .../tests/arrays/sparse/test_arithmetics.py | 148 +++++++++--------- 1 file changed, 75 insertions(+), 73 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 57f9f83c09d66..8c1206f4e1654 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -14,6 +14,12 @@ def kind(request): return request.param +@pytest.fixture(params=[True, False]) +def mix(request): + # whether to operate op(sparse, dense) instead of op(sparse, sparse) + return request.param + + @pytest.mark.filterwarnings("ignore:Sparse:FutureWarning") @pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning") class TestSparseArrayArithmetics: @@ -24,41 +30,37 @@ 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): + def _check_numeric_ops(self, a, b, a_dense, b_dense, mix): with np.errstate(invalid="ignore", divide="ignore"): # Unfortunately, trying to wrap the computation of each expected # value is with np.errstate() is too tedious. - for mix in [True, False]: - # True --> sparse & dense - # False --> sparse & sparse - - # sparse & sparse - for op in [operator.add, ops.radd, - operator.sub, ops.rsub, - operator.mul, ops.rmul, - operator.truediv, ops.rtruediv, - operator.floordiv, ops.rfloordiv, - operator.mod, ops.rmod, - operator.pow, ops.rpow]: - - if op in [operator.floordiv, ops.rfloordiv]: - # FIXME: GH#13843 - if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): - continue - - if mix: - result = op(a, b_dense).to_dense() - else: - result = op(a, b).to_dense() - - if op in [operator.truediv, ops.rtruediv]: - # pandas uses future division - expected = op(a_dense * 1.0, b_dense) - else: - expected = op(a_dense, b_dense) - - self._assert(result, expected) + # sparse & sparse + for op in [operator.add, ops.radd, + operator.sub, ops.rsub, + operator.mul, ops.rmul, + operator.truediv, ops.rtruediv, + operator.floordiv, ops.rfloordiv, + operator.mod, ops.rmod, + operator.pow, ops.rpow]: + + if op in [operator.floordiv, ops.rfloordiv]: + # FIXME: GH#13843 + if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): + continue + + if mix: + result = op(a, b_dense).to_dense() + else: + result = op(a, b).to_dense() + + if op in [operator.truediv, ops.rtruediv]: + # pandas uses future division + expected = op(a_dense * 1.0, b_dense) + else: + expected = op(a_dense, b_dense) + + self._assert(result, expected) def _check_bool_result(self, res): assert isinstance(res, self._klass) @@ -123,23 +125,23 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): self._check_bool_result(a | b_dense) self._assert((a | b_dense).to_dense(), a_dense | b_dense) - def test_float_scalar(self, kind): + def test_float_scalar(self, kind, mix): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) a = self._klass(values, kind=kind) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + self._check_numeric_ops(a, 1, values, 1, mix) + self._check_numeric_ops(a, 0, values, 0, mix) + self._check_numeric_ops(a, 3, values, 3, mix) a = self._klass(values, kind=kind, fill_value=0) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + self._check_numeric_ops(a, 1, values, 1, mix) + self._check_numeric_ops(a, 0, values, 0, mix) + self._check_numeric_ops(a, 3, values, 3, mix) a = self._klass(values, kind=kind, fill_value=2) - self._check_numeric_ops(a, 1, values, 1) - self._check_numeric_ops(a, 0, values, 0) - self._check_numeric_ops(a, 3, values, 3) + self._check_numeric_ops(a, 1, values, 1, mix) + self._check_numeric_ops(a, 0, values, 0, mix) + self._check_numeric_ops(a, 3, values, 3, mix) def test_float_scalar_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -159,21 +161,21 @@ 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): + def test_float_same_index(self, kind, mix): # when sp_index are the same 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]) a = self._klass(values, kind=kind) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) 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) + self._check_numeric_ops(a, b, values, rvalues, mix) def test_float_same_index_comparison(self, kind): # when sp_index are the same @@ -191,47 +193,47 @@ def test_float_same_index_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=0) self._check_comparison_ops(a, b, values, rvalues) - def test_float_array(self, kind): + def test_float_array(self, kind, mix): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) a = self._klass(values, kind=kind) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) 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) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, kind=kind, fill_value=1) b = self._klass(rvalues, kind=kind, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) - def test_float_array_different_kind(self): + def test_float_array_different_kind(self, mix): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) a = self._klass(values, kind="integer") b = self._klass(rvalues, kind="block") - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) a = self._klass(values, kind="integer", fill_value=0) b = self._klass(rvalues, kind="block") - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, kind="integer", fill_value=0) b = self._klass(rvalues, kind="block", fill_value=0) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, kind="integer", fill_value=1) b = self._klass(rvalues, kind="block", fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) def test_float_array_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -254,7 +256,7 @@ def test_float_array_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=2) self._check_comparison_ops(a, b, values, rvalues) - def test_int_array(self, kind): + def test_int_array(self, kind, mix): # have to specify dtype explicitly until fixing GH 667 dtype = np.int64 @@ -266,27 +268,27 @@ def test_int_array(self, kind): b = self._klass(rvalues, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype) b = self._klass(rvalues, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype) b = self._klass(rvalues, fill_value=0, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, fill_value=1, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype, fill_value=1) b = self._klass(rvalues, fill_value=2, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) def test_int_array_comparison(self, kind): dtype = "int64" @@ -334,7 +336,7 @@ 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): + def test_mixed_array_float_int(self, kind, mix): rdtype = "int64" values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -344,23 +346,23 @@ def test_mixed_array_float_int(self, kind): b = self._klass(rvalues, kind=kind) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues) - self._check_numeric_ops(a, b * 0, values, rvalues * 0) + self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind, fill_value=0) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) a = self._klass(values, kind=kind, fill_value=1) b = self._klass(rvalues, kind=kind, fill_value=2) assert b.dtype == SparseDtype(rdtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues) + self._check_numeric_ops(a, b, values, rvalues, mix) def test_mixed_array_comparison(self, kind): rdtype = "int64" @@ -400,7 +402,7 @@ class TestSparseSeriesArithmetic(TestSparseArrayArithmetics): def _assert(self, a, b): tm.assert_series_equal(a, b) - def test_alignment(self): + def test_alignment(self, mix): da = pd.Series(np.arange(4)) db = pd.Series(np.arange(4), index=[1, 2, 3, 4]) @@ -408,13 +410,13 @@ def test_alignment(self): sb = pd.SparseSeries( np.arange(4), index=[1, 2, 3, 4], dtype=np.int64, fill_value=0 ) - self._check_numeric_ops(sa, sb, da, db) + self._check_numeric_ops(sa, sb, da, db, mix) sa = pd.SparseSeries(np.arange(4), dtype=np.int64, fill_value=np.nan) sb = pd.SparseSeries( np.arange(4), index=[1, 2, 3, 4], dtype=np.int64, fill_value=np.nan ) - self._check_numeric_ops(sa, sb, da, db) + self._check_numeric_ops(sa, sb, da, db, mix) da = pd.Series(np.arange(4)) db = pd.Series(np.arange(4), index=[10, 11, 12, 13]) @@ -423,13 +425,13 @@ def test_alignment(self): sb = pd.SparseSeries( np.arange(4), index=[10, 11, 12, 13], dtype=np.int64, fill_value=0 ) - self._check_numeric_ops(sa, sb, da, db) + self._check_numeric_ops(sa, sb, da, db, mix) sa = pd.SparseSeries(np.arange(4), dtype=np.int64, fill_value=np.nan) sb = pd.SparseSeries( np.arange(4), index=[10, 11, 12, 13], dtype=np.int64, fill_value=np.nan ) - self._check_numeric_ops(sa, sb, da, db) + self._check_numeric_ops(sa, sb, da, db, mix) @pytest.mark.parametrize("op", [operator.eq, operator.add]) From 3edebac69f952bb7b2e27e75ffaac713818e69ce Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:10:09 -0700 Subject: [PATCH 04/11] fixture for op --- .../tests/arrays/sparse/test_arithmetics.py | 142 +++++++++--------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 8c1206f4e1654..1bea7dcee72b3 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -20,6 +20,19 @@ def mix(request): return request.param +@pytest.fixture(params=[ + operator.add, ops.radd, + operator.sub, ops.rsub, + operator.mul, ops.rmul, + operator.truediv, ops.rtruediv, + operator.floordiv, ops.rfloordiv, + operator.mod, ops.rmod, + operator.pow, ops.rpow +]) +def op(request): + return request.param + + @pytest.mark.filterwarnings("ignore:Sparse:FutureWarning") @pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning") class TestSparseArrayArithmetics: @@ -30,37 +43,28 @@ 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): + def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): with np.errstate(invalid="ignore", divide="ignore"): # Unfortunately, trying to wrap the computation of each expected # value is with np.errstate() is too tedious. - # sparse & sparse - for op in [operator.add, ops.radd, - operator.sub, ops.rsub, - operator.mul, ops.rmul, - operator.truediv, ops.rtruediv, - operator.floordiv, ops.rfloordiv, - operator.mod, ops.rmod, - operator.pow, ops.rpow]: - - if op in [operator.floordiv, ops.rfloordiv]: - # FIXME: GH#13843 - if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): - continue - - if mix: - result = op(a, b_dense).to_dense() - else: - result = op(a, b).to_dense() - - if op in [operator.truediv, ops.rtruediv]: - # pandas uses future division - expected = op(a_dense * 1.0, b_dense) - else: - expected = op(a_dense, b_dense) - - self._assert(result, expected) + if op in [operator.floordiv, ops.rfloordiv]: + # FIXME: GH#13843 + if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): + return # TODO: pytest.skip? xfail? + + if mix: + result = op(a, b_dense).to_dense() + else: + result = op(a, b).to_dense() + + if op in [operator.truediv, ops.rtruediv]: + # pandas uses future division + expected = op(a_dense * 1.0, b_dense) + else: + expected = op(a_dense, b_dense) + + self._assert(result, expected) def _check_bool_result(self, res): assert isinstance(res, self._klass) @@ -125,23 +129,23 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): self._check_bool_result(a | b_dense) self._assert((a | b_dense).to_dense(), a_dense | b_dense) - def test_float_scalar(self, kind, mix): + def test_float_scalar(self, kind, mix, op): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) a = self._klass(values, kind=kind) - self._check_numeric_ops(a, 1, values, 1, mix) - self._check_numeric_ops(a, 0, values, 0, mix) - self._check_numeric_ops(a, 3, values, 3, mix) + self._check_numeric_ops(a, 1, values, 1, mix, op) + self._check_numeric_ops(a, 0, values, 0, mix, op) + self._check_numeric_ops(a, 3, values, 3, mix, op) a = self._klass(values, kind=kind, fill_value=0) - self._check_numeric_ops(a, 1, values, 1, mix) - self._check_numeric_ops(a, 0, values, 0, mix) - self._check_numeric_ops(a, 3, values, 3, mix) + self._check_numeric_ops(a, 1, values, 1, mix, op) + self._check_numeric_ops(a, 0, values, 0, mix, op) + self._check_numeric_ops(a, 3, values, 3, mix, op) a = self._klass(values, kind=kind, fill_value=2) - self._check_numeric_ops(a, 1, values, 1, mix) - self._check_numeric_ops(a, 0, values, 0, mix) - self._check_numeric_ops(a, 3, values, 3, mix) + self._check_numeric_ops(a, 1, values, 1, mix, op) + self._check_numeric_ops(a, 0, values, 0, mix, op) + self._check_numeric_ops(a, 3, values, 3, mix, op) def test_float_scalar_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -161,21 +165,21 @@ 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): + def test_float_same_index(self, kind, mix, op): # when sp_index are the same 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]) a = self._klass(values, kind=kind) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues, mix) + 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) + self._check_numeric_ops(a, b, values, rvalues, mix, op) def test_float_same_index_comparison(self, kind): # when sp_index are the same @@ -193,47 +197,47 @@ def test_float_same_index_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=0) self._check_comparison_ops(a, b, values, rvalues) - def test_float_array(self, kind, mix): + def test_float_array(self, kind, mix, op): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) a = self._klass(values, kind=kind) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues, mix) - self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) 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) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, kind=kind, fill_value=1) b = self._klass(rvalues, kind=kind, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) - def test_float_array_different_kind(self, mix): + def test_float_array_different_kind(self, mix, op): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) a = self._klass(values, kind="integer") b = self._klass(rvalues, kind="block") - self._check_numeric_ops(a, b, values, rvalues, mix) - self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op) a = self._klass(values, kind="integer", fill_value=0) b = self._klass(rvalues, kind="block") - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, kind="integer", fill_value=0) b = self._klass(rvalues, kind="block", fill_value=0) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, kind="integer", fill_value=1) b = self._klass(rvalues, kind="block", fill_value=2) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) def test_float_array_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -256,7 +260,7 @@ def test_float_array_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=2) self._check_comparison_ops(a, b, values, rvalues) - def test_int_array(self, kind, mix): + def test_int_array(self, kind, mix, op): # have to specify dtype explicitly until fixing GH 667 dtype = np.int64 @@ -268,27 +272,27 @@ def test_int_array(self, kind, mix): b = self._klass(rvalues, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues, mix) - self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op) a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype) b = self._klass(rvalues, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, fill_value=0, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype) b = self._klass(rvalues, fill_value=0, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, fill_value=1, dtype=dtype, kind=kind) assert a.dtype == SparseDtype(dtype, fill_value=1) b = self._klass(rvalues, fill_value=2, dtype=dtype, kind=kind) assert b.dtype == SparseDtype(dtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) def test_int_array_comparison(self, kind): dtype = "int64" @@ -336,7 +340,7 @@ 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): + def test_mixed_array_float_int(self, kind, mix, op): rdtype = "int64" values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -346,23 +350,23 @@ def test_mixed_array_float_int(self, kind, mix): b = self._klass(rvalues, kind=kind) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues, mix) - self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) + self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, kind=kind, fill_value=0) b = self._klass(rvalues, kind=kind, fill_value=0) assert b.dtype == SparseDtype(rdtype) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) a = self._klass(values, kind=kind, fill_value=1) b = self._klass(rvalues, kind=kind, fill_value=2) assert b.dtype == SparseDtype(rdtype, fill_value=2) - self._check_numeric_ops(a, b, values, rvalues, mix) + self._check_numeric_ops(a, b, values, rvalues, mix, op) def test_mixed_array_comparison(self, kind): rdtype = "int64" @@ -402,7 +406,7 @@ class TestSparseSeriesArithmetic(TestSparseArrayArithmetics): def _assert(self, a, b): tm.assert_series_equal(a, b) - def test_alignment(self, mix): + def test_alignment(self, mix, op): da = pd.Series(np.arange(4)) db = pd.Series(np.arange(4), index=[1, 2, 3, 4]) @@ -410,13 +414,13 @@ def test_alignment(self, mix): sb = pd.SparseSeries( np.arange(4), index=[1, 2, 3, 4], dtype=np.int64, fill_value=0 ) - self._check_numeric_ops(sa, sb, da, db, mix) + self._check_numeric_ops(sa, sb, da, db, mix, op) sa = pd.SparseSeries(np.arange(4), dtype=np.int64, fill_value=np.nan) sb = pd.SparseSeries( np.arange(4), index=[1, 2, 3, 4], dtype=np.int64, fill_value=np.nan ) - self._check_numeric_ops(sa, sb, da, db, mix) + self._check_numeric_ops(sa, sb, da, db, mix, op) da = pd.Series(np.arange(4)) db = pd.Series(np.arange(4), index=[10, 11, 12, 13]) @@ -425,13 +429,13 @@ def test_alignment(self, mix): sb = pd.SparseSeries( np.arange(4), index=[10, 11, 12, 13], dtype=np.int64, fill_value=0 ) - self._check_numeric_ops(sa, sb, da, db, mix) + self._check_numeric_ops(sa, sb, da, db, mix, op) sa = pd.SparseSeries(np.arange(4), dtype=np.int64, fill_value=np.nan) sb = pd.SparseSeries( np.arange(4), index=[10, 11, 12, 13], dtype=np.int64, fill_value=np.nan ) - self._check_numeric_ops(sa, sb, da, db, mix) + self._check_numeric_ops(sa, sb, da, db, mix, op) @pytest.mark.parametrize("op", [operator.eq, operator.add]) From eb60fc36c7229b09982a540ef48a9faba86990f5 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:10:38 -0700 Subject: [PATCH 05/11] blackify --- .../tests/arrays/sparse/test_arithmetics.py | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 1bea7dcee72b3..296d6e3b80a17 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -20,15 +20,24 @@ def mix(request): return request.param -@pytest.fixture(params=[ - operator.add, ops.radd, - operator.sub, ops.rsub, - operator.mul, ops.rmul, - operator.truediv, ops.rtruediv, - operator.floordiv, ops.rfloordiv, - operator.mod, ops.rmod, - operator.pow, ops.rpow -]) +@pytest.fixture( + params=[ + operator.add, + ops.radd, + operator.sub, + ops.rsub, + operator.mul, + ops.rmul, + operator.truediv, + ops.rtruediv, + operator.floordiv, + ops.rfloordiv, + operator.mod, + ops.rmod, + operator.pow, + ops.rpow, + ] +) def op(request): return request.param @@ -50,7 +59,7 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): if op in [operator.floordiv, ops.rfloordiv]: # FIXME: GH#13843 - if (self._base == pd.Series and a.dtype.subtype == np.dtype("int64")): + if self._base == pd.Series and a.dtype.subtype == np.dtype("int64"): return # TODO: pytest.skip? xfail? if mix: From 3cf8b1ea854a9468510520aa5db56dc6ca3e2040 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:15:29 -0700 Subject: [PATCH 06/11] parametrize more --- pandas/tests/arrays/sparse/test_arithmetics.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 296d6e3b80a17..d1cae700a968d 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -138,20 +138,11 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): self._check_bool_result(a | b_dense) self._assert((a | b_dense).to_dense(), a_dense | b_dense) - def test_float_scalar(self, kind, mix, op): + @pytest.mark.parametrize("fill_value", [None, 0, 2]) + def test_float_scalar(self, kind, mix, op, fill_value): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) - a = self._klass(values, kind=kind) - self._check_numeric_ops(a, 1, values, 1, mix, op) - self._check_numeric_ops(a, 0, values, 0, mix, op) - self._check_numeric_ops(a, 3, values, 3, mix, op) - - a = self._klass(values, kind=kind, fill_value=0) - self._check_numeric_ops(a, 1, values, 1, mix, op) - self._check_numeric_ops(a, 0, values, 0, mix, op) - self._check_numeric_ops(a, 3, values, 3, mix, op) - - a = self._klass(values, kind=kind, fill_value=2) + a = self._klass(values, kind=kind, fill_value=fill_value) self._check_numeric_ops(a, 1, values, 1, mix, op) self._check_numeric_ops(a, 0, values, 0, mix, op) self._check_numeric_ops(a, 3, values, 3, mix, op) From c34a9cca1d27fabe8cf39ef710fe963ff7836a16 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 6 Jul 2019 21:19:25 -0700 Subject: [PATCH 07/11] param scalar --- pandas/tests/arrays/sparse/test_arithmetics.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index d1cae700a968d..5c8e1a154b437 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -138,14 +138,13 @@ def _check_logical_ops(self, a, b, a_dense, b_dense): self._check_bool_result(a | b_dense) self._assert((a | b_dense).to_dense(), 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, op, fill_value): + def test_float_scalar(self, kind, mix, op, fill_value, scalar): 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) - self._check_numeric_ops(a, 1, values, 1, mix, op) - self._check_numeric_ops(a, 0, values, 0, mix, op) - self._check_numeric_ops(a, 3, values, 3, mix, op) + self._check_numeric_ops(a, scalar, values, scalar, mix, op) def test_float_scalar_comparison(self, kind): values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) From b59b81a1b8d75591540d75ec3dff62f618207c9b Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sun, 7 Jul 2019 07:59:50 -0700 Subject: [PATCH 08/11] docstring, xfail --- pandas/tests/arrays/sparse/test_arithmetics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 5c8e1a154b437..698c37c37e805 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -11,6 +11,7 @@ @pytest.fixture(params=["integer", "block"]) def kind(request): + """kind kwarg to pass to SparseArray/SparseSeries""" return request.param @@ -60,7 +61,7 @@ def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): if op in [operator.floordiv, ops.rfloordiv]: # FIXME: GH#13843 if self._base == pd.Series and a.dtype.subtype == np.dtype("int64"): - return # TODO: pytest.skip? xfail? + pytest.xfail("Not defined/working. See GH#13843") if mix: result = op(a, b_dense).to_dense() From f085d6bd76419e6cc9576fe0f871efd8462f9dc8 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sun, 7 Jul 2019 08:04:00 -0700 Subject: [PATCH 09/11] remove defunct comment --- pandas/tests/arrays/sparse/test_arithmetics.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 698c37c37e805..1eeb5017344b5 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -55,9 +55,6 @@ def _assert(self, a, b): def _check_numeric_ops(self, a, b, a_dense, b_dense, mix, op): with np.errstate(invalid="ignore", divide="ignore"): - # Unfortunately, trying to wrap the computation of each expected - # value is with np.errstate() is too tedious. - if op in [operator.floordiv, ops.rfloordiv]: # FIXME: GH#13843 if self._base == pd.Series and a.dtype.subtype == np.dtype("int64"): From f03bd93d21609bea4d914cb7ee390f643b803d53 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 8 Jul 2019 16:21:33 -0700 Subject: [PATCH 10/11] implement all_arithmetic_functions fixture --- pandas/conftest.py | 30 +++++++++++ .../tests/arrays/sparse/test_arithmetics.py | 50 ++++++++----------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index 29833ab2fc0fa..f189947fb1817 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -1,5 +1,6 @@ from datetime import date, time, timedelta, timezone from decimal import Decimal +import operator import os from dateutil.tz import tzlocal, tzutc @@ -12,6 +13,7 @@ import pandas.util._test_decorators as td import pandas as pd +from pandas.core import ops from pandas import DataFrame import pandas.util.testing as tm @@ -163,6 +165,34 @@ def all_arithmetic_operators(request): return request.param +@pytest.fixture( + params=[ + operator.add, + ops.radd, + operator.sub, + ops.rsub, + operator.mul, + ops.rmul, + operator.truediv, + ops.rtruediv, + operator.floordiv, + ops.rfloordiv, + operator.mod, + ops.rmod, + operator.pow, + ops.rpow, + ] +) +def all_arithmetic_functions(request): + """ + Fixture for operator and roperator arithmetic functions. + + Note: This includes divmod and rdivmod, whereas all_arithmetic_operators + does not. + """ + return request.param + + _all_numeric_reductions = [ "sum", "max", diff --git a/pandas/tests/arrays/sparse/test_arithmetics.py b/pandas/tests/arrays/sparse/test_arithmetics.py index 1eeb5017344b5..0f8f3d261c3b3 100644 --- a/pandas/tests/arrays/sparse/test_arithmetics.py +++ b/pandas/tests/arrays/sparse/test_arithmetics.py @@ -21,28 +21,6 @@ def mix(request): return request.param -@pytest.fixture( - params=[ - operator.add, - ops.radd, - operator.sub, - ops.rsub, - operator.mul, - ops.rmul, - operator.truediv, - ops.rtruediv, - operator.floordiv, - ops.rfloordiv, - operator.mod, - ops.rmod, - operator.pow, - ops.rpow, - ] -) -def op(request): - return request.param - - @pytest.mark.filterwarnings("ignore:Sparse:FutureWarning") @pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning") class TestSparseArrayArithmetics: @@ -138,7 +116,10 @@ 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, op, fill_value, scalar): + def test_float_scalar( + self, kind, mix, all_arithmetic_functions, fill_value, scalar + ): + op = all_arithmetic_functions 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,8 +143,9 @@ 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, op): + def test_float_same_index(self, kind, mix, all_arithmetic_functions): # when sp_index are the same + op = all_arithmetic_functions 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]) @@ -194,7 +176,9 @@ def test_float_same_index_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=0) self._check_comparison_ops(a, b, values, rvalues) - def test_float_array(self, kind, mix, op): + def test_float_array(self, kind, mix, all_arithmetic_functions): + op = all_arithmetic_functions + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) @@ -215,7 +199,9 @@ def test_float_array(self, kind, mix, op): b = self._klass(rvalues, kind=kind, fill_value=2) self._check_numeric_ops(a, b, values, rvalues, mix, op) - def test_float_array_different_kind(self, mix, op): + def test_float_array_different_kind(self, mix, all_arithmetic_functions): + op = all_arithmetic_functions + values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) rvalues = self._base([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan]) @@ -257,7 +243,9 @@ def test_float_array_comparison(self, kind): b = self._klass(rvalues, kind=kind, fill_value=2) self._check_comparison_ops(a, b, values, rvalues) - def test_int_array(self, kind, mix, op): + def test_int_array(self, kind, mix, all_arithmetic_functions): + op = all_arithmetic_functions + # have to specify dtype explicitly until fixing GH 667 dtype = np.int64 @@ -337,7 +325,9 @@ 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, op): + def test_mixed_array_float_int(self, kind, mix, all_arithmetic_functions): + op = all_arithmetic_functions + rdtype = "int64" values = self._base([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan]) @@ -403,7 +393,9 @@ class TestSparseSeriesArithmetic(TestSparseArrayArithmetics): def _assert(self, a, b): tm.assert_series_equal(a, b) - def test_alignment(self, mix, op): + def test_alignment(self, mix, all_arithmetic_functions): + op = all_arithmetic_functions + da = pd.Series(np.arange(4)) db = pd.Series(np.arange(4), index=[1, 2, 3, 4]) From cd2f56466922bad3c3b20c6dfae1367ff264e0a3 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 8 Jul 2019 17:43:41 -0700 Subject: [PATCH 11/11] isort fixup --- pandas/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index f189947fb1817..ef2758d263e1a 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -13,8 +13,8 @@ import pandas.util._test_decorators as td import pandas as pd -from pandas.core import ops from pandas import DataFrame +from pandas.core import ops import pandas.util.testing as tm hypothesis.settings.register_profile(