diff --git a/doc/source/conf.py b/doc/source/conf.py index f222a228531ff..534c89cadb378 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -391,16 +391,23 @@ html_context = { - "redirects": dict(moved_api_pages), - "header": header, + "display_version": True, + "versions_dropdown": True, + "github_url": "https://github.com/pandas-dev/pandas", + # Remove the following items to simplify the footer + # 'other_versions': [ + # ("stable", "/pandas-docs/stable/"), + # ("dev", "/pandas-docs/dev/"), + # ], + # 'last_updated': datetime.now().strftime('%Y-%m-%d'), + # 'last_updated_date': datetime.now().strftime('%Y-%m-%d'), } # If false, no module index is generated. html_use_modindex = True # If false, no index is generated. -# html_use_index = True - +# html # If true, the index is split into individual pages for each letter. # html_split_index = False diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 016e553cf2092..470129d6d860b 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -1001,6 +1001,7 @@ Numeric - Bug in :meth:`Series.dot` returning ``object`` dtype for :class:`ArrowDtype` and nullable-dtype data (:issue:`61375`) - Bug in :meth:`Series.std` and :meth:`Series.var` when using complex-valued data (:issue:`61645`) - Bug in ``np.matmul`` with :class:`Index` inputs raising a ``TypeError`` (:issue:`57079`) +- Bug in arithmetic operations between objects with numpy-nullable dtype and :class:`ArrowDtype` incorrectly raising (:issue:`58602`) Conversion ^^^^^^^^^^ diff --git a/pandas/core/arrays/masked.py b/pandas/core/arrays/masked.py index 57efde1a928bc..cdba53662e6fa 100644 --- a/pandas/core/arrays/masked.py +++ b/pandas/core/arrays/masked.py @@ -37,7 +37,10 @@ is_string_dtype, pandas_dtype, ) -from pandas.core.dtypes.dtypes import BaseMaskedDtype +from pandas.core.dtypes.dtypes import ( + ArrowDtype, + BaseMaskedDtype, +) from pandas.core.dtypes.missing import ( array_equivalent, is_valid_na_for_dtype, @@ -767,6 +770,10 @@ def _arith_method(self, other, op): pd_op = ops.get_array_op(op) other = ensure_wrapped_if_datetimelike(other) + if isinstance(other, ExtensionArray) and isinstance(other.dtype, ArrowDtype): + # GH#58602 + return NotImplemented + if op_name in {"pow", "rpow"} and isinstance(other, np.bool_): # Avoid DeprecationWarning: In future, it will be an error # for 'np.bool_' scalars to be interpreted as an index @@ -843,7 +850,11 @@ def _cmp_method(self, other, op) -> BooleanArray: mask = None - if isinstance(other, BaseMaskedArray): + if isinstance(other, ExtensionArray) and isinstance(other.dtype, ArrowDtype): + # GH#58602 + return NotImplemented + + elif isinstance(other, BaseMaskedArray): other, mask = other._data, other._mask elif is_list_like(other): diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 2949b7ccc7cf3..2aa1b658fdf7b 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3702,6 +3702,28 @@ def test_pow_with_all_na_float(): tm.assert_series_equal(result, expected) +def test_mul_numpy_nullable_with_pyarrow_float(): + # GH#58602 + left = pd.Series(range(5), dtype="Float64") + right = pd.Series(range(5), dtype="float64[pyarrow]") + + expected = pd.Series([0, 1, 4, 9, 16], dtype="float64[pyarrow]") + + result = left * right + tm.assert_series_equal(result, expected) + + result2 = right * left + tm.assert_series_equal(result2, expected) + + # while we're here, let's check __eq__ + result3 = left == right + expected3 = pd.Series([True] * 5, dtype="bool[pyarrow]") + tm.assert_series_equal(result3, expected3) + + result4 = right == left + tm.assert_series_equal(result4, expected3) + + @pytest.mark.parametrize( "type_name, expected_size", [