diff --git a/pandas/tests/extension/test_numpy.py b/pandas/tests/extension/test_numpy.py index 547bd5d97d57e..4e054a07d8ef1 100644 --- a/pandas/tests/extension/test_numpy.py +++ b/pandas/tests/extension/test_numpy.py @@ -16,6 +16,8 @@ import numpy as np import pytest +from pandas.core.dtypes.dtypes import ExtensionDtype + import pandas as pd import pandas._testing as tm from pandas.core.arrays.numpy_ import PandasArray, PandasDtype @@ -121,7 +123,7 @@ def data_for_grouping(allow_in_pandas, dtype): @pytest.fixture -def skip_numpy_object(dtype): +def skip_numpy_object(dtype, request): """ Tests for PandasArray with nested data. Users typically won't create these objects via `pd.array`, but they can show up through `.array` @@ -132,14 +134,25 @@ def skip_numpy_object(dtype): marker to either an individual test or a test class. """ if dtype == "object": - raise pytest.skip("Skipping for object dtype.") + mark = pytest.mark.xfail(reason="Fails for object dtype") + request.node.add_marker(mark) skip_nested = pytest.mark.usefixtures("skip_numpy_object") class BaseNumPyTests: - pass + @classmethod + def assert_series_equal(cls, left, right, *args, **kwargs): + # base class tests hard-code expected values with numpy dtypes, + # whereas we generally want the corresponding PandasDtype + if ( + isinstance(right, pd.Series) + and not isinstance(right.dtype, ExtensionDtype) + and isinstance(left.dtype, PandasDtype) + ): + right = right.astype(PandasDtype(right.dtype)) + return tm.assert_series_equal(left, right, *args, **kwargs) class TestCasting(BaseNumPyTests, base.BaseCastingTests): @@ -148,12 +161,6 @@ def test_astype_str(self, data): # ValueError: setting an array element with a sequence super().test_astype_str(data) - @skip_nested - def test_astype_string(self, data): - # GH-33465 - # ValueError: setting an array element with a sequence - super().test_astype_string(data) - class TestConstructors(BaseNumPyTests, base.BaseConstructorsTests): @pytest.mark.skip(reason="We don't register our dtype") @@ -161,11 +168,6 @@ class TestConstructors(BaseNumPyTests, base.BaseConstructorsTests): def test_from_dtype(self, data): pass - @skip_nested - def test_array_from_scalars(self, data): - # ValueError: PandasArray must be 1-dimensional. - super().test_array_from_scalars(data) - @skip_nested def test_series_constructor_scalar_with_index(self, data, dtype): # ValueError: Length of passed values is 1, index implies 3. @@ -202,10 +204,16 @@ def test_loc_iloc_frame_single_dtype(self, data, request): class TestGroupby(BaseNumPyTests, base.BaseGroupbyTests): - @skip_nested def test_groupby_extension_apply( self, data_for_grouping, groupby_apply_op, request ): + dummy = groupby_apply_op([None]) + if ( + isinstance(dummy, pd.Series) + and data_for_grouping.dtype.numpy_dtype == object + ): + mark = pytest.mark.xfail(reason="raises in MultiIndex construction") + request.node.add_marker(mark) super().test_groupby_extension_apply(data_for_grouping, groupby_apply_op) @@ -225,17 +233,6 @@ def test_value_counts(self, all_data, dropna): def test_value_counts_with_normalize(self, data): return super().test_value_counts_with_normalize(data) - @pytest.mark.skip(reason="Incorrect expected") - # We have a bool dtype, so the result is an ExtensionArray - # but expected is not - def test_combine_le(self, data_repeated): - super().test_combine_le(data_repeated) - - @skip_nested - def test_combine_add(self, data_repeated): - # Not numeric - super().test_combine_add(data_repeated) - @skip_nested def test_shift_fill_value(self, data): # np.array shape inference. Shift implementation fails. @@ -258,11 +255,6 @@ def test_fillna_copy_series(self, data_missing): # The "scalar" for this array isn't a scalar. super().test_fillna_copy_series(data_missing) - @skip_nested - def test_hash_pandas_object_works(self, data, as_frame): - # ndarray of tuples not hashable - super().test_hash_pandas_object_works(data, as_frame) - @skip_nested def test_searchsorted(self, data_for_sorting, as_series): # Test setup fails. @@ -273,41 +265,51 @@ def test_where_series(self, data, na_value, as_frame): # Test setup fails. super().test_where_series(data, na_value, as_frame) - @skip_nested @pytest.mark.parametrize("repeats", [0, 1, 2, [1, 2, 3]]) - def test_repeat(self, data, repeats, as_series, use_numpy): - # Fails creating expected + def test_repeat(self, data, repeats, as_series, use_numpy, request): + if data.dtype.numpy_dtype == object and repeats != 0: + mark = pytest.mark.xfail(reason="mask shapes mismatch") + request.node.add_marker(mark) super().test_repeat(data, repeats, as_series, use_numpy) @pytest.mark.xfail(reason="PandasArray.diff may fail on dtype") def test_diff(self, data, periods): return super().test_diff(data, periods) - @skip_nested @pytest.mark.parametrize("box", [pd.array, pd.Series, pd.DataFrame]) - def test_equals(self, data, na_value, as_series, box): + def test_equals(self, data, na_value, as_series, box, request): # Fails creating with _from_sequence + if box is pd.DataFrame and data.dtype.numpy_dtype == object: + mark = pytest.mark.xfail(reason="AssertionError in _get_same_shape_values") + request.node.add_marker(mark) + super().test_equals(data, na_value, as_series, box) -@skip_nested class TestArithmetics(BaseNumPyTests, base.BaseArithmeticOpsTests): divmod_exc = None series_scalar_exc = None frame_scalar_exc = None series_array_exc = None + @skip_nested + def test_divmod(self, data): + super().test_divmod(data) + + @skip_nested def test_divmod_series_array(self, data): - s = pd.Series(data) - self._check_divmod_op(s, divmod, data, exc=None) + ser = pd.Series(data) + self._check_divmod_op(ser, divmod, data, exc=None) @pytest.mark.skip("We implement ops") def test_error(self, data, all_arithmetic_operators): pass + @skip_nested def test_arith_series_with_scalar(self, data, all_arithmetic_operators): super().test_arith_series_with_scalar(data, all_arithmetic_operators) + @skip_nested def test_arith_series_with_array(self, data, all_arithmetic_operators): super().test_arith_series_with_array(data, all_arithmetic_operators) @@ -316,7 +318,6 @@ class TestPrinting(BaseNumPyTests, base.BasePrintingTests): pass -@skip_nested class TestNumericReduce(BaseNumPyTests, base.BaseNumericReduceTests): def check_reduce(self, s, op_name, skipna): result = getattr(s, op_name)(skipna=skipna) @@ -324,6 +325,10 @@ def check_reduce(self, s, op_name, skipna): expected = getattr(s.astype(s.dtype._dtype), op_name)(skipna=skipna) tm.assert_almost_equal(result, expected) + @pytest.mark.parametrize("skipna", [True, False]) + def test_reduce_series(self, data, all_boolean_reductions, skipna): + super().test_reduce_series(data, all_boolean_reductions, skipna) + @skip_nested class TestBooleanReduce(BaseNumPyTests, base.BaseBooleanReduceTests): @@ -364,11 +369,6 @@ def test_fillna_fill_other(self, data_missing): class TestReshaping(BaseNumPyTests, base.BaseReshapingTests): - @pytest.mark.skip("Incorrect parent test") - # not actually a mixed concat, since we concat int and int. - def test_concat_mixed_dtypes(self, data): - super().test_concat_mixed_dtypes(data) - @skip_nested def test_merge(self, data, na_value): # Fails creating expected @@ -390,22 +390,6 @@ def test_transpose_frame(self, data): class TestSetitem(BaseNumPyTests, base.BaseSetitemTests): - @skip_nested - def test_setitem_scalar_series(self, data, box_in_series): - # AssertionError - super().test_setitem_scalar_series(data, box_in_series) - - @skip_nested - def test_setitem_sequence(self, data, box_in_series): - # ValueError: shape mismatch: value array of shape (2,1) could not - # be broadcast to indexing result of shape (2,) - super().test_setitem_sequence(data, box_in_series) - - @skip_nested - def test_setitem_sequence_mismatched_length_raises(self, data, as_array): - # ValueError: PandasArray must be 1-dimensional. - super().test_setitem_sequence_mismatched_length_raises(data, as_array) - @skip_nested def test_setitem_sequence_broadcasts(self, data, box_in_series): # ValueError: cannot set using a list-like indexer with a different @@ -459,7 +443,6 @@ def test_setitem_scalar_key_sequence_raise(self, data): def test_setitem_mask(self, data, mask, box_in_series): super().test_setitem_mask(data, mask, box_in_series) - @skip_nested def test_setitem_mask_raises(self, data, box_in_series): super().test_setitem_mask_raises(data, box_in_series) @@ -472,7 +455,6 @@ def test_setitem_mask_raises(self, data, box_in_series): def test_setitem_integer_array(self, data, idx, box_in_series): super().test_setitem_integer_array(data, idx, box_in_series) - @skip_nested @pytest.mark.parametrize( "idx, box_in_series", [